Viikko 2

9 Muuttuvat muuttujat

Olemassaolevan muuttujan arvoa halutaan usein muuttaa. Tämä onnistuu tavallisen sijoituslausekkeen avulla. Seuraavassa muuttujan ika arvoa kasvatetaan yhdellä:

int ika = 1;

System.out.println( ika );    // tulostuu 1
ika = ika + 1;                // ika:n uusi arvo on ika:n vanha arvo plus yksi    
System.out.println( ika );    // tulostuu 2

Komento ika = ika + 1 siis kasvattaa muuttujan ika arvoa yhdellä. Muuttujan arvon kasvattaminen yhdellä onnistuu myös seuraavasti:

int ika = 1;

System.out.println( ika );    // tulostuu 1
ika++;                        // tarkoittaa samaa kuin ika = ika + 1;
System.out.println( ika );    // tulostuu 2

Toinen esimerkki:

int pituus = 100;

System.out.println( pituus );   // tulostuu 100
pituus = pituus - 50;    
System.out.println( pituus );   // tulostuu 50
pituus = pituus * 2;
System.out.println( pituus );   // tulostuu 100 
pituus = pituus / 4;
System.out.println( pituus );   // tulostuu 25
pituus--;                       // sama kuin pituus = pituus-1;
System.out.println( pituus );   // tulostuu 24

Tee ohjelma, joka kysyy käyttäjältä kolme lukua ja tulostaa niitten summan. Tee ohjelmastasi seuraavan muotoinen:

Scanner lukija = new Scanner(System.in);
int summa = 0;
int luettu;

// KIRJOITA OHJELMA TÄHÄN
// ÄLÄ KÄYTÄ MUITA MUUTTUJIA KUIN lukija, summa JA luettu!

System.out.println("Summa: "+summa);
Anna ensimmäinen luku: 3
Anna toinen luku: 6
Anna kolmas luku: 12

Summa: 21

Tee ohjelma, joka lukee käyttäjältä lukuja ja tulostaa niiden summan. Ohjelma lopettaa kyselemisen kun syötetään luku 0. Käytä seuraavaa pohjaa, jonka saat myös palautusautomaatilta:

Scanner lukija = new Scanner(System.in);

int summa = 0;
System.out.print("Anna lukuja, nolla lopettaa: ");
while (true) {
    int luettu = Integer.parseInt(lukija.nextLine());
    if (luettu == 0) {
        break;
    }

    // TEE JOTAIN TÄÄLLÄ

    System.out.println("Summa nyt: "+summa);
}
System.out.println("Summa lopussa: "+summa);

Ohjelman tulee toimia seuraavasti:

Anna lukuja, nolla lopettaa:
3
Summa nyt: 3
2
Summa nyt: 5
1
Summa nyt: 6
1
Summa nyt: 7
0
Summa lopussa: 7

10 Lisää toistoa

Opimme aiemmin toteuttamaan while(true)-komennon avulla ohjelman, joka toistaa tiettyä komentosarjaa komennon break suorittamiseen asti.

Komento break ei ole ainoa tapa lopettaa toistoa. Toistokomennon yleinen muoto on while (ehto), jossa ehtona voi olla mikä tahansa totuusarvoinen lauseke, eli ehto voi olla täsmälleen samaa muotoa kuin if-komentojen ehdot.

Seuraavassa esimerkissä tulostetaan luvut 1, 2, ..., 10. Kun luku-muuttuja saa arvokseen yli 10, while-ehto ei ole enää voimassa ja toistaminen lopetetaan.

int luku = 1;

while (luku < 11) {
    System.out.println(luku);
    luku++;    // luku++ tarkoittaa samaa kuin luku = luku + 1
}

Lue ylläoleva "niin pitkään kuin luku on pienempi kuin 11, tulosta luku ja kasvata lukua yhdellä".

Ylläolevassa koodissa ehdossa olevaa muuttujaa luku kasvatettiin jokaisella kierroksella yhdellä. Päivitys voi olla mikä tahansa, eli ehdossa olevan muuttujan ei tarvitse suinkaan aina kasvaa yhdellä, esim:

int luku = 1024;

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

Screencast aiheesta:

Muutama NetBeans-vihje
  • Kaikki NetBeans-vihjeet löytyvät täältä täältä
  • Koodin automaattinen täydennys

    Jos ohjelmassasi on käytössä esim. muuttuja String sukunimi;, ei koko muuttujan nimeä tarvitse välttämättä joka kerta kirjoittaa kokonaan. Kokeile mitä tapahtuu kun kirjoitat s ja sen jälkeen painat yhtäaikaa ctrl ja välilyönti. HUOM: laitoksen koneilla automaattinen täydennys saadaan aikaan painamalla yhtä aikaa ctrl, alt ja välilyönti. Vastaavalla tavalla NetBeans osaa täydentää muitakin nimiä, esim. komennon while aikaansaamiseksi riittää kirjoittaa w ja painaa ctrl+välilyönti...

  • sout

    Muista että saat ruudulle tekstin System.out.println("") kirjoittamalla sout ja painamalla tabulaattoria eli q:n vasemmalla puolella olevaa näppäintä

Tee seuraavat tehtävät while-komennon avulla:

Tee ohjelma, joka tulostaa kokonaisluvut väliltä 1–100.

Ohjelman tulostus on seuraava:

1
2
3
(välissä paljon rivejä)
98
99
100

Tee ohjelma, joka tulostaa kokonaisluvut väliltä 100–1.

