Osa 2

Lisää toistolauseita

Tähän mennessä käyttämämme "while-true" -toistolause on erittäin näppärä silloin, kun ohjelmassa tulee toistaa toiminnallisuutta kunnes käyttäjä syöttää tietynlaisen syötteen.

Tutustutaan seuraavaksi muutamaan muuhun toiston toteutustapaan.

While-toistolause ehdolla

Olemme tähän mennessä käyttäneet toistolausetta, jonka suluissa on totuusarvo true, jolloin toistoa on jatkettu ikuisesti (tai kunnes toistolauseessa päädytään komentoon break).

Toistolauseen sulut sisältävät oikeastaan ehtolausekkeen, aivan samalla tavalla kuin if-komentoa seuraavat sulut. Arvon true voi korvata lausekkeella, joka evaluoidaan ohjelman suorituksen yhteydessä. Lauseke määritellään täsmälleen samalla tavalla kuin ehtolauseen lauseke.

Seuraavassa esimerkissä tulostetaan luvut 1, 2, ..., 5. Kun luku-muuttujan arvo on yli 5, while-ehto ei ole enää voimassa ja toistaminen lopetetaan.

int luku = 1;

while (luku < 6) {
    System.out.println(luku);
    luku++;
}

Lue ylläoleva "niin pitkään kuin muuttujan luku arvo on pienempi kuin 6, tulosta muuttujan luku arvo ja kasvata muuttujan luku arvoa yhdellä".

Loading...

Yllä muuttujan luku arvoa kasvatetaan yhdellä aina kun toistolauseen lohko suoritetaan.

Alla on video toistolauseen käytöstä.

For-toistolause

Edellä näimme miten while-toistolauseen ehdon avulla voidaan käydä läpi lukuja tietystä luvusta tiettyyn lukuun.

Tällaisen toistolauseen rakenne on seuraava.

int i = 0;
while (i < 10) {
    System.out.println(i);
    i++;
}

Ylläolevan toistolauseen voi pilkkoa kolmeen osaan. Ensin esittelemme toistolauseessa toistokertojen laskemiseen käytettävän muuttujan i ja asetamme sen arvon nollaksi: int i = 0;. Tätä seuraa toistolauseen määrittely — toistolauseen ehto on i < 10 eli toistolausetta suoritetaan niin pitkään kuin muuttujan i arvo on pienempi kuin 10. Toistolauseessa on toistettava toiminnallisuus System.out.println(i);, jota seuraa toistolauseessa käytettävän muuttujan kasvatus i++.

Saman toteuttaminen tapahtuu for-toistolauseella seuraavasti.

for (int i = 0; i < 10; i++) {
    System.out.println(i);
}

For-toistolause koostuu neljästä osasta: (1) toistokertojen laskemiseen käytettävän muuttujan esittelystä; (2) toistolauseen ehdosta; (3) laskemiseen käytetyn muuttujan kasvattamisesta (tai pienentämisestä tai muuttamisesta); ja (4) toistettavasta toiminnallisuudesta.

for (*muuttujan esittely*; *ehto*; *kasvatus*) {
    // toistettava toiminnallisuus
}

Alla on kuvattuna toistolauseen suoritus askeleittain.

Loading...

Yllä olevassa esimerkissä ohjelma tulostaa luvut nollasta neljään. Arvoalueen voi määrittää myös muuttujien avulla — alla olevassa esimerkissä määritellään muuttujat alku ja loppu, joiden avulla määritellään toistolauseen käsittelemä lukualue.

int alku = 3;
int loppu = 7;
for (int i = alku; i < loppu; i++) {
    System.out.println(i);
}
Loading...

Seuraavissa tehtävissä jatketaan toistolauseiden harjoittelua. Voit käyttää tehtävissä joko ehdollista while-toistolausetta, tai for-toistolausetta.

Loading
Loading
Loading

Toistolauseen suorituksen loppumisesta

Toistolauseen suoritus ei lopu heti kun toistolauseen ehtolauseke voisi evaluoitua todeksi. Toistolauseen ehtolauseke evaluoidaan aina kun saavutaan toistolauseen alkuun, eli (1) kun ohjelman seuraava suoritettava lause on toistolause, ja (2) kun toistolauseeseen liittyvän lohkon sisältämän ohjelmakoodin suoritus on saatu loppuun.

Tarkastellaan seuraavaa toistolausetta.

int luku = 1;

while (luku != 2) {
    System.out.println(luku);
    luku = 2;
    System.out.println(luku);
    luku = 1;
}

Ohjelman tulostus seuraavanlainen:

Esimerkkitulostus
1 2 1 2 1 2 ...

Vaikka muuttujan luku arvo on välillä 2, toistolauseen suoritus ei lopu koskaan.

Toistolauseen ehto tarkistetaan silloin kun toistolauseen toistaminen aloitetaan sekä silloin kun koodin suoritus on päässyt toistolauseen lopettavaan aaltosulkuun asti. Mikäli toistolauseen ehdon lauseke on evaluoituu todeksi eli muotoon true, suoritus jatkuu toistolauseen alusta. Mikäli lauseke evaluoituu epätodeksi eli muotoon false, suoritus siirtyy toistolausetta seuraavaan lauseeseen.

Vastaava sääntö pätee myös for-toistolauseelle. Alla olevassa esimerkissä toistolauseen suoritus — väärin ymmärrettynä — pitäisi lopettaa heti, kun muuttujan i arvo on 100. Näin ei kuitenkaan käy.

for (int i = 0; i != 100; i++) {
    System.out.println(i);
    i = 100;
    System.out.println(i);
    i = 0;
}

Yllä olevan ohjelman suoritus ei pääty koskaan.

