(Muutettu viimeksi 23.9.2010, sivu perustettu 3.9.2010. Arto Wikla)
Tässä luvussa siirrytään Scalan alkeista Java-kieleen. Java on kirjoitustyyliltään huomattavasti Scalaa monisanaisempaa. Javassa yhtenä ajatuksena on, että ohjelmoijan on kerrottava hyvin tarkasti, mitä hän tahtoo.
Tällä on hyvät puolensa, mutta toisaalta seurauksena on, että aloittelija joutuu kirjoittamaan paljon sellaista, mikä toistaiseksi vaikuttaa pelkältä loitsulta. Jos yhtään lohduttaa, niin jatkokurssin loppupuoleen mennessä noiden "loitsujen" merkityskin selviää.
Nyt ryhdytään myös käyttämään ohjelmankehitysympäristöä eli "IDEä" nimeltään NetBeans. Se osaltaan helpottaa myös noiden "loitsujen" lausumista.
Tässä luvussa käydään tiiviisti läpi luvun I Algoritmeja (Scala) tärkeimmät esimerkit Java-versioina. Samalla tiiviisti kerrotaan kielten eroista.
Scalalla maailmaa tervehdittiin vaivatta:
println("Hello world!");
Java-ohjelmoija joutuu kirjoittelemaan aika lailla noita mainittuja "loitsuja":
public class HelloOhjelma { public static void main(String[] args) { System.out.println("Hello world!"); } }
Kuten näkyy, Scala-versio sisältyy Java-versioon. Mutta loitsuissa löytyy...
Tässä loitsut lyhyesti sanottuna tarkoittavat seuraavaa:
public class HelloOhjelma
:
Suoritettava Java-ohjelma on julkinen luokka, jolle tässä on annettu
nimi HelloOhjelma
. Lähdekielinen ohjelma on tekstitiedossa,
jonka nimen alkuosa on sama kuin julkisen luokan: Ohjelma.java
.
public static void main(String[] args)
: Ohjelman suoritus alkaa
ns. pääohjelmasta, joka Javassa on aina nähdyn kaltainen.
Javan pääohjelmaa tavataan kutsua "main-metodiksi".
System.out.
: [Älä vielä yritäkään ymmärtää seuraavaa!]
Luokassa System
on julkinen kenttä out
, joka
viittaa tulostusolioon, jolla on mm. aksessori println
.
Java-ohjelma voidaan suorittaa ilman erityistä ohjelmankehitysympäristöä seuraavaan tapaan käyttöjärjestelmän komentotulkissa ("terminal"):
HelloOhjelma.java
.
Ohjelman nimen alkuosan pitää olla sama kuin luokan nimi, esimerkissä
siis HelloOhjelma
. Muista että luokkanimet on Javassa tapana kirjoittaa
suurella alkukirjaimella.
javac HelloOhjelma.javaJos ohjelmassa on muotovirheitä, kääntäjä antaa niistä enemmän tai vähemmän osuvia virheilmoituksia. Korjaa virheet tiedostossa
HelloOhjelma.java
ja
yritä kääntää uudelleen. Sitten kun ohjelma kelpaa kääntäjälle, kääntäjä tuottaa
ohjelman välikielivastineen tiedostoksi HelloOhjelma.class
.
java HelloOhjelmaHuomaa, että välikielisen ohjelmatiedoston nimen loppuosaa
.class
ei mainita tulkin käynnistyskomennossa.
Ohjelmointiympäristö eli IDE sisältää kääntäjän, editorin, yksinkertaisen virhetarkastuksen ja monia muita hyödyllisiä välineitä ohjelmoinnin helpottamiseen. Ja koska kaikki nuo ovat samassa ohjelmassa, kyseessä todellakin on "integroitu" ympäristö.
Kurssilla käytetään NetBeans-ohjelmointiympäristöä, joka löytyy valmiiksi asennettuna laitoksen koneista, Linuxissa Applications/Programming-alasvetovalikosta.
File -> New Project -> Java -> Java Application -> NextKirjoita kenttään Project Name (toistaiseksi) ohjelman luokan nimi
HelloOhjelma
. Kirjoita sama nimi myös kenttään
Create Main Class. Paina nappulaa Finish.
KUVA!
(Jos käynnityksen jälkeen yläpalkin alla näkyy Start Page, sulje
se klikkamalla rastia, ks. kuva.)
Niin yllättävältä kuin se saattaakin kuulostaa, ohjelmat eivät ihan aina toimi ihan oikein, vaikka ne kääntäjälle kelpaisivatkin... ;-)
Yksi tapa yrittää löytää syitä ohjelman virheelliseen toimintaan on ohjelman suorituksen pysäyttäminen ennalta määrättyihin kohtiin ja muuttujien arvojen tutkiminen tuolla hetkellä.
NetBeansilla tällaista analyysia voi tehdä seuraavaan tapaan:
NetBeansilla laaditusta Java-ohjelmasta on olemassa myös ihan tavallinen tekstitiedostoversio, jota voi perinteseen tapaan kääntää ja suorittaa käyttöjärjestelmän komentotulkissa.
Linuxissa NetBeansilla laaditut ohjelmat yms. oletusarvoisesti löytyvät
kotihakemiston alihakemistosta NetBeansProjects
.
Esimerkkitapauksessamme hakemistopolku on
NetBeansProjects/HelloOhjelma2/src/
Tuossa hakemistossa ohjelma on omalla nimellään tekstiedostona
HelloOhjelma.java
.
Scalan esimerkki
var teksti = "juttuhomma"; var kokonaisluku = 1234; var liukuluku = 3.14; var onkoTotta = true; println(teksti); println(kokonaisluku); println(liukuluku); println(onkoTotta); teksti = "uusjuttu"; kokonaisluku = -666; liukuluku = 1.2; onkoTotta = false; println(teksti); println(kokonaisluku); println(liukuluku); println(onkoTotta);
Javalla:
public class Muuttujia { public static void main(String[] args) { String teksti = "juttuhomma"; int kokonaisluku = 1234; double liukuluku = 3.14; boolean onkoTotta = true; System.out.println(teksti); System.out.println(kokonaisluku); System.out.println(liukuluku); System.out.println(onkoTotta); teksti = "uusjuttu"; kokonaisluku = -666; liukuluku = 1.2; onkoTotta = false; System.out.println(teksti); System.out.println(kokonaisluku); System.out.println(liukuluku); System.out.println(onkoTotta); } }
Huomaa: Muuttujat määritellään hieman toisin kuin Scalassa: ensin tyyppininmi ja sitten muuttujan nimi. Javan tyyppejä ovat mm. String, int, double ja boolean.
Käytäntö on Javassa sama kuin Scalassa.
Ja kurssilla siis suositaan "javamaisia" CamelCase-nimiä:
kuukaudenEnsimmainenPaiva
, jne...
Ja säästetään isolla kirjaimella alkavat tunnukset Javan luokkanimille.
Javassa on sama kommenttikäytäntö kuin Scalassa: monirivinen ja rivin loppu -kommentti:
/* monirivinen sepustus. */ // rivin loppu on kommenttia
Tulostukseen on käytettävissä Scalan tapaan
println
-operaation lisäksi operaatio
print
.
Ensin mainittu vaihtaa riviä tulostettuaan, jälkimmäinen ei
vaihda. Tarvitaan vain se System.out.
-lisäys:
public class Kissoja { public static void main(String[] args) { System.out.print("kissa"); System.out.println("kävelee"); // tulostaa: kissakävelee System.out.println("kissa"); System.out.println("kävelee"); // tulostaa: kissa // kävelee int i = 4321; System.out.print("Muuttujan i arvo on "); System.out.print(i); System.out.println("."); // tulostaa Muuttujan i arvo on 4321. } }
Merkkijonokatenaatiokin toimii tuttuun tapaan:
public class Katenointeja { public static void main(String[] args) { int i = 4321; System.out.println("Muuttujan i arvo on " + i + "."); // tulostaa Muuttujan i arvo on 4321. System.out.println("Yhtä suurempi arvo on " + (i+1) + "."); // tulostaa Yhtä suurempi arvo on 4322. // HUOM: SULUT I:N KASVATUKSEN YMPÄRILLÄ VÄLTTÄMÄTTÖMÄT, SILLÄ System.out.println("Yhtä suurempi arvo on " + i+1 + "."); // tulostaa Yhtä suurempi arvo on 43211. System.out.println("ahaa " + i + 7); // ahaa 43217 System.out.println("ahaa " + (i + 7)); // ahaa 4328 System.out.println(i + 7 + " ahaa"); // 4328 ahaa System.out.println("Merkkijonon sisäänkin saa lainausmerkin: \". Mukavaa."); System.out.println("Sarkain eli tabulointikin onnistuu: \t Kas näin."); System.out.println("Rivinvaihtojakin voi kirjoittaa: \n Tässä yksi. \n\nJa pari lisää."); } }
Nämä käyttäytyvät hyvin samaan tapaan kuin jo Scala-osiossa opittiin.
Esimerkki:
public class Lukuja { public static void main(String[] args) { int lkm=1, kpl=100; double pituus=1.1, leveys=2.2, korkeus=3.3; lkm = kpl- 10 * (kpl-8); pituus = leveys * korkeus + pituus * lkm; lkm = 5; korkeus = 5; kpl = lkm/2; // arvo on 2 leveys = korkeus/2; // arvo on 2.5 lkm = 17%3; // arvo on 2 } }
---> Lisätietoa kokonaisluvuista, liukuluvuista ja tyyppimuunnoksista
Javalla syöttötietoja voi lukea käyttämällä ns.
Scanner
-oliota
import java.util.Scanner; // Scanner-luokka tuodaan käännösyksikköön public class Viisas { private static Scanner lukija = new Scanner(System.in); // luodaan Scanner-olio public static void main(String[] args) { String nimi; int ika; double pituus; System.out.println("Mikä on nimesi?"); nimi = lukija.nextLine(); System.out.print("Ja ikäsi: "); ika = lukija.nextInt(); System.out.print("Entä pituutesi? "); pituus = lukija.nextDouble(); // Syötteessä käytettävä desimaalipilkkua!! System.out.println("Moi " + nimi +"!"); System.out.print("Tiedän että olet " + ika + "-vuotias "); System.out.println("ja että olet " + pituus + " senttiä pitkä."); System.out.println("Enkö olekin viisas!"); } }
Syöttö tapahtuu muuten kuin Scala-versiossa, mutta laitoksen koneissa desimaaliluku on syötettävä desimaalipilkullisena vaikka ohjelma itse käyttääkin desimaalipistettä. Syynä on "oletuslokalisaatio". Se voi omassa koneessasi olla eri...
Mikä on nimesi? Violetta Ja ikäsi: 20 Entä pituutesi? 167,8 Moi Violetta! Tiedän että olet 20-vuotias ja että olet 167.8 senttiä pitkä. Enko olekin viisas?
Jos ohjelmalle syöttää väärän tyyppistä tietoa, ohjelman suoritus päättyy virheeseen. Myös desimaalipisteen käyttö siis kaataa ohjelman.
---> Lisätietoa desimaalipisteen sallimisesta
Javan if
-lause, loogisten ehtojen kirjoittaminen
ja lohkot ovat samanlaisia kuin jo Scala-osiossa opittiin.
import java.util.Scanner; public class PosNegNol { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { System.out.println("Anna kokonaisluku!"); int luku = lukija.nextInt(); if (luku > 0) System.out.println("Luku on positiivinen."); else if (luku < 0) System.out.println("Luku on negatiivinen."); else System.out.println("Ahaa, luku on nolla."); // ei ollut positiivinen eikä negatiivinen... } }
Yksi kiinnostava ero kuitenkin löytyy: Scalan tapaan merkkijonon vertaaminen toiseen merkkijonoon ei onnistu vaivattomasti tyyliin:
if (s != "hupsista") ... if (s == "hupsista") ...
Näin saa kyllä kirjoittaa – se on "oikein" – mutta tarkoittaa luultavasti
jotain muuta kuin ohjelmoija tarkoitti:
Javassa kaikkien olioarvojen yhtäsuuruus- ja erisuuruusvertailut tarkoittavat
vastausta kysymykseen "onko kyseessä yksi ja sama olio". Ja on täysin mahdollista,
että muuttuja s viittaa eri merkkijono-olioon, jonka sisältö sattuu
olemaan myös "hupsista"
! Tässä tilanteessa ehto siis luultavasi siis tarkoittaa jotakin
muuta kuin ohjelmoija tarkoittaa.
Java-ohjelmassa merkkijonojen samansisältöisyyttä tutkitaan String-luokan aksessorimetodilla equals:
if (!s.equals("hupsista")) ... if (s.equals("hupsista")) ...
Olioista ja niiden vertailuista lisää myöhemmin.
Javan alkuehtoinen toisto, while-lause, on hyvin samanlainen kuin Scalassa:
import java.util.Scanner; public class Pariton { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { System.out.println("Anna pariton luku."); int luku = lukija.nextInt(); while (luku % 2 == 0) { System.out.println("Eihän luku " + luku + " ole pariton!"); System.out.println("Yritä uudelleen"); luku = lukija.nextInt(); } System.out.println("Kyllä! " + luku + " todella on pariton."); } }
Loppuehtoinen toisto eli do-while-lause on muotoa:
do { lause1; lause2; ... } while (jatkamisehto)
Esimerkki:
import java.util.Scanner; public class Pariton2 { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { int luku; boolean parillinen; do { System.out.println("Anna pariton luku!"); luku = lukija.nextInt(); parillinen = (luku%2 == 0); if (parillinen) { System.out.println("Eihän "+luku+" ole pariton ..."); System.out.println("Yritä uudelleen"); } } while (parillinen); System.out.println("Hienoa, "+luku+" on pariton!"); } }
Tässä esimerkissä on muutakin opittavaa: Totuusarvoista
muuttujaa parillinen
käytetään muistamaan
oliko viimeksi luettu luku parillinen. Jos oli, luku ei
siis ollut vaadittu pariton, ja voidaan antaa virheilmoitus
ja toistoehto aikaansaa uuden kyselyn.
Javassa taulukoiden määrittelyn ja käytön merknnät poikkeavat jonkin verran kurssilla jo opitusta, mutta idea on aivan sama:
import java.util.Scanner; public class EkaVikaksiJne { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { int[] luvut = new int[5]; // tämä selitetään kohta... int lokeronNumero = 0; while (lokeronNumero < 5) { System.out.print("Anna " + (lokeronNumero+1) + ". luku: "); // pyydetään 1., 2., ..., siksi tuo +1 luvut[lokeronNumero] = lukija.nextInt(); lokeronNumero = lokeronNumero +1; } System.out.println("Luvut käänteisessä järjestyksessä:"); lokeronNumero = 4; while (lokeronNumero >= 0) { System.out.println(luvut[lokeronNumero]); lokeronNumero = lokeronNumero - 1; } } }
Javassa taulukkomuuttujan määrittely ja taulukko-olion luonti ovat siis muotoa:
int[] luvut = new int[5];
Muuttuja luvut
on tyypiltään kokonaislukutaulukko.
Sen arvoksi luodaan viisialkioinen kokonaislukutaulukko-olio.
Indeksointi Scalan tapaan alkaa nollasta. Koska muuttuja on "muuttuja", sen
arvoksi voidaan tarvittaessa myöhemmin sijoittaa jokin toinen kokonaislukutaulukko,
myös toisen mittainen. Mutta vain kokonaislukutaulukko.
Taulukkoa indeksoidaan Javassa useimpien muiden ohjelmointikielten tapaan hakasulkein:
luvut[lokeronNumero] = lukija.nextInt();
Myös Javassa taulukon koon eli alkioiden lukumäärän ilmaisee
.length
:
public class Kokoja { public static void main(String[] args) { int[] t1 = new int[5]; double[] t2 = new double[500]; int[] t3 = new int[1000000]; System.out.println(t1.length); // 5 System.out.println(t2.length); // 500 System.out.println(t3.length); // 1000000 } }
Edellä opittiin Scalan for-lauseesta esimerkki:
for (i <- 5 to 10) print(i + " "); // 5 6 7 8 9 10 println(); // rivinvaihto for (i <- (5 to 10).reverse) print(i + " "); // 10 9 8 7 6 5 println(); // rivinvaihto
Saman voi tehdä Javalla seuraavaan tapaan:
for (int i = 5; i < 11; i = i+1) System.out.print(i + " "); // 5 6 7 8 9 10 System.out.println(); // rivinvaihto for (int i = 10; i > 4; i = i-1) System.out.print(i + " "); // 10 9 8 7 6 5 System.out.println(); // rivinvaihto
Tässä kannattaa kiinnittää huomio muutamaan yksityiskohtaan:
for (int i = 5; i < 11; i = i+1)
true
, toistettava alialgoritmi suoritetaan, jos false
,
alialgoritmia ei toisteta.
for (int i = 5; i < 11; ++i) for (int i = 10; i > 4; --i)Tai
for (int i = 5; i < 11; i++) for (int i = 10; i > 4; i--)
(Näillä kahdella tavalla ei tässä tilanteessa ole merkityseroa. On olemassa tilannne jossa merktykset eroavat, mutta se tilanne ei liity hyvään ohjelmointityyliin.)
//Tulostetaan luvun 3.14:n kahtakymmentä pienemmät monikerrat: for (double piit = 3.14; piit < 20; piit+=3.14) System.out.println(piit);Kun tämä suoritetaan, saadaan tulostus:
3.14 6.28 9.42 12.56 15.700000000000001 18.84
[Liukuluvut ovat aina likiarvoja ja yllä tapahtuu ns. pyöristysvirhe (---> lisätietoa pyöristysvirheestä).]
Tuttu Scala-esimerkki "javannettuna": Kysytty määrä syöttölukuja tulostetaan käänteisessä järjestyksessä:
import java.util.Scanner; public class EkaVikaksiJnePlus { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { System.out.println("Montako lukua haluat tulostaa käännetyssä järjestyksessä?"); int koko = lukija.nextInt(); int[]luvut = new int[koko]; // HUOM: taulukon koko saa olla siis myös muuttuja! for (int lokeronNumero=0; lokeronNumero < luvut.length; ++lokeronNumero) { System.out.print("Anna " + (lokeronNumero+1) + ". luku: "); luvut[lokeronNumero] = lukija.nextInt(); } System.out.println("Luvut käänteisessä järjestyksessä:"); for (int lokeronNumero = luvut.length-1; lokeronNumero >= 0; --lokeronNumero) System.out.println(luvut[lokeronNumero]); } }
Edellä opittu for-lauseen muoto talukoiden käsittelyssä perustuu
indeksointiin, siihen että askelmuuttuja
(vaikkapa int i
) käy läpi taulukon indeksit ja
toistettava alialgoritmi viittaa taulukon alkiohin indeksointi-ilmauksella
(vaikkapa taulu[i]
). Tällä menettelyllä taulukon alkioiden
arvoja voidaan tutkia ja myös muuttaa.
Jos on tarve vain tutkia taulukon alkiot yksi kerrallaan alusta loppuun, käytettävissä on myös ns. "for-each"-toisto, jossa taulukon alkioiden tyyppinen muuttuja saa yksi kerrallaan arvokseen taulukon alkioiden arvot. Lauseen muoto on:
for (taulukon_alkion_tyyppi alkio: taulukko) { // tänne saadaan yksi kerrallaan käyttöön // taulukon alkioiden arvot muuttujassa alkio }
Esimerkkinä taulukon alkioiden summan laskenta.
public class PiinAlkua { public static void main(String[] args) { int[] taulu = {3, 1, 4, 5, 9, 2, 6, 5, 3, 5}; int summa = 0; for (int alkio : taulu) summa = summa + alkio; System.out.println("Alkioiden summa: " + summa); } }
Huom: Tätä for-toiston muotoa käyttäen alkioiden arvoja ei siis
voi muuttaa. Muutostarpeen tullessa indeksointia "omin käsin" ei voi
välttää. Alkioiden idekseistä ei myöskään ole mitään tietoa.
Jos on tiedettävä, on syytä tällöikin ideksoida "omin käsin"
Siis:
for (taulukon_alkion_tyyppi alkio: taulukko) { // tällä ei ole tietoa alkion indeksistä // ja vaikka muutujan alkio arvoa muuttaisi, // taulukossa mikään ei muutu }
Huom: Tämä sama väline on käytettävissä myös Javan monien ns. kokoelmien alkioiden arvojen järjestelmälliseen läpikäyntiin.
Aiemmin nähtyjä esimerkkejä Javalla:
String teksti = "juttuhomma"; System.out.println(teksti); teksti = "uusjuttu"; System.out.println(teksti); String[] nimet = new String[3]; nimet[0] = "Aku"; nimet[1] = "Iines"; nimet[2] = "Hessu"; for (int indeksi=0; indeksi < nimet.length; ++indeksi) System.out.println(nimet[indeksi]);
Muista että Java-ohjelmoija joutuu vertailemaan merkkijonojen
samuutta erityisellä equals
-aksessorilla.
Yhtäsuuruusmerkki ==
tarkoittaa jotakin muuta...
if (teksti.equals("kissantassu")) ...
Myös Javassa taulukon voi määritellä myös luettelemalla alkioiden alkuarvot. Syntaksi vain on hieman erilainen:
import java.util.Scanner; public class koe { private static Scanner lukija = new Scanner(System.in); public static void main(String[] args) { String[] henkilot = {"Matti", "Maija", "Pekka", "Liisa"}; int[] ika = { 29, 22, 19, 27}; System.out.println("Kenen henkilön iän haluat tietää?"); String kuka = lukija.nextLine(); // etsitään indeksi: int indeksi = 0; while (indeksi < henkilot.length && !henkilot[indeksi].equals(kuka)) indeksi = indeksi + 1; // Nyt joko löytyi tai indeksi kasvoi yli: if ( indeksi == henkilot.length ) System.out.println("Henkilöä " + kuka + " ei löytynyt."); else { int haetunIka = ika[indeksi]; System.out.println("Henkilön " + kuka + " ikä on " + haetunIka + "."); } } }
Tässä esimerkissä on tälläkin kertaa paljon muutakin opittavaa kuin taulukon määrittely alkuarvot luettelemalla. Mitä? Mieti, tutki ja opi!
Java-ohjelmoijat kutsuvat nimettyjä aliohjelmia useimmiten metodeiksi (method). Nimitys tulee metodien yhdestä tärkeästä kayttotavasta: olioita ja niiden tilaa käsitellään metodein. Tästä lisää myöhemmin.
Metodien ohjelmoinnin ja käytön ideat ovat jo tuttuja kurssin alkuvaiheilta. Mutta kuten niin usein tällä alalla, nytkin joudutaan opettelemaan uusia tapoja ilmaista tuttuja ideoita.
Nimetyt alialgoritmit voivat olla "komentoja tehdä jotakin" samaan tapaan
kuin vaikkapa println
osaa kirjoittaa parametrinsa ohjelman
käyttäjän kuvaruudulle.
Nimettyjä
alialgoritmeja voi kirjoittaa myös sellaisiksi, että ne laskevat jonkin arvon
ja palauttavat tuon arvon. Esimerkkejä tällaisista ovat vaikkapa
trigonometriset funktiot, jotka useimmista ohjelmointikielistäkin löytyvät.
Javassa ensin mainittuja kutsutaan usein void
-metodeiksi
eli arvoa palauttamattomiksi metodeiksi. Jälkimmäiset siten luontevasti
ovat arvon palauttavia metodeita. Ja koska kaikilla arvoilla Javassa
on tyyppi, arvon palauttavia metodeita usein nimitetään paluuarvon
tyypin mukaan: int
-metodi, double
-metodi,
String
-metodi, jne.
Tässä luvussa laaditaan metodeita vielä klassiseen malliin "pääohjelman pikku apulaisiksi". Olio-ohjelmoinnin puolella sitten opitaan toinen tärkeä käyttötapa metodeille.
Ensin tuttu esimerkki esimerkki "komennon kaltaisesta" metodista:
public class Moi { private static void tervehdi() { // määrittely System.out.println("Moi!"); } public static void main(String[] args) { System.out.println("Kutsutaanpa tervehdystä:"); tervehdi(); // kutsu System.out.println("Kutsutaanpa kolmasti:"); tervehdi(); tervehdi(); tervehdi(); } }
Tuttu esimerkki arvon palauttavasta metodista:
public class Moi2 { private static int onnenluku() { // määrittely return 14; } public static void main(String[] args) { System.out.println("Onnenluku = " + onnenluku()); // kutsu System.out.println("Ja kolmeen kertaan: " + (onnenluku() + onnenluku() + onnenluku())); } }
Ja sitten muutamia huomioita Javan tyylistä
private
) ja luokkaan,
ei olioon, liittyviksi (static
). Nämä asiat selviävät
aikanaan, ei huolta.
void
-määreellä, joka
juuri sanoo, että "ei arvoa".
int
.
Metodin parametrien määrittely ja antaminen muistuttavat jo opittua – Javan tapaan tyyppinimi edeltää muuttujaa:
public class Moi3 { private static void tervehdi(String kuka) { // määrittely System.out.println("Moi " + kuka + "!"); } public static void main(String[] args) { System.out.println("Kutsutaanpa tervehdystä:"); tervehdi("Aku"); // kutsu System.out.println("Kutsutaanpa kolmasti:"); tervehdi("Iines"); tervehdi("Minni"); tervehdi("Mikki"); int monesko = 7; String nimi = "Jaska Jokunen"; tervehdi(nimi + ", perijä numero " + (monesko+2)); // tulostus: Moi Jaska Jokunen, perijä numero 9! } }
Huom: Muista terminologia: Metodin määrittelyssä esiteltyjä parametreja kutsutaan muodollisiksi parametreiksi. Metodin kutsuun kirjoitettavia arvoja kutsutaan todellisiksi parametreiksi, toisinaan myös argumenteiksi. [Tämän tyylin parametreja kutsutaan arvoparametreiksi. Scalassa ja Javassa parametrit ovat aina tällaisia. Mutta myös muita parametrinvälitystapoja ohjelmointikielistä löytyy.]
Tietenkin myös arvon palauttavalle metodille voi antaa parametreja:
public class Moi4 { private static int tuplaa(int luku) { // määrittely return 2 * luku; } public static void main(String[] args) { System.out.println("Kolme tuplana = " + tuplaa(3)); // kutsu int i = 8; int j = tuplaa(i); System.out.println( tuplaa(j) + tuplaa(2) ); System.out.println(tuplaa(tuplaa(tuplaa(1)))); } }
Parametreja voi toki olla useampiakin:
public class Onnea { private static void onnittele(String kuka, int kertaa) { for (int i = 0; i < kertaa; ++i) System.out.println( "Onnea " + kuka + "!"); } public static void main(String[] args) { onnittele("Liisa", 3); onnittele("Pekka", 2); } }
public class Nelis { private static int neliosumma(int a, int b) { int summa = a + b; int nelio = summa * summa; return nelio; } public static void main(String[] args) { System.out.println(neliosumma(1, 1)); System.out.println(neliosumma(3, 2)); } }
Metodin sisällä eli metodin lohkossa määritellyt muuttujat eivät milloinkaan voi näkyä metodin lohkon ulkopuolelle. Tällaisia muuttujia kutsutaan funktion paikallisiksi muuttujiksi. Ne ovat käytettävissä vain metodin omassa algoritmissa.
Metodin paikalliset muuttujat ja muodolliset parametrit itse asiassa syntyvät, kun metodia kutsutaan ja metodi käynnistyy. Paikallisille muuttujille ja muodollisille parametreille varattu tila vapautetaan, kun metodin suoritus päättyy. Koska paikalliset muuttujat eivät säily suorituskerrasta toiseen, niiden avulla myöskään "ei voi muistaa mitään" seuraavalle suorituskerralle.
Metodin muodolliset parametrit ovat muuten samassa asemassa kuin paikalliset muuttujat, mutta niillä on aina alkuarvonaan kulloisessakin kutsussa annettujen todellisten parametrien arvo. Arvoa on lupa myös muuttaa, mutta muutos ei näy metodin ulkopuolelle, koska muodollisten parametrienkin tila vapautetaan metodin suorituksen päättyessä.
Java-kielessä pätee sääntö: Mistään aliohjelmasta ei koskaan voi nähdä minkään toisen aliohjelman paikallista muuttujaa.
Myös taulukon voi välittää parametrina, mikä usein on näppärää:
public class ArvotPaikalleen { private static void asetaJokaAlkiolle(int[] taulu, int arvo) { for (int i = 0; i < taulu.length; ++i) taulu[i] = arvo; } public static void main(String[] args) { int[] t = new int[10]; System.out.println(t[7]); // 0 asetaJokaAlkiolle(t, 100); System.out.println(t[7]); // 100 t = new int[1000000]; // uusi arvo t:lle asetaJokaAlkiolle(t, 9876); System.out.println(t[765432]); // 9876 } }
Esimerkki peräkkäishausta: metodi etsii taulukosta kysyttyä arvoa ja palauttaa vastaavan indeksin ensimmäisestä löytyneestä. Jos päästään talukon loppuun löytämättä haettua arvoa, palautetaan arvo -1, joka ei kelpaa taulukon indeksiksi. Se viestii, ettei haettua arvoa löytynyt:
public class Perakkaishakuesimerkki { private static int mikaOnArvonIndeksi(int etsittava, int[] taulu) { for (int i = 0; i < taulu.length; ++i) if (taulu[i] == etsittava) return i; // jos tänne päästään, ei löytynyt return -1; // -1 ei voi olla indeksi } public static void main(String[] args) { int[] t = {2, 4, 6, 8, 10, 12, 14}; System.out.println("Luvun 8 indeksi on " + mikaOnArvonIndeksi(8, t)); System.out.println("Luvun 7 indeksi on " + mikaOnArvonIndeksi(7, t)); if (mikaOnArvonIndeksi(8, t) != -1) System.out.println("8 löytyy"); else System.out.println("8 ei löydy"); if (mikaOnArvonIndeksi(7, t) != -1) System.out.println("7 löytyy"); else System.out.println("7 ei löydy"); } }