Ohjelman tulostus on seuraava:

100
99
98
(välissä paljon rivejä)
3
2
1

Vihje: aseta toistossa käytettävän apumuuttujan arvoksi aluksi 100 ja vähennä muuttujan arvoa yhdellä toiston sisällä.

Tee ohjelma, joka tulostaa parilliset kokonaisluvut väliltä 2–100.

2
4
6
(välissä paljon rivejä)
96
98
100

Kirjoita ohjelma, joka tulostaa kokonaisluvut 1:stä käyttäjän antamaan lukuun asti.

Mihin asti? 3
1
2
3
Mihin asti? 5
1
2
3
4
5

Vihje: käyttäjältä lukemasi luku toimii nyt whilen lopetusehdon ylärajana. Muista että Javassa a <= b tarkoittaa a pienempi tai yhtä suuri kuin b.

Kirjoita ohjelma, joka kysyy käyttäjältä ensimmäisen ja viimeisen luvun ja tulostaa niiden välissä olevat luvut.

Ensimmäinen: 5
Viimeinen: 8
5
6
7
8

Jos ensimmäinen on suurempi kuin viimeinen ei tulostu mitään:

Ensimmäinen: 16
Viimeinen: 12

Huom! muista että ala- ja yläraja voivat olla myös negatiivisia!

10.1 Sijoitusoperaatiot

Koska vanhan muuttujan arvon muuttaminen on hyvin yleinen operaatio, on Javassa sitä varten erityiset sijoitusoperaatiot.

int pituus = 100;

pituus += 10;  // sama kuin pituus = pituus + 10;
pituus -= 50;  // sama kuin pituus = pituus - 50;

Olemassaolevan muuttujan arvoa muuttava sijoitusoperaatio merkitään muuttuja muutostyyppi= muutos, esimerkiksi muuttuja += 5. Huomaa, että muuttujan tyyppi pitää aina kertoa ennen kuin sille voidaan asettaa arvo. Muuttuja tulee siis aina esitellä ennen kuin se on käytettävissä. Muuttujan esittely tapahtuu kertomalla muuttujan tyyppi ja nimi.

Seuraava esimerkki ei toimi, sillä muuttujan pituus tyyppiä ei ole kerrottu.

pituus = pituus + 100;   // ei toimi!
pituus += 100;           // ei toimi!

Kun tyyppi on kerrottu, laskutkin toimivat oikein.

int pituus = 0;
pituus = pituus + 100;
pituus += 100;

// muuttujan pituus arvo on 200

Myös muille kuin yhteen- ja vähennyslaskuille on Javassa vastaavat sijoitusoperaatiot.

int pituus = 100;

pituus *= 10; // sama kuin pituus = 10 * pituus; 
pituus /= 100; //sama kuin pituus = pituus / 100;
pituus %= 3;  // sama kuin pituus = pituus % 3;

// muuttujan pituus arvo 1

Usein ohjelmissa esiintyy toisto jonka aikana muuttujaan lasketaan jokin toistosta riippuvainen arvo. Seuraava ohjelma laskee tulon 4*3 hieman kömpelöllä tavalla eli summana 3+3+3+3:

int tulos = 0;

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

Alussa tulos = 0. Toistossa muuttujan arvo nousee joka kierroksella 3:lla. Ja koska toistoja on 4, on lopulta muuttujan arvona siis 3*4.

Käyttämällä yllä esiteltyä sijoitusoperaattoria, sama saadaan aikaan seuraavasti:

int tulos = 0;

int i = 0;
while ( i < 4 ) {
    tulos += 3;      // tämä on siis sama kuin tulos = tulos + 3;
    i++;             // tarkoittaa samaa kuin i = i+1;
}

Tee ohjelma, joka laskee summan 1+2+3+...+n, missä n on käyttäjän syöttämä luku.

Esimerkkitulostuksia:

Mihin asti? 3
Summa on 6   

Edellisessä esimerkissä laskettiin 1+2+3 = 6

Mihin asti? 7
Summa on 28   

Ja nyt laskettiin 1+2+3+4+5+6+7 = 28

Vihje: Tee ohjelma while-komennon avulla. Käytä ohjelmassasi apumuuttujaa toistokertojen muistamiseen. Lisää jokaisella toistokerralla toistokerrat muistavan muuttujan arvo apumuuttujaan johon lasket summan arvon.

Muuta edellistä tehtävää siten, että käyttäjä määrää summan laskemisen aloituskohdan. Voit olettaa, että käyttäjä antaa ensin pienemmän luvun ja sitten suuremman luvun.

Esimerkkitulostuksia:

Ensimmäinen: 3
Viimeinen: 5
Summa on 12
Ensimmäinen: 2
Viimeinen: 8
Summa on 35

Tee ohjelma, joka laskee luvun n kertoman. Kertoma n! lasketaan kaavalla 1*2*3*...*n. Esimerkiksi 4! = 1*2*3*4 = 24. Lisäksi on määritelty, että 0! = 1.

Esimerkkitulostuksia:

Anna luku: 3
Kertoma on 6
Anna luku: 10
Kertoma on 3628800

Tee ohjelma, joka laskee summan 20+21+22+...+2n, missä n on käyttäjän syöttämä luku. Merkintä 2i tarkoittaa luvun 2 korottamista potenssiin i, esimerkiksi 24 = 2*2*2*2 = 16. Javassa merkintä ab ei ole käytössä, mutta potenssin voi laskea komennolla Math.pow(luku, potenssi). Huom. komento palauttaa double-tyyppisen eli liukulukutyyppisen luvun. Liukulukutyyppisen luvun voi muuttaa kokonaisluvuksi ( int-tyyppiseksi ) seuraavasti: int tulos = (int) Math.pow(2, 3). Lasku asettaa muuttujaan tulos laskun 2 potenssiin 3 arvon.

