725G61 - Laboration 2 Loopar och arrayer Johan Falkenjack October 29, 2013 1 Inledning I labb 1 lärde vi oss om de primitiva datatyperna (och lite om String). Vi lärde oss också att använda variabler av olika typer. I slutet av labben lärde vi oss också lite om villkorssatser. Detta låter oss lösa enkla beräkningsproblem men vill vi ha någon form av interaktivitet eller upprepning räcker det inte långt. Vi kommer dock inte lämna något av detta bakom oss för att göra något helt annat, variabler och villkorssatser är fundamentala för programmering och kommer följa med oss genom alla labbar framöver. En av de viktigaste aspekterna av programmering är att kunna upprepa ett stycke kod. T.ex. kanske man vill läsa in kommandon till programmet och skriva ut resultaten av att köra dessa kommandon, som i en klassisk DOSprompt. Detta kallas för en interaktionsloop och sådana kommer vi titta mer på i labb 4. Vi kan också ha en mängd objekt i någon form av lista som vi vill göra samma sak med. T.ex. en lista med personer vilkas namn vi vill skriva ut. Många mer avancerade algoritmer bygger på att man loopar, eller itererar. 1.1 Förberedelse Klasserna i labb 2 har samma namn som i labb 1 så antingen måste man skapa ett nytt projket eller ett nytt paket att ha klasserna i. Skapa ett nytt projekt i Eclipse eller skapa ett nytt paket i samma projekt som använde för labb 1. Fråga en labbassistent om du inte vet hur man gör. 2 While-loopen Den enklaste formen av loop i Java är den så kallade while-loopen. En whileloop fungerar på precis samma sätt som en if-sats, med den skillnaden att whilesatsens kodblock upprepas så länge predikat-uttrycket är sant. 1 while(true) { 2 System.out.println("This will print forever!"); 3 } Ovan har vi det enklaste exemplet på en while-loop, en loop som fortsätter i all evighet. Det är kanske inte den mest spännande typen av loop men kan faktiskt vara användbar ibland. While-loopar är praktiska när man inte vet i förväg hur många gånger en iteration ska utföras, som när antalet varv är beroende av input från användaren. Ett exempel är en interaktionsloop som upprepas tills användaren skriver "exit". 1 Övning 2.1 Klistra in följande kod i en klass som du döper till Exit. 1 public class Exit { 2 public static void main (String[] args) { 3 Random rand = new Random(); 4 int num = rand.nextInt(4); 5 while (num != 0) { 6 System.out.println(num); 7 num = rand.nextInt(4); 8 } 9 System.out.println("Got 0, now " + 10 "we stop this sillyness."); 11 } 12 } Här använder vi en slumpgenerator (skapas på rad 3 och används på rad 4) som sedan får slumpa fram heltal från 0 och upp till men inte med 4. Testkör koden flera gånger och fundera över vad de olika delarna av programmet gör. 2.1 Styrvariabler I övningen ovan hade vi variabeln input som fungerade som sk styrvariabel. En styrvariabel är en variabel som används för att styra ett programs flöde genom att man använder t.ex. if-satser och while-loopar som agerar olika beroende på variabelns värde. En styrvariabel kan vara av vilken typ som helst. I det enklaste fallet är det en sanningsvariabel som sätts till true eller false inne i loopen och som avgör om loopen ska köras igen eller ej. Vanligare är dock att det, som ovan, är en variabel vars värde undersöks för att se om det matchar ett sk stoppvillkor. 3 Do-loopen En while-loop kommer inte köras en enda gång om predikatet är falskt redan från början. I många fall vill man dock garantera att ett stycke kod körs åtminstone en gång oberoende av predikatet, i det fallet kan man använda do-loopen. Den fungerar som en while-loop men istället för att kolla predikatet först så kollas predikatet sist. Do-loopar är förhållandevis ovanliga i produktionskod eftersom de är så lika while-loopar men det är bra att känna till att de finns. 2 Övning 2.2 Klistra in följande kod i en klass som du döper till Exit2. public class Exit2 { public static void main (String[] args) { java.util.Scanner in = new java.util.Scanner(System.in); String input; do { System.out.println("Write ’exit’ to exit."); input = in.next(); } while (!input.equals("exit")); System.out.println("Thank you, now I can rest."); } } Här gör vi en hel del vi inte gjort förut. Dels skapar vi en sk Scanner på rad 3 och 4, det är en komponent som låter Java läsa in text från tangentbordet. (Scanner kommer tas upp på föreläsning 4 och kommer förekomma igen i labb 4.) Dels skapar vi en do-loop som körs tills det att användaren skriver exit. Testkör koden och fundera över vad de olika delarna av programmet gör. Vi kommer hålla på mycket mer med interaktionsloopar i kommande labbar. 4 For-loopen och postinkrementoperatorn Den kanske vanligaste typen av loop i Java är den så kallade for-loopen. Forloopen är så kallat syntaktiskt socker för en while-loop där vi vet precis hur många varv vi ska loopa. Syntaktiskt socker är ett begrepp som används när en konstruktion i ett språk existerar för att lösa ett specifikt problem på ett vackrare, enklare eller mer konsekvent sätt än en mer generell konstruktion kan göra. Vad det innebär är att en for-loop egentligen inte kan göra något som inte en while-loop kan göra, men då dess utseende är mer formaliserat så är den lättare att läsa. En for-loop har inte ett predikat på samma sätt som en while-loop eller en if-sats. Istället fungerar for-loopen på följande vis: 1 for (int i = 0; i < 10; i++) { 2 //do something 3 } Koden ovan kan verka förvirrande vid första anblick men du kommer snabbt lära dig känna igen en for-loop och dess olika delar. Istället för ett predikat har vi tre uttryck separerade av semikolon. Det första som står i parentesen är en 3 variabeldeklaration där vi skapar vår styrvariabel, i det här fallet en heltalsvariabel som får startvärdet 0. Efter det följer ett stoppvillkor, detta kan liknas vid predikatet i en if- eller while-sats. Sist kommer en manipulation av styrvariabeln, i det här fallet en postinkrementation. En postinkrementation, i++, är (nästan) samma sak som i = i + 1, och fungerar för många olika datatyper. För att bättre förstå for-loopen ovan kommer här en while-loop som gör precis samma sak: 1 int i = 0 2 while (i < 10) { 3 //do something 4 i++; 5 } Vad vi har gjort är helt enkelt att vi bakat in styrvariabeln i själva for-satsen snarare än att deklarera den innan loopen och ändra dess värde inne i loopen. Vi har också fördelen att variabeln i bara existerar och kan manipuleras inne i loopen, i while-exemplet blir i kvar och kan användas igen, på gott och ont. Förutom postinkrementation så finns det också en preinkrementation (++i). Den fungerar nästan på samma sätt och i en for-loop gör de samma sak. När ni gjort labb 3 och fått lite känsla för retur-värden kan ni googla på post- och preinkrementation för att läsa på om skillnaderna. Det är viktigt att inse att vissa delar i for-satsen kan utelämnas under speciella förhållanden. T.ex. kan det första fältet utelämnas om man vill använda en styrvariabel som deklarerats utanför for-loopen, på samma sätt som i en while-loop. Det sista fältet kan också utelämnas om man vill. Utelämnar man båda dessa fungerar for-loopen precis som en while-loop. Övning 2.3 Skapa ett program och klistra in for-satsen från exemplet ovan. Ersätt kommentaren ’//do something’ med en utskrift som skriver ut värdet på i. Innan du kör koden, fundera över vad som kommer skrivas ut. Testkör, hade du rätt? 4 Övning 2.4 class Loops { public static void main (String[] args) { int m = 0; while (m > 0) { System.out.print(m + " "); } System.out.println(); do { System.out.print(m + " "); } while (m > 0); System.out.println(); for ( ; m > 0 ; ) { System.out.print (m + " "); } System.out.println(); } } Vilken utskrift får du när du exekverar det här programmet? Försök att förutsäga vilken utskriften kommer att bli innan du exekverar programmet, kontrollera sedan om det stämmer och analysera resultatet. 5 Övning 2.5 class VariableInABlock { public static void main (String[] args) { for (int i = 1; i <= 5; i++) { int n = 0; System.out.print( n + " "); n++; } System.out.println(); // System.out.println(n); } } Vilken utskrift får du när du exekverar det här programmet? Försök att förutsäga vilken utskriften kommer att bli innan du exekverar programmet, kontrollera sedan om det stämmer och analysera resultatet. Vad händer när man tar bortkommentarsmarkeringen? Varför? UPPGIFT 2.1 Skapa en klass som heter Uppgift1 och skapa en main-metod. Skapa en heltalsvariabel i med värdet 5. Skapa sedan en while-loop som skriver ut värdena 5, 10, 15, 20 och 25 genom att skriva ut värdet på i och sedan ändra det. Tänk på att while-loopen ska sluta efter att 25 skrivits ut. Lös samma problem med en do-loop och en for-loop. Hur kan man se till bara multiplar av 5 skrivs ut med en for-loop? UPPGIFT 2.2 Skapa en klass som heter Uppgift2 och skapa en main-metod. Skriv ett program som skriver ut alla stora bokstäver från engelska alfabetet (A till Z) 10 gånger. Använd en loop i en annan loop för att lösa problemet. Den ena loopen ska vara en for-loop och den andra ska vara en while-loop, vilken som ska vara "ytterst" bestämmer du själv. 5 Arrayer En array är den mest enkla och primitiva formen av en sekvens. Formellt sett är array engelska och det svenska ordet är fält eller eventuellt vektor. Det svenska ordet fält hör man dock väldigt sällan och ordet vektor kan lätt blandas ihop 6 med klassen Vector som ni kan komma att stöta på längre fram. Därför använder man oftast ordet array. En array är alltså en sekvenstyp som används för att lagra ett antal värden av en viss typ. Man kan alltså betrakta det som en lista eller en behållare. En array kan bara innehålla element av en viss typ och har en viss längd som sätts när arrayen initieras. Viktigt att veta är att arrayvariabler är referensvariabler, precis som String, med de skillnader från vanliga variabler som det innebär. En array skapas på något av följande sätt: 1 int[] integerArray; 2 integerArray = new int[3]; 3 char[] charArray = {’a’, ’b’, ’c’}; Arrayen integerArray ovan kan innehålla heltal och har kapacitet för 3 element. Vi har dock inte stoppat in några egna värden än så värdena på alla platser i arrayen är int-typens standardvärde, dvs 0. Arrayen charArray har vi dock initierat med en specifik array som innehåller tecknena ’a’, ’b’ och ’c’. Övning 2.6 Klistra in arrayerna ovan i ett program och försök skriva ut variablerna integerArray och charArray. Vad händer i respektive fall? Intressant att inse här är att String, under ytan, bara är en array med chars. För att komma åt ett element ur en array använder man indexering, för att t.ex. skriva ut första elementet i integerArray: 1 System.out.println(integerArray[0]}; Notera att första elementet har index 0 och inte index 1. Index numrerade från 0 används i alla ordnade sekvenser i Java, t.ex. String, ArrayList, LinkedList m.m. Man kan tänka sig en sådan struktur på följande sätt: 0 1 2 3 7 4 5 Övning 2.7 class AnArray { public static void main (String[] args) { int n1 = 11; int n2 = 12; int n3 = 13; int n4 = 14; int n5 = 15; System.out.print( n1 + " "); System.out.print( n2 + " "); System.out.print( n3 + " "); System.out.print( n4 + " "); System.out.print( n5 ); System.out.println(); int[] n = new int[5]; for (int i = 0; i < 5; i++) { n[i] = 11 + i; } for (int i = 0; i < 5; i++) { System.out.print (n[i] + " "); } System.out.prinln(); } } Vilken utskrift får du när du exekverar det här programmet? Utvidga programmet så att det lagrar och skriver ut 10 olika heltal (istället för 5) båda gångerna. 5.1 Referenser igen Som sades i labb 1 kan det vara lite knöligt att förstå sig på referenser. Dels kan det bli problem när man försöker jämföra referenser, men det kan också bli problem när olika variabler refererar till samma data. T.ex. om man gjort följande: 1 String[] a1 = new String[5]; 2 String[] a2 = a1; 8 Övning 2.8 class ReferencesArray { public static void main (String[] args) { int[] u = null; int[] v = null; u = new int[5]; for (int i = 0; i < u.length; i++) { u[i] = i + 1; } for (int i = 0; i < u.length; i++) { System.out.print (u[i] + " "); } System.out.prinln(); v = new int[4]; for (int i = 0; i < v.length; i++) { v[i] = i + 1; } for (int i = 0; i < v.length; i++) { System.out.print (v[i] + " "); } System.out.prinln(); u = v; for (int i = 0; i < u.length; i++) { System.out.print (u[i] + " "); } System.out.prinln(); } } Vilken utskrift får du när du exekverar det här programmet? Varför? Försök att förutsäga vilken utskriften kommer att bli innan du exekverar programmet, kontrollera sedan om det stämmer och analysera resultatet. UPPGIFT 2.3 Skapa en klass som heter Uppgift3 och skapa en main-metod. Skriv sedan ett program som skapar en teckenarray och initierar dess element, samt skriver ut den. Skapa två nya referenser och låt även dessa referera till arrayen. Ändra sedan det första elementet i arrayen genom att använda en av de nya referenserna och det andra elementet i arrayen genom att använda den andra. Avsluta med att visa arrayen tre gånger, via tre olika referenser. 9 5.2 Flerdimensionella arrayer De arrayer vi hittills stött på är den vanligaste, endimensionella, typen av array. Det är dock möjligt att ha flerdimensionella arrayer. En två-dimensionell array skapas exempelvis på följande sätt: 1 //Two-dimensional 8x8 array 2 char[][] twoDimensions = new char[8][8]; Den två-dimensionella arrayen ovan skulle t.ex. kunna användas för att representera ett schack-bräde. Enklaste sättet att tänka är att de två indexen representerar koordinater i ett koordinatsystem, detta gäller även för arrayer av högre dimensioner. Generellt sett ser man sällan arrayer med fler än 3 dimensioner. Övning 2.9 class TwoDimensionalArray { public static void main (String[] args) { int[][] v = new int[4][5]; for (int i = 0; i < v.length; i++) { for (int j = 0; j < v[i].length; j++) { v[i][j] = i + j + 1; } } int[][] u = v; u[0][0] = 9; for (int i = 0; i < v.length; i++) { for (int j = 0; j < v[i].length; j++) { System.out.print(v[i][j] + " "); } System.out.println(); } } } Vilken utskrift får du när du exekverar det här programmet? Försök att förutsäga vilken utskriften kommer att bli innan du exekverar programmet, kontrollera sedan om det stämmer och analysera resultatet. 10 UPPGIFT 2.4 Skriv ett program som skapar en tvådimensionell array, eller matris. Med hjälp av en loopar ska matrisen fyllas med värden så att den motsvarar följande tabell: 1 4 7 2 5 8 3 6 9 Beräkna sedan summan av alla heltal i arrayen genom att loopa över matrisen. Skriv till sist ut summan. 6 Sortering Sortering kan göras på många olika sätt, det finns så många algoritmer för sortering att hela böcker har skrivits på ämnet. Vi kommer dock inte gå in på dessa sorteringsalgoritmer här, om någon är intresserad finns det massor att läsa på Wikipedia. För att sortera arrayer i Java, utan att själv hacka sorteringsalgoritm (sånt är kul men lite utanför kursens ramar), kan man använda den inbyggda klassen Arrays. Använd JavaDoc för klassen Arrays (du hittar den i paketet java.util) för att ta reda på hur den kan användas för sortering. Använd Google för att hitta exempel om du känner att det behövs. UPPGIFT 2.5 Skapa en heltalsarray med 10 slumpmässiga element, använd klassen Random (se Övning 2.1) för att generera heltalen och en for-loop för att lägga till dem i arrayen. Skapa sedan en for each-loop som skriver ut talen. Använd sedan Arrays för att sortera arrayen och skriv till sist ut arrayen igen. Tänk på att Random genererar olika slumpmässiga tal varje gång så bli inte förvirrade när ni får olika tal varje gång ni kör programmet. 7 ArrayList - ett sätt att slippa arrayer Som ni har märkt är arrayer jobbiga att arbeta med, speciellt jobbigt är det att man redan när arrayen skapas måste bestämma dess storlek. Istället för att använda arrayer kan man därför ofta använda klassen ArrayList istället. En ArrayList kan inte innehålla primitiva datatyper, men som tur är finns det för varje primitiv datatyp en klassmotsvarighet, för int heter den Integer. Slå upp ArrayList i JavaDoc för standardbiblioteket, och googla för att hitta exempel om du behöver, lös sedan Uppgift 2.6. 11 UPPGIFT 2.6 Skapa en ArrayList<Integer> med 10 slumpmässiga element, använd klassen Random för att generera heltalen och en for-loop för att lägga till dem i ArrayListen. Skapa sedan en traditionell for loop som skriver ut talen. Använd sedan klassen Collections för att sortera talen och skriv till sist ut ArrayListen igen, den här gången med en for each-loop. Varför använder man fortfarande arrayer om ArrayList är så mycket lättare att arbeta med? Det beror främst på att array är en så enkel datastruktur att den lämpar sig när effektivitet och hastighet är viktiga. Det är av samma skäl förhållandevis enkelt att skicka en array över ett nätverk eller spara en array på hårddisken. 8 Redovisning Nu när ni är färdiga med alla uppgifter är det dags at lämna in era lösningar för Uppgift 2.1 till 2.6 för rättning. Gå igenom era lösningar en extra gång och se till så att hi har kommenterat er kod, och testkört den noga så att ni är säkra på att alla lösningar fungerar. Samla ihop kodfilerna (filerna som slutar på .java) i ett zip-arkiv och ladda upp zip-filen under ’Labb2’ i LISAM. Glöm inte att skriva namnen på båda gruppmedlemmarna i kommentarsfältet vid inlämningen. 12