Metodit ja ohjelman jakaminen pienempiin osiin
Olemme käyttäneet useita erilaisia komentoja: arvon asettamista, laskutoimituksia, ehtolauseita, ja toistolauseita.
Ruudulle tulostaminen on tehty System.out.println()
-lauseella ja lukeminen Integer.valueOf(lukija.nextLine())
lauseella. Ehtolauseessa on käytetty if
:iä, toistolauseessa while
:ä ja for
:ia. Huomaamme, että tulostaminen ja lukeminen poikkeaa if
:istä, while
:stä, for
:ista siinä, että tulostus- ja lukemiskomennon perässä on sulut ja joskus sulkujen sisällä komennolle annettava parametrit. Nämä "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. Esimerkiksi koodirivillä System.out.println("olen metodille annettava parametri!")
kutsutaan metodia, joka suorittaa ruudulle tulostamisen. Metodin sisäinen toteutus — eli joukko suoritettavia lauseita — on piilossa, eikä ohjelmoijan tarvitse välittää siitä metodia käytettäessä.
Tähän mennessä käyttämämme metodit ovat kaikki olleet Javan valmiita metodeita. Opetellaan seuraavaksi tekemään omia metodeita.
Omat metodit
Metodi tarkoittaa nimettyä lauseista koostuvaa joukkoa, jota voi kutsua muualta ohjelmakoodista nimen perusteella. Ohjelmointikielet tarjoavat valmiita metodeja, mutta ohjelmoija voi myös kirjoittaa omia metodeja. On oikeastaan on melko poikkeuksellista mikäli ohjelmassa ei ole yhtään itse kirjoitettua metodia, sillä metodit auttavat ohjelman jäsentämisessä. Tästä lähtien lähes jokainen kurssilla tehty ohjelma sisältääkin itsekirjoitettuja metodeja.
Metodit kirjoitetaan ohjelmarunkoon 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!");
}
}
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 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 ja jatketaan ohjelman suoritusta seuraavasta lauseesta.
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 (metodilla on oma lohko, joten metodin koodin sisennys on neljä välilyöntiä).
public static void tamaMetodiSanooMur() {
System.out.println("mur");
}
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ä. Metodissa käytettävät parametrien arvot kopioituvat metodikutsun yhteydessä metodille annettavista parametreista.
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);
System.out.println("");
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ä lauseke evaluoituu arvoksi 3
ja lopullinen metodikutsu on muotoa tervehdi(3);
.
Useampi parametri
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
Parametrien arvot kopioituvat metodikutsussa
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);
System.out.println();
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. 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 |
|
Metodi palauttaa `int`-tyyppisen muuttujan |
|
Metodi palauttaa `double`-tyyppisen muuttujan |
|
Kun metodin suorituksessa päädytään komentoon return
, metodin suoritus päättyy ja metodista palautetaan arvo sitä kutsuneelle metodille.
Komentoa return
seuraavia lähdekoodirivejä ei koskaan suoriteta. Jos ohjelmoija lisää lähdekoodia return-komennon jälkeen paikkaan, jota ei metodin suorituksessa voida koskaan saavuttaa, ohjelmointiympäristö antaa virheviestin.
Seuraavanlainen metodi on virheellinen ohjelmointiympäristön näkökulmasta.
public static int virheellinenMetodi() {
return 10;
System.out.println("Väitän palauttavani kokonaisluvun, mutten palauta sitä.");
}
Seuraava metodi taas toimii, sillä — vaikka return-komennon alla on lähdekoodia — jokainen metodin lause on mahdollista saavuttaa.
public static int toimivaMetodi(int parametri) {
if (parametri > 10) {
return 10;
}
System.out.println("Parametrina saatu luku on kymmenen tai pienempi.");
return parametri;
}
Mikäli metodi on muotoa public static void metodinNimi()
, voi metodista palata — tai toisin sanoen metodin suorituksen voi lopettaa kesken — komennolla return
, jota ei seuraa arvo. Esimerkiksi:
public static void jakolasku(int osoittaja, int nimittaja) {
if (nimittaja == 0) {
System.out.println("Nollalla ei saa jakaa!");
return;
}
System.out.println("" + osoittaja + " / " + nimittaja + " = " + (1.0 * osoittaja / nimittaja));
}
Muuttujien määrittely metodien sisällä
Muuttujien määrittely tapahtuu metodeissa samalla tavalla kuin "pääohjelmassa". 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);
}
Metodissa määritellyt muuttujat näkyvät vain metodissa. Tämä tarkoittaa sitä, että yllä metodin keskiarvo
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.
Palautettavan arvon laskeminen metodissa
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!