Esimerkkitulostuksia:

Anna luku: 3
Tulos on 15
Anna luku: 7
Tulos on 255

10.2 Ikuinen silmukka

Yksi suosituimmista ohjelmointivirheistä toistolauseissa on tehdä vahingossa ikuinen silmukka. Seuraavassa yritetään tulostaa ruudulle 10 kertaa "En enää ikinä ohjelmoi ikuista silmukkaa":

int i = 0;

while( i<10 ) {
    System.out.println("En enää ikinä ohjelmoi ikuista silmukkaa");
}

Toistokertojen määrää kontrolloiva muuttuja i on aluksi 0 ja toistoja on tarkoitus tehdä niin kauan kuin i<10. Käy kuitenkin hieman hassusti: muuttujan i arvoa ei muuteta missään, joten toistoehto pysyy ikuisesti totena.

10.3 while ja lopetus

Olemme tehneet peräkkäin jo muutamia toistotehtäviä, joissa toistoehto on muotoa:

int i = 1;
while ( i < 10 ) {
    // ...
    i++;
}

Ylläolevassa rungossa muuttuja i muistaa toistokertojen määrän, ja lopetusehto perustuu i:n vertailuun.

Muistellaan taas toiston lopetusta. Toiston lopetuksen ei tarvitse perustua toistokertojen laskemiseen. Katsotaan esimerkkiä jossa kysytään käyttäjän ikää. Jos ikä ei ole välillä 5-85, annetaan huomautus ja kysytään ikä uudelleen. Toistolauseen while-lauseen ehto voi siis olla mitä tahansa totuusarvon tuottavaa.

System.out.println("ikäsi: ");

int ika = Integer.parseInt(lukija.nextLine());

