Ohjelman pilkkominen osiin: metodit
Olemme käyttäneet useita erilaisia komentoja Javassa: sijoitusta, laskutoimituksia, vertailuja, if:iä ja whileä. Ruudulle tulostaminen on tehty System.out.println()
-lauseella ja lukeminen Integer.valueOf(lukija.nextLine())
lauseella.
Huomaamme, että tulostaminen ja lukeminen poikkeaa if
:istä ja while
:stä ym. siinä, että komennon perässä on sulut ja joskus sulkujen sisällä komennolle annettava parametrit. "Sulkuihin päättyvät" eivät oikeastaan olekaan komentoja vaan metodeja.
Teknisesti ottaen metodi tarkoittaa nimettyä lauseista koostuvaa joukkoa, eli ohjelman palaa, jota voi kutsua muualta ohjelmakoodista metodille annetun nimen perusteella. Koodirivi System.out.println("olen metodille annettava parametri!")
siis tarkoittaa, että kutsutaan metodia, joka suorittaa ruudulle tulostamisen. Metodin sisäinen toteutus — eli joukko suoritettavia lauseita — on tässä tapauksessa java-ohjelmointikielen piilottama.
Parametrin lisäksi metodilla voi olla paluuarvo. Esim. tuttu lause:
String merkkijono = lukija.nextLine();
lukija.nextLine()
. Usein metodin nimeen näyttää liittyvän piste, kuten yllä olevassa lauseessa. Oikeastaan tässäkin metodin nimi on pisteen oikeanpuoleinen osa, eli nextLine()
. Pisteen vasemmanpuoleinen osa, eli tässä lukija
, kertoo kenen metodista on kyse. Kyseessä on lukijan tarjoama 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öä.Vastaavasti lauseessa:
int luku = Integer.valueOf(lukija.nextLine());
on kaksi metodikutsua. Ensin kutsutaan sisempänä olevaa metodia lukija.nextLine()
, joka palauttaa merkkijonon. Seuraavaksi kutsutaan metodia Integer.valueOf(...)
. Metodikutsun Integer.valueOf(...)
parametriksi asetetaan se merkkijono, jonka metodin lukija.nextLine()
kutsu palautti. Metodin Integer.valueOf(...)
paluuarvona on merkkijonoa vastaava kokonaisluku.
Tähän mennessä käyttämämme metodit ovat kaikki olleet Javan valmiita metodeita. Opetellaan seuraavaksi tekemään omia metodeita.
Omat metodit
Edellä mainittiin että metodi tarkoittaa nimettyä lauseista koostuvaa joukkoa, jota voi kutsua muualta ohjelmakoodista nimen perusteella. Javan valmiita metodeja on käytetty 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 Esimerkki {
public static void main(String[] args) {
Scanner lukija = new Scanner(System.in);
// ohjelmakoodi
}
// omia metodeja tänne
}
Tarkastellaan uuden metodin luomista. Luodaan metodi tervehdi
.
public static void tervehdi() {
System.out.println("Terveiset metodimaailmasta!");
}
Ja asetetaan se metodeille kuuluvalle paikalle.
import java.util.Scanner;
public class Esimerkki {
public static void main(String[] args) {
Scanner lukija = new Scanner(System.in);
// ohjelmakoodi
}
// omia metodeja tänne
public static void tervehdi() {
System.out.println("Terveiset metodimaailmasta!");
}
}
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 tervehdi-metodia yhteensä neljä kertaa.
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 ohjelman suoritusjärjestys. Ohjelman suoritus etenee siten, että pääohjelman — eli main:in — rivit suoritetaan ylhäältä alas yksi kerrallaan. Kun lause on metodikutsu, ohjelman suoritus siirtyy metodiin. Metodin lauseet suoritetaan yksi kerrallaan ylhäältä alas. Tämän jälkeen palataan kohtaan, josta metodin kutsu tapahtui. Tarkemmin ottaen metodikutsun jälkeiselle riville.
Jos ollaan tarkkoja niin pääohjelma eli main on 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ä.
Metodien nimennästä
Metodit nimetään siten, että ensimmäinen sana kirjoitetaan pienellä ja loput alkavat isolla alkukirjaimella, tälläisestä kirjoitustavasta käytetään nimitystä camelCase. Tämän lisäksi, metodin sisällä koodi on sisennetty taas neljä merkkiä.
Alla olevassa esimerkissä metodi on nimetty väärin. Nimi alkaa isolla alkukirjaimella ja metodin nimen osat on eroteltu toisistaan merkillä _. Metodin sulut ovat myös erillään toisistaan ja sisennys on väärin.
public static void Tama_metodi_sanoo_mur ( ) {
System.out.println("mur");
}
Alla taas metodi on nimetty oikein. Nimi alkaa pienellä alkukirjaimella ja nimen osat on yhdistetty toisiinsa camelCase-tyylillä, missä jokainen uusi sana alkaa isolla kirjaimella. Sulut ovat kiinni metodissa ja toisissaan, jonka lisäksi metodin sisältö on sisennetty oikein.
public static void tamaMetodiSanooMur() {
System.out.println("mur");
}
Metodin muuttujat
Muuttujien määrittely metodissa tapahtuu tutulla tavalla. Seuraava metodi laskee parametrina saamiensa lukujen keskiarvon. Keskiarvon laskemisessa käytetään apumuuttujia summa
ja ka
.
public static double keskiarvo(int luku1, int luku2, int luku3) {
int summa = luku1 + luku2 + luku3;
double ka = summa / 3.0;
return ka;
}
Metodin kutsu voi tapahtua esim seuraavasti
public static void main(String[] args) {
Scanner lukija = new Scanner(System.in);
System.out.print("Anna ensimmäinen luku: ");
int eka = Integer.valueOf(lukija.nextLine());
System.out.print("Anna toinen luku: ");
int toka = Integer.valueOf(lukija.nextLine());
System.out.print("Anna kolmas luku: ");
int kolmas = Integer.valueOf(lukija.nextLine());
double keskiarvonTulos = keskiarvo(eka, toka, kolmas);
System.out.print("Lukujen keskiarvo: " + keskiarvonTulos);
}
Huomaa että metodin sisäiset muuttujat summa
ja ka
eivät näy pääohjelmaan. Tyypillinen ohjelmoinnin harjoittelussa eteen tuleva virhe on yrittää käyttää metodia seuraavasti.
public static void main(String[] args) {
int eka = 3;
int toka = 8;
int kolmas = 4;
keskiarvo(eka, toka, kolmas);
// yritetään käyttää metodin sisäistä muuttujaa, EI TOIMI!
System.out.print("Lukujen keskiarvo: " + ka);
}
Yllä yritetään käyttää metodin keskiarvo
sisällä määriteltyä muuttujaa ka
ja tulostaa sen arvo. Muuttuja ka
on kuitenkin olemassa vain metodin keskiarvo
sisällä, eikä siihen pääse käsiksi ulkopuolelta.
Myös seuraavanlaista virhettä näkee usein.
public static void main(String[] args) {
int eka = 3;
int toka = 8;
int kolmas = 4;
// yritetään käyttää pelkkää metodin nimeä, EI TOIMI!
System.out.print("Lukujen keskiarvo: " + keskiarvo);
}
Yllä yritetään käyttää metodin keskiarvo
nimeä muuttujamaisesti. Metodia tulee kuitenkin kutsua.
Toimiva tapa metodin tuloksen sijoittamisen apumuuttujaan lisäksi on suorittaa metodikutsu suoraan tulostuslauseen sisällä:
public static void main(String[] args) {
int eka = 3;
int toka = 8;
int kolmas = 4;
// kutsutaan metodia tulostuslauseessa, TOIMII!
System.out.print("Lukujen keskiarvo: " + keskiarvo(eka, toka, kolmas));
}
Tässä siis ensin tapahtuu metodikutsu joka palauttaa arvon 5.0 joka sitten tulostetaan tulostuskomennon avulla.
Muuttuja ei ole olemassa ennen sen esittelyä, ja muuttuja on olemassa vain niiden aaltosulkujen sisällä kuin missä se on esitelty. Metodien yhteydessä tämä tarkoittaa sitä, että metodeilla on pääsy vain niihin muuttujiin, jotka ovat määritelty metodien sisällä, tai jotka metodi saa parametrina. Alla oleva esimerkki konkretisoi tilanteen, missä kasvataKolme
-metodin sisällä yritetään muuttaa main
-metodissa määritellyn luku
-muuttujan arvoa.
// pääohjelma
public static void main(String[] args) {
int luku = 1;
kasvataKolmella();
}
// metodi
public static void kasvataKolmella() {
luku = luku + 3;
}
Yllä oleva ohjelma ei toimi, sillä metodi kasvataKolmella
ei näe pääohjelman muuttujaa luku
. Tarkemmin ottaen, metodi kasvataKolmella
ei edes tiedä mistä muuttujasta luku
on kyse, sillä muuttujaa ei ole määritelty metodissa kasvataKolmella
tai sen parametreissa.
Yleisemmin voi todeta, että pääohjelman muuttujat eivät näy metodien sisälle, ja metodin muuttujat eivät näy muille metodeille tai pääohjelmalle. Ainoa keino viedä metodille tietoa metodin ulkopuolelta on parametrin avulla.
Metodin parametrit
Parametrit ovat metodille annettavia arvoja, joita käytetään metodin suorituksessa. Metodin parametrit 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 int-tyyppinen parametri montakoKertaa
.
public static void tervehdi(int montakoKertaa) {
int i = 0;
while (i < montakoKertaa) {
System.out.println("Tervehdys!");
i++;
}
}
Kutsutaan metodia tervehdi
siten, että parametrin montakoKertaa
arvoksi asetetaan ensimmäisellä kutsulla 1
ja toisella kutsulla 3
.
public static void main(String[] args) {
tervehdi(1);
tervehdi(3);
}
Tervehdys! Tervehdys! Tervehdys! Tervehdys!
Aivan kuten Javan valmista System.out.println()
-metodia kutsuttaessa, voi oman metodin kutsussa parametrina antaa lausekkeen.
public static void main(String[] args) {
tervehdi(1 + 2);
}
Tervehdys! Tervehdys! Tervehdys!
Jos metodia kutsuttaessa parametriksi määritellään lauseke, evaluoidaan lauseke ennen metodikutsua. Yllä metodikutsun parametri evaluoituu arvoksi 3
ja lopullinen metodikutsu on muotoa tervehdi(3);
.
Metodille voidaan määritellä useita parametreja. Tällöin metodin kutsussa parametrit annetaan samassa järjestyksessä.
public static void summa(int eka, int toka) {
System.out.println("Lukujen " + eka + " ja " + toka + " summa on " + (eka + toka));
}
summa(3, 5);
int luku1 = 2;
int luku2 = 4;
summa(luku1, luku2);
Lukujen 3 ja 5 summa on 8 Lukujen 2 ja 4 summa on 6
Metodikutsun yhteydessä parametrien arvot kopioituvat. Tämä tarkoittaa käytännössä sitä, että sekä main-metodissa että kutsuttavassa metodissa voi olla saman nimiset muuttujat, mutta muuttujien arvon muuttaminen kutsuttavan metodin sisällä ei muuta main-metodissa olevan muuttujan arvoa. Tarkastellaan tätä seuraavan ohjelman avulla.
public class Esimerkki {
public static void main(String[] args) {
int mista = 5;
int mihin = 10;
tulostaLuvut(mista, mihin);
mista = 8;
tulostaLuvut(mista, mihin);
}
public static void tulostaLuvut(int mista, int mihin) {
while (mista < mihin) {
System.out.println(mista);
mista++;
}
}
}
Ohjelman tulostus on seuraava:
5 6 7 8 9 8 9
Alla sama askeleittaisena visualisaationa. Huomaat että main-metodissa olevat arvot jäävät kutsupinoon odottamaan metodin tulostaLuvut suorittamista. Metodissa tulostaLuvut olevien muuttujien arvojen muuttaminen ei muuta metodin main muuttujien arvoja, vaikka ne ovatkin saman nimisiä.
Metodien parametrit ovat siis erillisiä muiden metodien muuttujista (tai parametreista), vaikka niillä olisikin sama nimi. Kun metodikutsun yhteydessä metodille annetaan muuttuja, muuttujan arvo kopioituu kutsuttavan metodin metodimäärittelyssä olevan parametrimuuttujan arvoksi. Kahdessa eri metodissa olevat muuttujat ovat erillisiä toisistaan.
Tarkastellaan vielä seuraavaa esimerkkiä, missä pääohjelmassa määritellään muuttuja luku
. Muuttuja luku annetaan parametrina metodille kasvataKolmella
.
// pääohjelma
public static void main(String[] args) {
int luku = 1;
System.out.println("Pääohjelman muuttujan luku arvo: " + luku);
kasvataKolmella(luku);
System.out.println("Pääohjelman muuttujan luku arvo: " + luku);
}
// metodi
public static void kasvataKolmella(int luku) {
System.out.println("Metodin parametrin luku arvo: " + luku);
luku = luku + 3;
System.out.println("Metodin parametrin luku arvo: " + luku);
}
Ohjelman suoritus aiheuttaa seuraavanlaisen tulostuksen.
Pääohjelman muuttujan luku arvo: 1 Metodin parametrin luku arvo: 1 Metodin parametrin luku arvo: 4 Pääohjelman muuttujan luku arvo: 1
Kun metodin sisällä kasvatetaan muuttujan luku
arvoa kolmella, se onnistuu. Tämä ei kuitenkaan näy pääohjelmassa olevassa muuttujassa luku
. Pääohjelmassa oleva muuttuja luku
on eri kuin metodissa oleva muuttuja luku
.
Parametri luku
kopioidaan metodin käyttöön, eli metodia kasvataKolmella
varten luodaan oma muuttuja nimeltä luku
, johon pääohjelmassa olevan muuttujan luku
arvo kopioidaan metodikutsun yhteydessä. Metodissa kasvataKolmella
oleva muuttuja luku
on olemassa vain metodin suorituksen ajan, eikä sillä ole yhteyttä pääohjelman samannimiseen muuttujaan.
Metodi voi palauttaa arvon
Metodin määrittelyssä kerrotaan palauttaako metodi arvon. Jos metodi palauttaa arvon, tulee metodimäärittelyn yhteydessä kertoa palautettavan arvon tyyppi. Muulloin määrittelyssä käytetään avainsanaa void
. Tähän mennessä tekemämme metodit ovat määritelty avainsanaa void
käyttäen eli eivät ole palauttaneet arvoa.
public static **void** kasvataKolmella() {
...
}
Avainsana void
tarkoittaa että metodi ei palauta mitään. Jos haluamme, että metodi palauttaa arvon, tulee avainsanan void
paikalle asettaa palautettavan muuttujan tyyppi. Seuraavassa esimerkissä on määritelty metodi palautetaanAinaKymppi
, joka palauttaa kokonaislukutyyppisen (int
) muuttujan (tässä arvon 10).
Konkreettinen arvon palautus tapahtuu komennolla return
, jota seuraa palautettava arvo (tai muuttujan nimi, jonka arvo palautetaan).
public static int palautetaanAinaKymppi() {
return 10;
}
Yllä määritelty metodi palauttaa sitä kutsuttaessa int
-tyyppisen arvon 10
. Jotta metodin palauttamaa arvoa voisi käyttää, tulee se ottaa talteen muuttujaan. Tämä tapahtuu samalla tavalla kuin normaali muuttujan arvon asetus, eli yhtäsuuruusmerkillä.
public static void main(String[] args) {
int luku = palautetaanAinaKymppi();
System.out.println("metodi palautti luvun " + luku);
}
Metodin paluuarvo sijoitetaan int
-tyyppiseen muuttujaan aivan kuin mikä tahansa muukin int-arvo. Paluuarvo voi toimia myös osana mitä tahansa lauseketta.
double luku = 4 * palautetaanAinaKymppi() + (palautetaanAinaKymppi() / 2) - 8;
System.out.println("laskutoimituksen tulos " + luku);
Kaikki tähän mennessä näkemämme muuttujatyypit voidaan palauttaa metodista.
Palautettavan arvon tyyppi | Esimerkki |
---|---|
Metodi ei palauta arvoa | ```java public static void metodiJokaEiPalautaMitaan() { // metodin runko }``` |
Metodi palauttaa `int`-tyyppisen muuttujan | ```java public static int metodiJokaPalauttaaKokonaisLuvun() { // metodin runko, tarvitsee return-komennon }``` |
Metodi palauttaa `double`-tyyppisen muuttujan | ```java public static double metodiJokaPalauttaaLiukuluvun() { // metodin runko, tarvitsee return-komennon }``` |
Jos metodille määritellään paluuarvon tyyppi, on sen pakko palauttaa arvo. Esimerkiksi seuraava metodi on virheellinen.
public static int virheellinenMetodi() {
System.out.println("Väitän palauttavani kokonaisluvun, mutten palauta sitä.");
}
Ylläolevassa metodissa tulee olla komento return
, jota seuraa palautettavan arvon tyyppi.
Palautettavan arvon ei tarvitse olla täysin ennalta määritelty, vaan se voidaan laskea. Metodista arvon palauttavalle return-komennolle voidaan antaa myös lauseke, joka evaluoituu ennen kuin arvo palautetaan.
Seuraavassa esimerkissä määritellään metodi summa, joka laskee kahden muuttujan arvon yhteen ja palauttaa summan. Yhteen laskettavien muuttujien eka
ja toka
arvot saadaan metodin parametrina.
public static int summa(int eka, int toka) {
return eka + toka;
}
Kun metodin suorituksessa päädytään lauseeseen return eka + toka;
, evaluoidaan lauseke eka + toka
, jonka arvo lopulta palautetaan.
Metodin kutsutaan seuraavasti. Alla metodia käytetään laskemaan luvut 2 ja 7 yhteen. Metodikutsusta saatava paluuarvo asetetaan muuttujaan lukujenSumma
:
int lukujenSumma = summa(2, 7);
// lukujenSumma on nyt 9
Laajennetaan edellistä esimerkkiä siten, että käyttäjä syöttää luvut.
public static void main(String[] args) {
Scanner lukija = new Scanner(System.in);
System.out.print("Anna ensimmäinen luku: ");
int eka = Integer.valueOf(lukija.nextLine());
System.out.print("Anna toinen luku: ");
int toka = Integer.valueOf(lukija.nextLine());
System.out.print("Luvut ovat yhteensä: " + summa(eka, toka));
}
public static int summa(int eka, int toka) {
return eka + toka;
}
Yllä olevassa esimerkissä metodin paluuarvoa ei aseteta muuttujaan, vaan sitä käytetään suoraan osana tulostusta. Tällöin tulostuskomennon suoritus tapahtuu siten, että tietokone selvittää ensin tulostettavan merkkijonon "Luvut ovat yhteensä: " + summa(eka, toka)
. Ensin tietokone etsii muuttujat eka
ja toka
, ja kopioi niiden arvot metodin summa
parametrien arvoiksi. Tämän jälkeen metodissa lasketaan parametrien arvot yhteen, jonka jälkeen summa palauttaa arvon. Tämä arvo asetetaan metodikutsun summa
paikalle, jonka jälkeen summa liitetään merkkijonon "Luvut ovat yhteensä: "
jatkeeksi.
Koska metodille annettavat arvot kopioidaan metodin parametreihin, metodin parametrien nimillä ja metodin kutsujan puolella määritellyillä muuttujien nimillä ei ole oikeastaan mitään tekemistä keskenään. Edellisessä esimerkissä sekä pääohjelman muuttujat että metodin parametrit olivat "sattumalta" nimetty samoin (eli eka
ja toka
). Seuraava toimii täysin samalla tavalla vaikka muuttujat ovatkin eri nimisiä:
public static void main(String[] args) {
Scanner lukija = new Scanner(System.in);
System.out.print("Anna ensimmäinen luku: ");
int luku1 = Integer.valueOf(lukija.nextLine());
System.out.print("Anna toinen luku: ");
int luku2 = Integer.valueOf(lukija.nextLine());
System.out.print("Luvut ovat yhteensä: " + summa(luku1, luku2));
}
public static int summa(int eka, int toka) {
return eka + toka;
}
Nyt pääohjelman muuttujan luku1
arvo kopioituu metodin parametrin eka
arvoksi ja pääohjelman muuttujan luku2
arvo kopioituu metodin parametrin toka
arvoksi.
Metodikutsujen suoritus ja kutsupino
Mistä tietokone tietää minne metodin suorituksen jälkeen tulee palata?
Java-lähdekoodin suoritusympäristö pitää kirjaa suoritettavasta metodista kutsupinossa. Kutsupino sisältää kehyksiä, joista jokainen sisältää tiedon kyseisen metodin sisäisistä muuttujista sekä niiden arvoista. Kun metodia kutsutaan, kutsupinoon luodaan uusi kehys, joka sisältää metodin sisältämät muuttujat. Kun metodin suoritus loppuu, metodiin liittyvä kehys poistetaan kutsupinosta, jolloin suoritusta jatketaan kutsupinon edeltävästä metodista.
Alla olevan visualisaation oikealla laidalla näytetään kutsupinon toimintaa. Metodikutsun yhteydessä kutsupinoon luodaan uusi kehys, joka poistetaan metodikutsusta poistuttaessa.
Kun metodia kutsutaan, kutsuvan metodin suoritus jää odottamaan kutsutun metodin suorittamista. Tätä voidaan visualisoida kutsupinon avulla. Kutsupino tarkoittaa metodien kutsumisen muodostamaa pinoa — juuri suoritettevana oleva metodi on aina pinon päällimmäisenä, ja metodin suorituksen päättyessä palataan pinossa seuraavana olevaan metodiin. Tarkastellaan seuraavaa ohjelmaa:
public static void main(String[] args) {
System.out.println("Hei maailma!");
tulostaLuku();
System.out.println("Hei hei maailma!");
}
public static void tulostaLuku() {
System.out.println("Luku");
}
Kun ohjelma käynnistetään, suoritus alkaa main
-metodin ensimmäiseltä riviltä. Tällä rivillä olevalla komennolla tulostetaan teksti "Heippa maailma!"
. Ohjelman kutsupino näyttää seuraavalta:
main
Kun tulostuskomento on suoritettu, siirrytään seuraavaan komentoon, missä kutsutaan metodiatulostaLuku
. Metodin tulostaLuku
kutsuminen siirtää ohjelman suorituksen metodin tulostaLuku
alkuun, jolloin main
-metodi jää odottamaan metodin tulostaLuku
suorituksen loppumista. Metodin tulostaLuku
sisällä ollessa kutsupino näyttää seuraavalta.
tulostaLuku main
Kun metodi tulostaLuku
on suoritettu, palataan kutsupinossa metodia tulostaLuku
yhtä alempana olevaan metodiin, eli metodiin main
. Kutsupinosta poistetaan tulostaLuku
, ja jatketaan main
-metodin suoritusta tulostaLuku
-metodikutsun jälkeiseltä riviltä. Kutsupino on nyt seuraavanlainen:
main
Kutsupino ja metodin parametrit
Tarkastellaan kutsupinoa tilanteessa, missä metodille on määritelty parametreja.
public static void main(String[] args) {
int alku = 1;
int loppu = 5;
tulostaTahtia(alku, loppu);
}
public static void tulostaTahtia(int alku, int loppu) {
while (alku < loppu) {
System.out.print("*");
alku++; // sama kuin alku = alku + 1
}
}
Ohjelman suoritus alkaa main
-metodin ensimmäiseltä riviltä, jota seuraavilla riveillä luodaan muuttujat alku
ja loppu
, sekä asetetaan niihin arvot. Ohjelman tilanne ennen metodin tulostaTahtia
-kutsumista:
Kun metodia tulostaTahtia
kutsutaan, main
-metodi jää odottamaan. Metodikutsun yhteydessä metodille tulostaTahtia
luodaan uudet muuttujat alku
ja loppu
, joihin asetetaan parametreina annetut arvot. Nämä kopioidaan main
-metodin muuttujista alku
ja loppu
. Metodin tulostaTahtia
suorituksen ensimmäisellä rivillä ohjelman tilanne on seuraavanlainen.
Kun toistolauseessa suoritetaan komento alku++
, muuttuu tällä hetkellä suoritettavaan metodiin liittyvän alku
-muuttujan arvo.
Metodin main
muuttujien arvot eivät siis muutu. Metodin tulostaTahtia
suoritus jatkuisi tämän jälkeen jokusen hetken. Kun metodin tulostaTahtia
suoritus loppuu, palataan takaisin main
-metodin suoritukseen.
Tarkastellaan samaa ohjelman suorituksen askeleittaisella visualisoinnilla. Visualisointiin käyttämämme sovellus kasvattaa kutsupinoa alaspäin — oikealla laidalla ylin on aina main-metodi, jonka alle tulee kutsuttavat metodit.
Kutsupino ja arvon palauttaminen metodista
Tarkastellaan seuraavaksi esimerkkiä, missä metodi palauttaa arvon. Ohjelman main
-metodi kutsuu erillistä kaynnista
-metodia, jossa luodaan kaksi muuttujaa, kutsutaan summa
-metodia, ja tulostetaan summa
-metodin palauttama arvo.
public static void main(String[] args) {
kaynnista();
}
public static void kaynnista() {
int eka = 5;
int toka = 6;
int summa = summa(eka, toka);
System.out.println("Summa: " + summa);
}
public static int summa(int luku1, int luku2) {
return luku1 + luku2;
}
Metodin kaynnista
suorituksen alussa kutsupino näyttää seuraavalta, sillä siihen päädyttiin main
-metodista. Metodilla main
ei tässä esimerkissä ole omia muuttujia:
Kun kaynnista
-metodissa on luotu muuttujat eka
ja toka
, eli sen ensimmäiset kaksi riviä on suoritettu, on tilanne seuraava:
Komento int summa = summa(eka, toka);
luo metodiin kaynnista
muuttujan summa
, ja kutsuu metodia summa
. Metodi kaynnista
jää odottamaan. Koska metodissa summa
on määritelty parametrit luku1
ja luku2
, luodaan ne heti metodin suorituksen alussa, ja niihin kopioidaan parametrina annettujen muuttujien arvot.
Metodin summa
suoritus laskee muuttujien luku1
ja luku2
arvot yhteen. Komento return
palauttaa lukujen summan kutsupinossa yhtä alemmalle metodille, eli metodille kaynnista
. Palautettu arvo asetetaan muuttujan summa
arvoksi.
Tämän jälkeen suoritetaan tulostuskomento, jonka jälkeen palataan main
-metodiin. Kun suoritus on main
-metodin lopussa, ohjelman suoritus loppuu.
Metodi kutsuu toista metodia
Kuten edellä huomattiin, metodin sisältä voi kutsua myös muita metodeja. Alla vielä esimerkki tähän liittyen. Tehdään metodi kertotaulu
, joka tulostaa annetun luvun kertotaulun. Kertotaulu tulostaa rivit metodin tulostaKertotaulunRivi
avulla.
public static void kertotaulu(int ylaraja) {
int luku = 1;
while (luku <= ylaraja) {
tulostaKertotaulunRivi(luku, ylaraja);
luku++;
}
}
public static void tulostaKertotaulunRivi(int luku, int kerroin) {
int tulostettava = luku;
while (tulostettava <= luku * kerroin) {
System.out.print(" " + tulostettava);
tulostettava += luku;
}
System.out.println("");
}
Esimerkiksi metodikutsun kertotaulu(3)
tulostus on seuraava.
Alla metodikutsu kertotaulu(3)
visualisoituna. Huomaa, miten kutsupinossa on tieto kutsuvan metodin sisäisestä tilasta.
Muistathan tarkistaa pistetilanteesi materiaalin oikeassa alareunassa olevasta pallosta!