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