while( ika < 5 || ika  > 85 ) {   // ikä pienempi kuin 5 TAI suurempi kuin 85
    System.out.println("Valehtelet");
    if ( ika < 5 ) {
        System.out.println("Olet niin nuori ettet osaa kirjoittaa");   
    } else if ( ika > 85 ) {
        System.out.println("Olet niin vanha ettet osaa käyttää tietokonetta");   
    } 

    System.out.println("syötä ikäsi uudelleen: ");
    ika = Integer.parseInt(lukija.nextLine();
}

System.out.println("Ikäsi on siis "+ ika);

Ohjelman olisi voinut tehdä myös vanhaa tuttua while(true) -rakennetta käyttäen:

System.out.println("ikäsi: ");

while( true ) {   
    int ika = Integer.parseInt(lukija.nextLine());

    if ( ika >= 5 && ika <= 85 ) {   // ikä 5:n JA 85:n välillä
        break;                              // lopetetaan toisto
    }

    System.out.println("Valehtelet");
    if ( ika < 5 ) {
        System.out.println("Olet niin nuori ettet osaa kirjoittaa");   
    } else {  // ikä siis yli 85
        System.out.println("Olet niin vanha ettet osaa käyttää tietokonetta");   
    } 

    System.out.println("syötä ikäsi uudelleen: ");
}

System.out.println("Ikäsi on siis "+ ika);

Tämä tehtäväsarja muodostaa yhden isomman ohjelman, jonka toiminnallisuus toteutetaan pienissä paloissa. Jos et tee tehtäväsarjaa loppuun asti, voit lähettää sen tarkastettavaksi vajaatekoisenakin. Tämä onnistuu painamalla testausnapin oikealla puolella olevasta "submit"-napista eli pienestä ylöspäinosoittavasta nuolesta. Vaikka palautusautomaatti valittaakin vielä tekemättä olevien tehtävänosien testeistä, kirjautuvat jo tekemiesi osien pisteet.

Huom: nyt (ja jatkossa) jokainen isomman tehtävän "alitehtävä" (kuten 36.1) on saman arvoinen tehtävä kuin alikohdaton tehtävä. Tehtävä 36 siis vastaa viittä normaalia tehtävää.

36.1 Lukujen lukeminen

Tee ohjelma, joka kysyy käyttäjältä lukuja (ohjelma tulostaa käyttäjälle aluksi "Syötä luvut:"), kunnes käyttäjä antaa luvun -1. Kun käyttäjä syöttää luvun -1, ohjelma tulostaa "Kiitos ja näkemiin!" ja päättyy.

Syötä luvut:
5
2
4
-1
Kiitos ja näkemiin!

36.2 Lukujen summa

Laajenna edellistä ohjelmaa siten, että ohjelma ilmoittaa käyttäjän syöttämien lukujen summan. (Lukua -1 ei lasketa mukaan.)

Syötä luvut:
5
2
4
-1
Kiitos ja näkemiin!
Summa: 11

36.3 Lukujen summa ja lukumäärä

Laajenna edellistä ohjelmaa siten, että ohjelma ilmoittaa myös käyttäjien antamien lukujen lukumäärän. (Lukua -1 ei lasketa mukaan.)

Syötä luvut:
5
2
4
-1
Kiitos ja näkemiin!
Summa: 11
Lukuja: 3

36.4 Lukujen keskiarvo

Muuta edellistä ohjelmaa siten, ohjelma ilmoittaa lukujen keskiarvon. (Lukua -1 ei lasketa mukaan.)

Syötä luvut:
5
2
4
-1
Kiitos ja näkemiin!
Summa: 11
Lukuja: 3
Keskiarvo: 3.666666666666

36.5 Parilliset ja parittomat

Laajenna edellistä ohjelmaa siten, että ohjelma ilmoittaa parillisten ja parittomien lukujen määrän. (Lukua -1 ei lasketa mukaan.)

Syötä luvut:
5
2
4
-1
Kiitos ja näkemiin!
Summa: 11
Lukuja: 3
Keskiarvo: 3.666666666666
Parillisia: 2
Parittomia: 1
Huomio: Ohjelmien tekeminen pienissä paloissa

Edeltävissä tehtävissä tehtiin oikeastaan ainoastaan yksi ohjelma, mutta ohjelman rakentaminen tapahtui hyvin pienissä paloissa. Tämä on ehdottoman suositeltava tapa AINA kun ohjelmoit.

Eli kun teet ohjelmaa, oli se sitten harjoitustehtävä tai oma projektisi, kannattaa edetä hyvin pienissä paloissa. Älä koskaan yritä ratkaista koko ongelmaa kerralla. Aloita jollain helpolla asialla jonka tiedät varmasti osaavasi. Esim. edellisessä tehtäväsarjassa keskityttiin aluksi pelkästään siihen, että osataan pysäyttää ohjelma käyttäjän syöttäessä luvun -1. Kun yksi ohjelman osa on saatu toimimaan, voidaan siirtyä ratkaisemaan jotain seuraavaa varsinaisen ongelman osaongelmaa.

Osa kurssin tehtäviä on edellisten tapaan valmiiksi osiin pilkottuja. Usein osat pitää vielä pilkkoa ohjelmoinnin kannalta vieläkin pienempiin paloihin. Kannattaa tehdä siten, että suoritat ohjelman lähes jokaisen uuden koodirivin jälkeen. Tällöin varmistat, että ratkaisu on etenemässä haluttuun suuntaan.

Lisätietoa: toisto for-lauseen avulla

Edellä esitellyn while-toistolauseen lisäksi Javassa toiston voi hoitaa myös for-toistolauseen avulla. Varsinaisesti rupeamme käyttämään for:ia vasta hieman myöhemmin kurssilla, mutta jo tässä vaiheessa mainittakoon, että toistolause

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

tehtäisiin for:in avulla seuraavasti:

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

eli for-komento sisältää samalla rivillä indeksimuuttujan alustuksen, toistoehton ja indeksimuuttujan kasvatuksen puolipistein eroteltuna. Voit unohtaa for:in olemassaolon toistaiseksi jos et halua sekoittaa päätäsi sen olemassaololla.

11 Metodit

Olemme käyttäneet useita erilaisia komentoja Javassa: sijoitusta, laskutoimituksia, vertailuja, if:iä ja whileä. Ruudulle tulostaminen on tehty "komentoa" System.out.println() käyttäen. Kahden luvun maksimi osataan laskea "komennolla" Math.max(). Tuttuja ovat myös lukija.nextLine() ja sen kanssa usein nähty Integer.parseInt().

Huomaamme, että jälkimmäinen joukko edellä lueteltuja komentoja poikkeaa if:istä ja while:stä ym. siinä, että komennon perässä on sulut ja joskus sulkujen sisällä komennolle annettava syöte. "Sulkuihin päättyvät" eivät oikeastaan olekaan komentoja vaan metodeja.

Teknisesti ottaen metodi tarkoittaa koodinpätkää, jota voi kutsua muualta ohjelmakoodista. Koodirivi System.out.println("olen metodille annettava parametri!") siis tarkoittaa, että kutsutaan metodia, joka suorittaa ruudulle tulostamisen. Metodin suorituksen jälkeen palataan siihen kohtaa missä ennen metodikutsua oltiin menossa. Metodille suluissa annettua syötettä kutsutaan metodin parametriksi.

Parametrin lisäksi metodilla voi olla paluuarvo. Esim. tuttu koodinpätkä:

int luku = Integer.parseInt( lukija.nextLine() );

sisältää kaksi metodikutsua. Ensin kutsutaan sisempänä olevaa metodia lukija.nextLine. Metodilla on paluuarvonaan käyttäjän syöttämä merkkijono. Seuraavaksi kutsutaan metodia Integer.parseInt. Metodikutsun parametrina on merkkijono jonka lukija.nextLine:n kutsu palautti ja metodin paluuarvona on merkkijonoa vastaava kokonaisluku.

Metodin nimeen näyttää liittyvän piste, esim. lukija.nextLine(). Oikeastaan tässä metodin nimi onkin pisteen oikeanpuoleinen osa, eli nextLine(). Pisteen vasemmanpuoleinen osa, eli tässä lukija kertoo kenen metodista on kyse. Eli kyseessä on lukijan metodi nextLine. Opimme hiukan myöhemmin tarkemmin mistä tässä pisteen vasemmanpuoleisessa osassa on kyse. Tarkka lukija tietysti huomaa, että System.out.println():ssa on "kaksi pistettä". Metodin nimi tässä on println, ja System.out on se kenen metodista on kyse. Karkeasti ottaen System.out tarkoittaa koneen näyttöä.

Tähän mennessä käyttämämme metodit ovat kaikki olleet Javan valmiita metodeita. Nyt opettelemme tekemään omia metodeita.

12 Omat metodit

Olemme tähän mennessä ohjelmoineet ohjelmamme siten, että kaikki tapahtuu yhdessä jatkumossa ja koodia luetaan ylhäältä alas.

Edellä mainittiin että "metodi tarkoittaa koodinpätkää, jota voi kutsua muualta ohjelmakoodista". Javan valmiita metodeja on käytetty jo oikeastaan ensimmäisestä ohjelmasta lähtien.

Javan valmiiden metodien käytön lisäksi ohjelmoija voi kirjoittaa itse metodeja joita sovellus kutsuu. Oikeastaan on hyvin poikkeuksellista jos ohjelmassa ei ole yhtään itse kirjoitettua metodia. Tästälähtien lähes jokainen kurssilla tehty ohjelma sisältääkin itsekirjoitettuja metodeja.

Ohjelmarunkoon metodit kirjoitetaan main:in aaltosulkeiden ulkopuolelle mutta kuitenkin "uloimmaisten" aaltosulkeiden sisäpuolelle, joko mainin ylä- tai alapuolelle

import java.util.Scanner;

public class OhjelmaRunko {
    // omia metodeja tänne

    public static void main(String[] args) {
        Scanner lukija = new Scanner(System.in);
        // ohjelmakoodi
    }

    // omia metodeja tai tänne
}

Luodaan metodi tervehdi.

public static void tervehdi() {
    System.out.println("Terveiset metodimaailmasta!");
}

Ja asetetaan se metodeille kuuluvalle paikalle.

import java.util.Scanner;

public class OhjelmaRunko {
    public static void main(String[] args) {
        Scanner lukija = new Scanner(System.in);
        // ohjelmakoodi
    }

    // omat metodit
    public static void tervehdi() {
        System.out.println("Terveiset metodimaailmasta!");
    }
}

Metodin määrittely sisältää kaksi osaa. Metodimäärittelyn ensimmäisellä rivillä on metodin nimi eli tervehdi. Nimen vasemmalla puolella tässä vaiheessa määreet public static void. Metodin nimen sisältävän rivin alla on aaltosulkeilla erotettu koodilohko, jonka sisälle kirjoitetaan metodin koodi, eli ne komennot jotka metodia kutsuttaessa suoritetaan. Metodimme tervehdi ei tee muuta kuin kirjoittaa rivillisen tekstiä ruudulle.

Itsekirjoitetun metodin kutsu on helppoa, kirjoitetaan metodin nimi ja perään sulut ja puolipiste. Seuraavassa main eli pääohjelma kutsuu metodia ensin kerran ja sen jälkeen useita kertoja.

import java.util.Scanner;

public class OhjelmaRunko {
    public static void main(String[] args) {
        Scanner lukija = new Scanner(System.in);

        // ohjelmakoodi
        System.out.println("Kokeillaan pääsemmekö metodimaailmaan:");
        tervehdi();

        System.out.println("Näyttää siltä, kokeillaan vielä:");
        tervehdi(); 
        tervehdi(); 
        tervehdi();
    }

    // omat metodit
    public static void tervehdi() {
        System.out.println("Terveiset metodimaailmasta!");
    }
}

Ohjelman suoritus saa aikaan seuraavan tulosteen:

Kokeillaan pääsemmekö metodimaailmaan:
Terveiset metodimaailmasta!
Näyttää siltä, kokeillaan vielä:
Terveiset metodimaailmasta!
Terveiset metodimaailmasta!
Terveiset metodimaailmasta!

Huomionarvoista tässä on koodin suoritusjärjestys. Koodin suoritus etenee siten, että pääohjelman -- eli main:in -- rivit suoritetaan ylhäältä alas yksi kerrallaan. Koodirivin ollessa metodikutsu, mennään suorittamaan metodin koodirivit, jonka jälkeen palataan kohtaan, josta metodin kutsu tapahtui. Tarkemmin ottaen metodikutsun jälkeiselle riville.

Jos ollaan tarkkoja on pääohjelma eli main itsekin metodi. Kun ohjelma käynnistyy, kutsuu käyttöjärjestelmä main:ia. Metodi main on siis ohjelman käynnistyspiste, jonka ylimmältä riviltä ohjelman suoritus lähtee liikkeelle. Ohjelman suoritus loppuu kun päädytään mainin loppuun.

Jatkossa kun esittelemme metodeja, emme erikseen mainitse että niiden täytyy sijaita omalla paikallaan. Metodia ei esimerkiksi voi määritellä toisen metodin sisällä.

Tee metodi tulostaTeksti, joka tulostaa tekstin "Alussa olivat suo, kuokka ja Java." sekä rivinvaihdon.

public static void main(String[] args) {
    tulostaTeksti();
}

public static void tulostaTeksti() {
    // kirjoita koodia tähän
}

Ohjelman tulostus:

Alussa olivat suo, kuokka ja Java.

Laajenna edellistä ohjelmaa siten, että pääohjelma kysyy käyttäjältä, montako kertaa teksti tulostetaan eli montako kertaa metodia kutsutaan.

public static void main(String[] args) {
    // kysy käyttäjältä, montako kertaa teksti tulostetaan
    // kutsu metodia tulostaTeksti while-komennon avulla useita kertoja
}

public static void tulostaTeksti() {
    // kirjoita koodia tähän
}

Ohjelman tulostus:

Kuinka monta?
7
Alussa olivat suo, kuokka ja Java.
Alussa olivat suo, kuokka ja Java.
Alussa olivat suo, kuokka ja Java.
Alussa olivat suo, kuokka ja Java.
Alussa olivat suo, kuokka ja Java.
Alussa olivat suo, kuokka ja Java.
Alussa olivat suo, kuokka ja Java.

huom: tulosta kehote Kuinka monta? omalle rivilleen!

12.1 Metodin parametrit

Metodista saa huomattavasti monikäyttöisemmän antamalla sille parametreja. Parametrit ovat muuttujia, jotka määritellään metodin ylimmällä rivillä metodin nimen jälkeen olevien sulkujen sisällä. Kun metodia kutsutaan, sen parametreille annetaan arvot kutsuvaiheessa.

Seuraavassa esimerkissä määritellään parametrillinen metodi tervehdi, jolla on String-tyyppinen parametri nimi.

public static void tervehdi(String nimi) {
    System.out.println("Hei " + nimi + ", terveiset metodimaailmasta!");
}

Kutsutaan metodia tervehdi siten, että parametrin nimi arvoksi asetetaan ensimmäisellä kutsulla Matti ja toisella kutsulla Arto.

public static void main(String[] args) {
    tervehdi("Matti");
    tervehdi("Arto");
}
Hei Matti, terveiset metodimaailmasta!
Hei Arto, terveiset metodimaailmasta!

Aivan kuten kutsuttaessa Javan valmista System.out.println()-metodia, voi oman metodin kutsussa parametrina käyttää monimutkaisempaa ilmausta:

public static void main(String[] args) {
    String nimi1 = "Antti";
    String nimi2 = "Mikkola";
    tervehdi( nimi1 + " " + nimi2 );

    int ika = 24;
    tervehdi("Juhana " + ika + " vuotta");
}
Hei Antti Mikkola, terveiset metodimaailmasta!
Hei Juhana 24 vuotta, terveiset metodimaailmasta!

Molemmissa tapauksissa metodilla on edelleen vain 1 parametri. Parametrin arvo lasketaan ennen metodin kutsumista. Ensimmäisessä tapauksessa parametrin arvo saadaan merkkijonokatenaationa nimi1 + " " + nimi2 joka siis on arvoltaan Antti Mikkola ja jälkimmäisessä tapauksessa merkkijonokatenaatiosta "Juhana " + ika + " vuotta".

12.2 Monta parametria

Metodille voidaan määritellä useita parametreja. Tällöin metodin kutsussa parametrit annetaan samassa järjestyksessä.

public static void tervehdi(String nimi, String mistaTerveiset) {
    System.out.println("Hei " + nimi + ", terveiset " + mistaTerveiset);
}
String kuka = "Matti";
String terveiset = "Kyröjoelta";

tervehdi(kuka, terveiset);
tervehdi(kuka, terveiset + " ja Kumpulasta");

Jälkimmäisessä tervehdi-funktion kutsussa toinen parametri muodostetaan katenoimalla muuttujaan terveiset teksti " ja Kumpulasta". Tämä suoritetaan ennen varsinaista funktion suoritusta.

Hei Matti, terveiset Kyröjoelta
Hei Matti, terveiset Kyröjoelta ja Kumpulasta  

12.3 Metodi kutsuu toista metodia

main ei ole suinkaan ainoa joka voi kutsua metodeita. Metodit voivat kutsua myös toisiaan. Tehdään metodi tervehdiMontaKertaa, joka tervehtii käyttäjää useasti metodin tervehdi avulla:

public static void tervehdi(String nimi) {
    System.out.println("Hei " + nimi + ", terveiset metodimaailmasta!");
}

public static void tervehdiMontaKertaa(String nimi, int kerrat) {
    int i = 0;
    while ( i < kerrat ) {
        tervehdi(nimi);
        i++;
    }

}

public static void main(String[] args) {
    tervehdiMontaKertaa("Antti", 3);
    System.out.println("ja");
    tervehdiMontaKertaa("Martin", 2);
}

Tulostuu:

Hei Antti, terveiset metodimaailmasta!
Hei Antti, terveiset metodimaailmasta!
Hei Antti, terveiset metodimaailmasta!
ja
Hei Martin, terveiset metodimaailmasta!
Hei Martin, terveiset metodimaailmasta!

Screencast aiheesta:

39.1 Tähtien tulostus

Tee metodi tulostaTahtia, joka tulostaa annetun määrän tähtiä ja rivinvaihdon.

Tee metodi seuraavaan runkoon:

private static void tulostaTahtia(int maara) {
    // yhden tähden saat tulostettua komennolla
    // System.out.print("*");
    // kutsu tulostuskomentoa n kertaa
    // tulosta lopuksi rivinvaihto komennolla
    // System.out.println("");
}

public static void main(String[] args) {
    tulostaTahtia(5);
    tulostaTahtia(3);
    tulostaTahtia(9);
}

Ohjelman tulostus:

*****
***
*********

huom: moniosaisen tehtävät voi palauttaa palvelimelle (painamalla testausnapin oikealla puolella olevaa nappia) vaikka kaikki osat eivät olisikaan tehty. Palvelin valittelee tällöin tekemättömien osien testeistä, tehdyt osat palvelin kirjaa.

39.2 Neliön tulostus

Tee metodi tulostaNelio(int sivunpituus) joka tulostaa neliön käyttäen tulostaTahtia-metodia. Siis esimerkiksi kutsu tulostaNelio(4) tulostaa seuraavaa:

****
****
****
****

Huom: tehtävässä ei riitä että tulostus näyttää oikealta, tulostaNelio-metodin sisällä neliön "rivien" tulostus tulee tehdä tulostaTahtia-metodia käyttäen.

Ohjelmaa tehdessäsi kannattaa varmistaa main:iin kirjoitetun testikoodin avulla että metodit toimivat vaaditulla tavalla.

39.3 Suorakulmion tulostus

Tee metodi tulostaSuorakulmio(int leveys, int korkeus) joka tulostaa suorakulmion käyttäen tulostaTahtia-metodia. Siis esimerkiksi kutsu tulostaSuorakulmio(17,3) tulostaa seuraavaa:

*****************
*****************
*****************

39.4 Vasemmalle nojaavan kolmion tulostus

Tee metodi tulostaKolmio(int koko) joka tulostaa kolmion käyttäen tulostaTahtia-metodia. Siis esimerkiksi kutsu tulostaKolmio(4) tulostaa seuraavaa:

*
**
***
****

40.1 Tähtirivin ja tyhjien tulostus

Tee metodi tulostaTyhjaa(int maara) joka tulostaa maara kappaletta välilyöntejä. Metodi ei tulosta rivinvaihtoa.

Joudut myös joko kopioimaan edellisen tehtävän vastauksestasi metodin tulostaTahtia tai toteuttamaan sen uudelleen tämän tehtävän tehtäväpohjaan.

40.2 Oikealle nojaavan kolmion tulostus

Tee metodi tulostaKolmio(int koko) joka tulostaa kolmion käyttäen tulostaTyhjaa- ja tulostaTahtia-metodeja. Siis esimerkiksi kutsu tulostaKolmio(4) tulostaa seuraavaa:

   *
  **
 ***
****

40.3 Joulukuusen tulostus

Tee metodi jouluKuusi(int korkeus) joka tulostaa joulukuusen. Joulukuusi koostuu annetun korkuisesta kolmiosta ja jalasta. Jalka on kaksi tähteä korkea ja kolme tähteä leveä ja se on keskellä kolmion pohjaa. Kuusi tulee rakentaa käyttämällä tulostukseen metodeja tulostaTyhjaa ja tulostaTahtia

Esimerkiksi kutsu jouluKuusi(4) tulostaa seuraavaa:

   *
  ***
 *****
*******
  ***
  ***

Kutsu jouluKuusi(10) tulostaa:

         *
        ***
       *****
      *******
     *********
    ***********
   *************
  ***************
 *****************
*******************
        ***
        ***

Huom: Korkeuksien jotka ovat alle 3 ei tarvitse toimia!

Tässä tehtävässä luodaan seuraavanlainen numerovisa:

Arvaa luku: 73
Luku on pienempi, tehtyjä arvauksia: 1
Arvaa luku: 22
Luku on suurempi, tehtyjä arvauksia: 2
Arvaa luku: 51
Luku on suurempi, tehtyjä arvauksia: 3
Arvaa luku: 62
Luku on suurempi, tehtyjä arvauksia: 4
Arvaa luku: 68
Luku on suurempi, tehtyjä arvauksia: 5
Arvaa luku: 71
Luku on pienempi, tehtyjä arvauksia: 6
Arvaa luku: 70
Onneksi olkoon, oikein arvattu!

41.1 Numeron arvaaminen

Tehtävänannon mukana tulevassa ohjelmassa tulee mukana komento arvoLuku, joka arpoo luvun suljetulta väliltä [0, 100] (0 ja 100 ovat myös mahdollisia). Toteuta ohjelma jossa arvataan arvottua lukua kerran. Ohjelman tulee tulostaa joko "Luku on pienempi", "Luku on suurempi" tai "Onneksi olkoon, oikein arvattu!" riippuen käyttäjän antamasta luvusta.

Arvaa luku: 12
Luku on suurempi
Arvaa luku: 66
Luku on pienempi
Arvaa luku: 42
Onneksi olkoon, oikein arvattu!

41.2 Toistuva arvaaminen

Lisää ohjelmaan toiminnallisuus jossa arvausta tehdään toistuvasti kunnes käyttäjä syöttää oikean numeron. Huomaa, että sinun tulee arpoa numero komentoa arvoLuku ennen toistolauseketta. Miksi? Mitä tapahtuu, jos luku arvotaan toistolausekkeen sisällä?

Alla olevassa esimerkissä kutsu komentoon arvoLuku palautti arvon 83.

Arvaa luku: 55
Luku on suurempi
Arvaa luku: 85
Luku on pienempi
Arvaa luku: 77
Luku on suurempi
Arvaa luku: 81
Luku on suurempi
Arvaa luku: 83
Onneksi olkoon, oikein arvattu!

41.3 Arvauskertojen laskeminen

Lisää ohjelmaan kokonaislukutyyppinen muuttuja, jonka avulla pidetään kirjaa tehtyjen arvausten määrästä. Tulosta arvausten määrä aina arvauksen yhteydessä.

Arvaa luku: 55
Luku on suurempi, tehtyjä arvauksia: 1
Arvaa luku: 85
Luku on pienempi, tehtyjä arvauksia: 2
Arvaa luku: 77
Luku on suurempi, tehtyjä arvauksia: 3
Arvaa luku: 81
Luku on suurempi, tehtyjä arvauksia: 4
Arvaa luku: 83
Onneksi olkoon, oikein arvattu!

Kaverisi ohjelmoi käyttöösi Hirsipuu-pelin, jolta puuttuu vielä käyttöliittymätoiminnallisuus. Hirsipuulla on seuraavat metodit:

  • hirsipuu.peliKaynnissa()
    Kertoo onko peli käynnissä.
  • hirsipuu.tulostaTilanne()
    Tulostaa pelin tilanteen. Kertoo tehtyjen arvausten määrän ja käyttämättömät kirjaimet.
  • hirsipuu.tulostaSana()
    Tulostaa arvattavan sanan. Pelin aikana arvaamattomat kirjaimet on piilotettu kysymysmerkein, esimerkiksi "muu??uja".
  • hirsipuu.tulostaUkko()
    Piirtää hirsipuun.
  • hirsipuu.arvaa(String kirjain)
    Arvaa onko sanassa parametrina annettava kirjain.

Käytössäsi on palautusautomaatista tuleva ohjelmarunko, jossa on jo hieman toiminnallisuutta:

Scanner lukija = new Scanner(System.in);
Hirsipuu hirsipuu = new Hirsipuu();

System.out.println("************");
System.out.println("* HIRSIPUU *");
System.out.println("************");
System.out.println("");
tulostaValikko();
System.out.println("");

// OHJELMOI TOTEUTUKSESI TÄNNE

System.out.println("Kiitos pelistä!");

Rungon lisäksi käytössäsi on metodi tulostaValikko:

public static void tulostaValikko() {
    System.out.println(" * valikko *");
    System.out.println("lopeta   - lopettaa pelin");
    System.out.println("tilanne  - tulostaa tarkemman tilanteen");
    System.out.println("yksittäinen kirjain arvaa annettua kirjainta");
    System.out.println("tyhjä rivi tulostaa tämän valikon");
}

Tehtävä toteutetaan pienissä osissa.

42.1 Toistolauseke ja siitä poistuminen

Luo ohjelmaan toistolauseke, joka toimii käyttöliittymän pohjana. Lue toistolausekkeen sisällä käyttäjältä komento. Jos komento on "lopeta", poistu toistolauseesta.

Käytä whilen ehtona komentoa hirsipuu.peliKaynnissa(), eli toisto on muotoa:

while (hirsipuu.peliKaynnissa()) {
  String komento = lukija.nextLine();
  // ...
}

Ensi viikolla ymmärrämme mistä tässä hieman erikoiselta näyttävässä toiston lopetusehdossa on tarkkaan ottaen kysymys.

Tässä vaiheessa ohjelman tulisi toimia seuraavasti:

************
* HIRSIPUU *
************

* valikko *
lopeta   - lopettaa pelin
tilanne  - tulostaa tarkemman tilanteen
yksittäinen kirjain arvaa annettua kirjainta
tyhjä rivi tulostaa tämän valikon 

Anna komento: 
ei lopeta

Anna komento: 
lopeta
Kiitos pelistä!

42.2 Tilanteen näyttäminen

Jos käyttäjä syöttää merkkijonon "tilanne", tulosta tilanne metodin hirsipuu.tulostaTilanne() avulla.

************
* HIRSIPUU *
************

* valikko *
lopeta   - lopettaa pelin
tilanne  - tulostaa tarkemman tilanteen
yksittäinen kirjain arvaa annettua kirjainta
tyhjä rivi tulostaa tämän valikon

Anna komento: 
tilanne
Et ole vielä tehnyt yhtään arvausta.
Käyttämättömät kirjaimet: abcdefghijklmnopqrstuvwxyzåäö

Anna komento: 
lopeta
Kiitos pelistä!

42.3 Arvauksen tekeminen

Jos käyttäjä kirjoittaa komentona yhden merkin pituisen merkkijonon, eli yksittäisen kirjaimen, käytä syötettä arvaamiseen. Arvaaminen tapahtuu metodilla hirsipuu.arvaa(komento). Arvauskomennolla on oma tulostustoiminnallisuus, jolla se tulostaa lisätietoa arvauksen onnistumisesta.

Vihje: komennon toteaminen yksittäiseksi kirjaimeksi onnistuu seuraavasti:

String komento = lukija.nextLine();

if(komento.length() == 1) {  // komento on vain yksi kirjain, eli kyseessä on arvaus
    hirsipuu.arvaa(komento);
} 
...
Anna komento: 
a
Kirjainta a ei löytynyt sanasta.

Anna komento: 
b
Kirjainta b ei löytynyt sanasta.

Anna komento: 
c
Kirjain c löytyi sanasta!

Anna komento: 
lopeta
Kiitos pelistä!

42.4 Valikon tulostaminen

Jos käyttäjä syöttää tyhjän merkkijonon, eli merkkijonon jonka pituus on nolla, kutsu metodia tulostaValikko. Huomaa, että metodi tulostaValikko ei liity Hirsipuu-peliin, vaan omaan ohjelmaasi.

Vihje: merkkijonon tyhjyyden tarkastaminen onnistuu seuraavasti:

String nalle = "puh";
if(nalle.isEmpty()) {
    System.out.println("Tyhjä merkkijono");
} else {
    System.out.println("Löytyipäs sieltä jotain!");
}

42.5 Pelitilanteen tulostaminen

Jos käyttäjä ei ole syöttänyt komentoa lopeta, kutsu toistolausekkeen lopussa hirsipuupelin komentoja hirsipuu.tulostaUkko() ja hirsipuu.tulostaSana().

...
Anna komento: 
a
Kirjainta a ei löytynyt sanasta.
____
|   
|   
|   
|   
/|\
Arvattava sana: ????

Anna komento: 
m
Kirjain m löytyi sanasta!
____
|   
|   
|   
|   
/|\
Arvattava sana: m???

Anna komento: 
lopeta
Kiitos pelistä!