Loopit
Usein ohjelmoidessa tulee vastaan sellaisia tilanteita, että sama komento täytyy suorittaa monta kertaa peräkkäin. Tarkastellaan tilannetta, jossa halutaan tulostaa numerot yhdestä kymmeneen:
System.out.println(1);
System.out.println(2);
System.out.println(3);
System.out.println(4);
System.out.println(5);
System.out.println(6);
System.out.println(7);
System.out.println(8);
System.out.println(9);
System.out.println(10);
Kaikkien print-komentojen kirjoittaminen ei ole kovinkaan käytännöllistä. Ja entä mitä jos tulostettavien numeroiden määrää ei tiedetä etukäteen? Silloin kaikkia print-komentoja ei voi kirjoittaa käsin.
Tässä tilanteessa kannattaa käyttää looppia (silmukkaa). Looppeja on kolme erilaista.
While-loop
Kirjoitetaan koodi uudelleen käyttäen while-silmukkaa:
int i = 1;
while (i <= 10) {
System.out.println(i);
i++;
}
Koodi lyheni huomattavasti. Mutta mikä on while-silmukka?
While toimii niin, että sulkeiden sisään kirjoitetaan jokin ehto, ja jos ehdosta tulee
totuusarvo true
, niin aaltosulkeiden sisällä oleva koodi suoritetaan. Jos ehdosta tulee
totuusarvo false
, niin silmukan suoritus loppuu (siispä jos kirjoitat sulkeiden sisään true,
niin silmukka ei ikinä lopu, ja jos kirjoitat sulkeiden sisään false, niin silmukka
ei tee mitään).
Tämä koodi siis toimii niin, että aluksi määritellään muuttuja i
, ja annetaan sille
arvoksi 1. Seuraavalla rivillä while-silmukka alkaa ja tarkistaa, onko i:n arvo
pienempi tai yhtä suuri kuin 10. Koska ehto on tosi, silmukan sisällä oleva koodi
suoritetaan: i:n arvo tulostetaan ja i:n arvoa korotetaan yhdellä. Sitten silmukka
alkaa alusta, ja tarkistaa, onko i:n arvo vielä pienempi tai yhtä suuri kuin 10.
Tämä jatkuu siihen saakka, kunnes i saa arvon 11. Ehto ei enää toteudu, joten silmukka
loppuu ja silmukan jälkeen tuleva koodi voidaan suorittaa (tässä tapauksessa enempää
koodia ei ollut).
For-loop
Toinen silmukkatyyppi on for-silmukka. Kirjoitetaan koodi uudelleen käyttäen for-silmukkaa:
for (int i = 1; i <= 10; i++) {
System.out.println(i);
}
For-silmukan syntaksi on vähän erilainen kuin while-silmukan. Jos vertaat tätä ja edellistä silmukkaa, niin huomaat, että ne koostuvat samoista osista, mutta for-silmukassa kaikki kolme i-muuttujaa käsittelevää riviä on laitettu silmukan sulkeiden sisälle. For-silmukan sulkeiden sisään laitetaan kolme eri asiaa: määritellään alkutilanne, kerrotaan missä tilanteessa silmukan suorittamista jatketaan, ja lisäksi kerrotaan komento, joka suoritetaan joka kierroksen lopussa.
Listojen läpikäyminen
Kolmas silmukka on myös for-silmukka, mutta sitä käytetään listojen läpikäymiseen. Sen
syntaksi näyttää tältä:
int[] lista = {1,2,3,4,5,6,7,8,9,10};
for (int numero: lista) {
System.out.println(numero);
}
Tällaista silmukkaa käytetään niin, että ensin määritellään sulkujen sisälle muuttuja,
johon haluat sijoittaa vuorotellen kaikki listan sisältämät arvot (tässä int numero
),
ja sitten kaksoispisteen jälkeen kerrotaan lista, joka halutaan käydä läpi. Huomaa,
että muuttujan tyyppi täytyy olla sama kuin listan sisältämien alkioiden tyyppi. Jos
listassa olisi vaikka String-tyyppisiä alkioita, ja yrittäisit käydä niitä läpi tyyliin
for (int alkio: lista)
, niin tässähän yrittäisit laittaa String-tyyppisiä arvoja
int-tyyppiseen muuttujaan. Näin ei voi tehdä, ja Java-kääntäjäkin valittaisi asiasta:
error: incompatible types: String cannot be converted to int
Tämän kolmannen silmukan syntaksi saattaa näyttää aluksi vieraalta, mutta sen käyttäminen on yleensä helpompaa kuin indeksien käyttäminen listan läpikäymiseen: ei tarvitse miettiä, mitkä ovat listan alku- ja loppuindeksit.
Nämä kaksi silmukkaa tekevät saman asian:
String[] lista = {"alkio 1", "alkio 2", "alkio 3"};
for (int i = 0; i < lista.length; i++) {
System.out.println(lista[i]);
}
for (String alkio: lista) {
System.out.println(alkio);
}
Listojen muokkaaminen loopissa
Kuitenkin jos haluaisit esimerkiksi lisätä kaikkiin listan alkioihin jonkin luvun tai muokata listaa jollain toisella tavalla, et siihen pystyisi käyttämään tätä kolmatta silmukkatyyppiä. Silmukka nimittäin vain tallentaa listan alkion arvon määrittelemääsi muuttujaan, ja jos muokkaat muuttujan arvoa, niin se ei tee listassa sijaitsevalle alkuperäiselle arvolle mitään. Tässä tapauksessa täytyy käyttää tavallista for-looppia ja käydä lista läpi indeksien avulla.
for (int i = 0; i < lista.length; i++) {
lista[i] += 1;
}
Jos haluaisit esimerkiksi käydä loopissa läpi ArrayListin ja poistaa siitä arvoja, sinun täytyy käydä lista läpi lopusta alkuun. Nimittäin jos poistat listan keskeltä arvon, niin kaikkien sen jälkeisten alkioiden indeksi vähenee yhdellä, ja jos käyt listaa läpi alusta loppuun, niin seuraava alkio jää käymättä läpi (koska se korvaa juuri läpikäydyn alkion ja looppi siirtyy seuraavaan). Lisäksi lista tulee lyhyemmäksi, mutta jos alussa olet määritellyt loopin jatkuvan alkuperäisen listan pituuteen saakka, niin tästä syntyy ajonaikainen virhe, kun yrität saada listasta alkioita indekseistä joita ei ole enää olemassa. Mutta lopusta alkuun listaa läpikäydessä nämä asiat eivät haittaa, koska listan muuttuva loppupää on jo käyty läpi. Tämä toteutetaan näin:
ArrayList<Integer> lista = new ArrayList<>();
lista.add(24);
lista.add(-100);
lista.add(77);
lista.add(-61);
// poistetaan listasta negatiiviset luvut:
for (int i = 0; i < lista.size(); i++) {
if (lista.get(i) < 0) {
lista.remove(i);
}
}