Toistetaan toiminnallisuutta

Eräs yleinen ongelmatyyppi on "tee jotain tietty määrä kertoja". Näissä ohjelmissa esiintyy toisto, jonka jokaisella toistokerralla tehdään haluttu toiminnallisuus sekä muutetaan kertojen lukumäärää laskevaa laskurimuuttujaa.

Seuraava ohjelma laskee tulon 4*3 hieman kömpelöllä tavalla eli summana 3 + 3 + 3 + 3:

int tulos = 0;

int i = 0;
while (true) {
    tulos += 3; // tarkoittaa samaa kuin tulos = tulos + 3;
    i++;  // tarkoittaa samaa kuin i = i + 1;

    if (i == 4) {
        break;
    }
}

System.out.println(tulos);

Saman toiminnallisuuden voi toteuttaa myös seuraavasti.

int tulos = 0;

int i = 0;
while (i < 4) {
    tulos += 3; // tarkoittaa samaa kuin tulos = tulos + 3;
    i++;  // tarkoittaa samaa kuin i = i + 1;
}

System.out.println(tulos);

Tai for-lauseen avulla seuraavasti.

int tulos = 0;

for (int i = 0; i < 4; i++) {
    tulos += 3;
}

System.out.println(tulos);

Alla ohjelman suoritus on kuvattuna while-toistolausetta käyttäen.

Loading...
Loading
Loading
Loading

Toistolausetta käyttävien ohjelmien rakenteesta

Edellisissä esimerkeissä olemme keskittyneet ohjelmiin, joissa toistolauseessa olevaa koodia toistetaan tietty määrä. Tämä määrä on voinut rajoittua käyttäjän syötteen perusteella — tällaisissa ohjelmissa for-toistolause on varsin näppärä.

Ohjelmissa, joissa toistolauseessa olevaa koodia tulee suorittaa kunnes käyttäjä syöttää tietyn syötteen, for-toistolause ei toimi kovin hyvin. Tällöin aiemmin harjoittelemamme while-true -toistolause toimii hyvin.

Tarkastellaan lyhyesti hieman laajempaa ohjelmaa, joka lukee käyttäjältä kokonaislukuja. Ohjelma käsittelee negatiiviset luvut epäkelpoina lukuina, positiiviset luvut hyväksyttävinä lukuina, sekä nollan lukemisen lopettamista ilmaisevana lukuna. Kun käyttäjä syöttää nollan, ohjelma tulostaa hyväksyttyjen lukujen summan, hyväksyttyjen lukujen lukumäärän sekä epäkelpojen lukujen lukumäärän.

Alla on kuvattuna eräs mahdollinen ratkaisu, joka ei kuitenkaan ole tyylin kannalta ideaali.

Scanner lukija = new Scanner(System.in);

System.out.print("Anna lukuja, negatiiviset luvut eivät kelpaa: ");
int summa = 0;
int hyvaksytytLuvut = 0;
int epakelvotLuvut = 0;

while (true) {
    int luettu = Integer.valueOf(lukija.nextLine());

    if (luettu == 0) {
        System.out.println("Hyväksyttävien lukujen summa: " + summa);
        System.out.println("Hyväksyttyjä lukuja: " + hyvaksytytLuvut);
        System.out.println("Epäkelvot luvut: " + epakelvotLuvut);
        break;
    }

    if (luettu < 0) {
        epakelvotLuvut++;
        continue;
    }

    summa += luettu;
    hyvaksytytLuvut++;
}

Yllä kuvatussa lähestymistavassa toistolauseen päättymisen jälkeen tapahtuva laskenta on toteutettu toistolauseen sisälle. Lähestymistapa ei ole suositeltava, sillä se johtaa helposti hyvin monimutkaiseen ohjelman rakenteeseen. Jos toistolauseen lopettamisen yhteydessä pitäisi tehdä muutakin — esimerkiksi lukea lisää syötteitä — asetettaisiin kyseinenkin toiminnallisuus helposti ehtolauseen sisälle. Lisätoiminnallisuuden kertyessä, ohjelma muuttuisi yhä vaikeammin ja vaikeammin luettavaksi.

Pitäydytään seuraavassa toistolauseen muodossa:

Scanner lukija = new Scanner(System.in);

// toistolauseessa tarvittavien muuttujien luominen

while (true) {
    // syötteen lukeminen

    // toistolauseesta poistuminen -- break

    // epäkelpojen syötteiden rajaaminen pois -- continue

    // hyväksyttävien syötteiden käsittely
}

// toistolauseesta poistumisen jälkeen suoritettava toiminnallisuus

Toisin sanoen, oleva ohjelma on selkeämpi jos toistolauseesta poistumisen jälkeen tehtävät asiat ovat toistolauseen ulkopuolella.

Scanner lukija = new Scanner(System.in);

System.out.print("Anna lukuja, negatiiviset luvut eivät kelpaa: ");
int summa = 0;
int hyvaksytytLuvut = 0;
int epakelvotLuvut = 0;

while (true) {
    int luettu = Integer.valueOf(lukija.nextLine());

    if (luettu == 0) {
        break;
    }

    if (luettu < 0) {
        epakelvotLuvut++;
        continue;
    }

    summa += luettu;
    hyvaksytytLuvut++;
}

System.out.println("Hyväksyttävien lukujen summa: " + summa);
System.out.println("Hyväksyttyjä lukuja: " + hyvaksytytLuvut);
System.out.println("Epäkelvot luvut: " + epakelvotLuvut);
Loading
Pääsit aliluvun loppuun! Jatka tästä seuraavaan osaan:

Muistathan tarkistaa pistetilanteesi materiaalin oikeassa alareunassa olevasta pallosta!