Tämä materiaali on lisensoitu Creative Commons BY-NC-SA-lisenssillä, joten voit käyttää ja levittää sitä vapaasti, kunhan alkuperäisten tekijöiden nimiä ei poisteta. Jos teet muutoksia materiaaliin ja haluat levittää muunneltua versiota, se täytyy lisensoida samanlaisella vapaalla lisenssillä. Materiaalien käyttö kaupalliseen tarkoitukseen on ilman erillistä lupaa kielletty.
Tekijät: Arto Vihavainen ja Matti Luukkainen
Aaltosululla {
alkavaa ja aaltosululla }
loppuvaa koodia sisältävää aluetta kutsutaan lohkoksi. Kuten on jo nähty, lohkoja käytetään muun muassa ehto- ja toistolauseiden alueen rajaamisessa. Tärkeä lohkon ominaisuus on se, että lohkossa määritellyt muuttujat ovat voimassa vain lohkon sisällä.
Seuraavassa esimerkissä määritellään ehtolausekkeeseen liittyvän lohkon sisällä tekstimuuttuja teksti
, joka on olemassa vain lohkon sisällä. Lohkossa esitellyn muuttujan tulostus lohkon ulkopuolella ei toimi!
int luku = 5; if (luku == 5) { String teksti = "Oho!"; } System.out.println(teksti); // ei toimi!
Lohkossa voidaan käyttää ja muuttaa sen ulkopuolella ennen lohkoa määriteltyjä muuttujia.
int luku = 5; if (luku == 5) { luku = 6; } System.out.println(luku); // tulostaa luvun 6
String teksti = "Jee!"; int luku = 5; if (luku == 5) { teksti = "Oho!"; } System.out.println(teksti); // tulostaa "Oho!"
Lohkon sisällä voi olla mitä tahansa koodia. Esimerkiksi while-toistolauseen määrittelemän lohkon sisällä voi olla toinen while-toistolauseke. Tarkastellaan seuraavaa ohjelmaa:
int rivinumero = 0; while (rivinumero < 3) { System.out.print(rivinumero + ": "); int luku = 0; while (luku < 3) { System.out.print(luku + " "); luku++; } System.out.println(); rivinumero++; }
Ohjelman tulostus on seuraava:
0: 0 1 2 1: 0 1 2 2: 0 1 2
Eli mitä ohjelmassa tapahtuukaan? Jos ajatellaan pelkkää ulommaista while-lohkoa, on toiminnallisuus helppo ymmärtää:
int rivinumero = 0; while (rivinumero < 3) { System.out.print(rivinumero + ": "); // sisempi while System.out.println(); rivinumero++; }
Eli ensin rivinumero=0
ja tulostuu 0:
ja rivinvaihto. Tämän jälkeen rivinumero kasvaa ja tulostuu ykkönen, jne., eli ulompi for saa aikaan seuraavan:
0: 1: 2:
Myös sisempi while on helppo ymmärtää erillään. Se saa aina aikaan tulosteen 0 1 2
. Kun yhdistämme nämä kaksi, huomaamme, että sisempi while-toistolause suorittaa tulosteensa aina juuri ennen ulomman while-toistolauseen tulostamaa rivinvaihtoa.
Tutkitaan seuraavaa muunnosta edelliseen esimerkkiin:
int rivinumero = 0; while (rivinumero < 3) { System.out.print(rivinumero + ": "); int luku = 0; while (luku <= rivinumero) { System.out.print(luku + " "); luku++; } System.out.println(); rivinumero++; }
Sisemmän toistolausekkeen toistojen määrä riippuukin nyt ulommassa toistolausekkeessa käytettävän muuttujan rivinumero
arvosta. Eli kun rivinumero=0
, tulostaa sisempi toistolause luvun 0, kun rivinumero=1
, tulostaa sisempi toistolauseke "0 1 ", jne. Koko ohjelman tulostus on seuraava:
0: 0 1: 0 1 2: 0 1 2
Seuraava ohjelma tulostaa lukujen 1..10 kertotaulun.
int rivinumero = 1; while (rivinumero <= 10) { int sarake = 1; while (sarake <= 10) { System.out.print(rivinumero * sarake + " "); sarake++; } System.out.println(); rivinumero++; }
Tulostus näyttää seuraavalta:
1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100
Ylimmällä rivillä on luvun 1 kertotaulu. Alussa rivinumero=1
ja sisemmän toistolauseen muuttuja sarake
saa arvot 1...10. Jokaisella rivinumero, sarake
-arvoparilla tulostetaan niiden tulo. Eli alussa rivinumero=1, sarake=1
, sitten rivinumero=1, sarake=2
, ..., rivinumero=1, sarake=10
seuraavaksi rivinumero=2, sarake=1
, jne.
Kertotaulu-ohjelman voi toki pilkkoa pienempiin osiin. Voimme määritellä metodit public void tulostaKertotaulunRivi(int kerroin, int montakokertaa)
ja public void tulostaKertotaulu(int mihinAsti)
.
public class Kertotaulu { public void tulosta(int mihinAsti) { int rivinumero = 1; while (rivinumero <= mihinAsti) { tulostaKertotaulunRivi(rivinumero, mihinAsti); System.out.println(); rivinumero++; } } public void tulostaKertotaulunRivi(int rivi, int lukuja) { int sarake = 1; while (sarake <= lukuja) { System.out.print(rivi * sarake + " "); sarake++; } } }
Nyt kutsu new Kertotaulu().tulosta(5);
tulostaa allaolevan kertotaulun.
1 2 3 4 5 2 4 6 8 10 3 6 9 12 15 4 8 12 16 20 5 10 15 20 25
Harjoitellaan taas toistolausekkeiden, muuttujien ja indeksien käyttöä.
Toteuta luokka Lukutulostin
ja tee sille seuraavat toiminnallisuudet. Huom! Tässä tehtävässä ei ole etenemistä ohjaavia automaattisia testejä, jotta voit harjoitella ohjelmointia ilman "apupyöriä". Palauta tehtävä kun tiedät itse, että se toimii halutusti.
Toteuta luokalle Lukutulostin
metodi public void lukuporras(int luku)
. Metodin tulee toimia seuraavasti.
Lukutulostin tulostin = new Lukutulostin(); tulostin.lukuporras(2); System.out.println(); tulostin.lukuporras(3);
1 1 2 1 1 2 1 2 3
Lukutulostin tulostin = new Lukutulostin(); tulostin.lukuporras(5); System.out.println(); tulostin.lukuporras(2);
1 1 2 1 2 3 1 2 3 4 1 2 3 4 5 1 1 2
Toteuta luokalle Lukutulostin
metodi public void rajattuLukuporras(int alku, int loppu)
. Metodin tulee toimia seuraavasti.
Lukutulostin tulostin = new Lukutulostin(); tulostin.rajattuLukuporras(2, 2); System.out.println(); tulostin.rajattuLukuporras(2, 3);
1 2 1 2 1 2 3
Lukutulostin tulostin = new Lukutulostin(); tulostin.rajattuLukuporras(3, 5); System.out.println(); tulostin.rajattuLukuporras(1, 2);
1 2 3 1 2 3 4 1 2 3 4 5 1 1 2
Toteuta luokalle Lukutulostin
metodi public void jatkuvaLukuporras(int luku)
. Metodin tulee toimia seuraavasti.
Lukutulostin tulostin = new Lukutulostin(); tulostin.jatkuvaLukuporras(2); System.out.println(); tulostin.jatkuvaLukuporras(3);
1 2 3 1 2 3 4 5 6
Lukutulostin tulostin = new Lukutulostin(); tulostin.jatkuvaLukuporras(5); System.out.println(); tulostin.jatkuvaLukuporras(2);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 2 3
Toteuta luokalle Lukutulostin
metodi public void kertokolmio(int luku)
. Kertokolmio-metodin tulee toimia seuraavien esimerkkien mukaisesti.
Lukutulostin tulostin = new Lukutulostin(); tulostin.kertokolmio(2);
1 2 4
Lukutulostin tulostin = new Lukutulostin(); tulostin.kertokolmio(5); System.out.println(); tulostin.kertokolmio(3);
1 2 4 3 6 9 4 8 12 16 5 10 15 20 25 1 2 4 3 6 9
Toteuta luokka Sanatulostin
, jossa on seuraavat toiminnallisuudet. Kuten edellisessä tehtävässä, myös tässäkään tehtävässä ei ole apupyöriä.
Toteuta luokalle Sanatulostin
merkkijonon vastaanottava konstruktori sekä metodi public void sanaporras(int luku)
, joka toimii seuraavasti:
Sanatulostin tulostin = new Sanatulostin("Ananas"); tulostin.sanaporras(2); System.out.println(); tulostin.sanaporras(4);
A na A na nas Anan
Sanatulostin tulostin = new Sanatulostin("Sauna"); tulostin.sanaporras(3);
S au naS
Toteuta luokalle Sanatulostin
metodi public void laskevaSanaporras(int luku)
joka toimii seuraavasti:
Sanatulostin tulostin = new Sanatulostin("Ananas"); tulostin.laskevaSanaporras(2); System.out.println(); tulostin.laskevaSanaporras(3);
An a Ana na s
Sanatulostin tulostin = new Sanatulostin("Sauna"); tulostin.laskevaSanaporras(4);
Saun aSa un a
Toteuta luokalle Sanatulostin
metodi public void sanapyramidi(int luku)
, joka toimii seuraavasti:
Sanatulostin tulostin = new Sanatulostin("Nauris"); tulostin.sanapyramidi(3); System.out.println(); tulostin.sanapyramidi(1);
N au ris Na u N
Sanatulostin tulostin = new Sanatulostin("Saippuakauppias"); tulostin.sanapyramidi(4); System.out.println(); tulostin.sanapyramidi(2);
S ai ppu akau ppi as S S ai p
Kertaa edellisen viikon materiaali ennen jatkamista!
Jatkamme vielä tehtävien tekemistä siten, että niissä ei ole apupyöriä. Tehdään tässä luokka ostoslistan ylläpitoon.
Toteuta luokka Ostoslista
, jolla on parametriton konstruktori, ja joka sisältää listan String
-olioita. Toteuta luokalle metodit public void lisaa(String tuote)
ja public boolean onkoListalla(String tuote)
.
Luokkaa Ostoslista
ja luotavia metodeja tulee voida käyttää seuraavasti:
Ostoslista lista = new Ostoslista(); lista.lisaa("porkkana"); lista.lisaa("nauris"); if (!lista.onkoListalla("kauris")) { System.out.println("kauris ei ole listalla"); } if (lista.onkoListalla("nauris")) { System.out.println("nauris on listalla"); }
kauris ei ole listalla nauris on listalla
Lisää luokalle Ostoslista
metodi public int kappalemaara(String tuote)
, joka palauttaa listalla olevien tuotteiden lukumäärän haetulle tuotteelle. Metodin tulee toimia seuraavasti.
Ostoslista lista = new Ostoslista(); lista.lisaa("porkkana"); lista.lisaa("porkkana"); lista.lisaa("nauris"); lista.lisaa("porkkana"); System.out.println("Porkkanaa: " + lista.kappalemaara("porkkana") + " kpl"); System.out.println("Tomaatteja: " + lista.kappalemaara("tomaatti") + " kpl");
Porkkanaa: 3 kpl Tomaatteja: 0 kpl
Lisää luokalle Ostoslista
metodi public void poista(String tuote)
, joka poistaa yhden kappaleen annettua tuotetta. Metodin tulee toimia seuraavasti.
Ostoslista lista = new Ostoslista(); lista.lisaa("porkkana"); lista.lisaa("porkkana"); lista.lisaa("nauris"); lista.lisaa("porkkana"); System.out.println("Porkkanaa: " + lista.kappalemaara("porkkana") + " kpl"); System.out.println("Tomaatteja: " + lista.kappalemaara("tomaatti") + " kpl"); lista.poista("porkkana"); System.out.println(); System.out.println("Porkkanaa: " + lista.kappalemaara("porkkana") + " kpl"); System.out.println("Tomaatteja: " + lista.kappalemaara("tomaatti") + " kpl");
Porkkanaa: 3 kpl Tomaatteja: 0 kpl Porkkanaa: 2 kpl Tomaatteja: 0 kpl
Lisää luokalle Ostoslista
metodi, jonka avulla siitä tehtävä olio voidaan tulostaa System.out.println()
-komennon avulla. Tulostuksen tulee toimia seuraavasti (huomaathan että tuotteet tulostetaan aakkosjärjestyksessä):
Ostoslista lista = new Ostoslista(); lista.lisaa("porkkana"); lista.lisaa("porkkana"); lista.lisaa("nauris"); lista.lisaa("porkkana"); lista.lisaa("satsuma"); System.out.println(lista); lista.poista("porkkana"); System.out.println(lista);
Ostetaan seuraavat tuotteet nauris 1 kpl. porkkana 3 kpl. satsuma 1 kpl. Ostetaan seuraavat tuotteet nauris 1 kpl. porkkana 2 kpl. satsuma 1 kpl.
Olemme nähneet metodeja jotka palauttavat totuusarvoja, lukuja, listoja ja merkkijonoja. On helppoa arvata, että metodi voi palauttaa minkä tahansa tyyppisen olion. Tehdään painovartijayhdistykselle metodi, jolla saadaan tietoon yhdistyksen suurimman painoindeksin omaava henkilö.
public class PainonvartijaYhdistys { // ... public Henkilo suurinPainoindeksinen() { // jos jasenlista on tyhjä, palautetaan null-viite if (this.jasenet.isEmpty()) { return null; } Henkilo painavinTahanAsti = this.jasenet.get(0); for (Henkilo henkilo : this.jasenet) { if (henkilo.painoIndeksi() > painavinTahanAsti.painoIndeksi()) { painavinTahanAsti = henkilo; } } return painavinTahanAsti; } }
Logiikaltaan edeltävä metodi toimii samaan tapaan kuin suurimman luvun etsiminen taulukosta. Käytössä on apumuuttuja painavinTahanAsti
joka laitetaan aluksi viittaamaan listan ensimmäiseen henkilöön. Sen jälkeen käydään lista läpi ja katsotaan tuleeko vastaan suuremman painoindeksin omaavia henkilöitä, jos tulee, niin otetaan viite talteen muuttujaan painavinTahanAsti
. Lopuksi palautetaan muuttujan arvo eli viite henkilöolioon.
Tehdään lisäys edelliseen pääohjelmaan. Pääohjelma ottaa vastaan metodin palauttaman viitteen muuttujaan painavin
.
public static void main(String[] args) { PainonvartijaYhdistys painonVartija = new PainonvartijaYhdistys("Kumpluan paino", 25); // .. Henkilo painavin = painonVartija.suurinPainoindeksinen(); System.out.print("suurin painoindeksinen jäsen: " + painavin.getNimi()); System.out.println(" painoindeksi " + String.format("%.2f", painavin.painoIndeksi())); }
Tulostuu:
suurin painoindeksinen jäsen: Petri painoindeksi 37,42
Edellisessä esimerkissä metodi palautti yhden painonVartija-olion sisältämistä Henkilo-olioista. On myös mahdollista, että metodi palauttaa kokonaan uuden olion. Seuraavassa yksinkertainen laskuri, jolla on metodi kloonaa
, jonka avulla laskurista voidaan tehdä klooni, eli uusi laskurio-olio, jolla on luomishetkellä sama arvo kuin kloonattavalla laskurilla:
public Laskuri { private int arvo; public Laskuri() { this(0); } public Laskuri(int alkuarvo) { this.arvo = alkuarvo; } public void kasvata() { this.arvo++; } public String toString() { return "arvo: " + arvo; } public Laskuri kloonaa() { // luodaan uusi laskuriolio, joka saa alkuarvokseen kloonattavan laskurin arvon Laskuri klooni = new Laskuri(this.arvo); // palautetaan klooni kutsujalle return klooni; } }
Seuraavassa käyttöesimerkki:
Laskuri laskuri = new Laskuri(); laskuri.kasvata(); laskuri.kasvata(); System.out.println(laskuri); // tulostuu 2 Laskuri klooni = laskuri.kloonaa(); System.out.println(laskuri); // tulostuu 2 System.out.println(klooni); // tulostuu 2 laskuri.kasvata(); laskuri.kasvata(); laskuri.kasvata(); laskuri.kasvata(); System.out.println(laskuri); // tulostuu 6 System.out.println(klooni); // tulostuu 2 klooni.kasvata(); System.out.println(laskuri); // tulostuu 6 System.out.println(klooni); // tulostuu 3
Kloonattavan ja kloonin arvo on siis kloonauksen tapahduttua sama. Kyseessä on kuitenkin kaksi erillistä olioa, eli jatkossa kun toista laskureista kasvatetaan, ei kasvatus vaikuta toisen arvoon millään tavalla.
Vastaavasti myös Tehdas
-olio voisi luoda ja palauttaa uusia Auto
-olioita. Alla on hahmoteltu tehtaan runkoa -- tehdas tietää myös luotavien autojen merkin.
public class Tehdas { private String merkki; public Tehdas(String merkki) { this.merkki = merkki; } public Auto tuotaAuto() { return new Auto(this.merkki); } }
Tehtäväpohjan mukana tulee aiemmin esitelty luokka Paivays
, jossa päivämäärä talletetaan oliomuuttujien vuosi
, kuukausi
, ja paiva
avulla:
public class Paivays { private int paiva; private int kuukausi; private int vuosi; public Paivays(int paiva, int kuukausi, int vuosi) { this.paiva = paiva; this.kuukausi = kuukausi; this.vuosi = vuosi; } public String toString() { return this.paiva + "." + this.kuukausi + "." + this.vuosi; } public boolean aiemmin(Paivays verrattava) { // ensin verrataan vuosia if (this.vuosi < verrattava.vuosi) { return true; } // jos vuodet ovat samat, verrataan kuukausia if (this.vuosi == verrattava.vuosi && this.kuukausi < verrattava.kuukausi) { return true; } // vuodet ja kuukaudet samoja, verrataan päivää if (this.vuosi == verrattava.vuosi && this.kuukausi == verrattava.kuukausi && this.paiva < verrattava.paiva) { return true; } return false; } }
Tässä tehtäväsarjassa laajennetaan luokkaa.
Toteuta metodi public void etene()
, joka siirtää päiväystä yhdellä päivällä. Tässä tehtävässä oletetaan, että jokaisessa kuukaudessa on 30 päivää. Huom! Sinun tulee tietyissä tilanteissa muuttaa kuukauden ja vuoden arvoa.
Toteuta metodi public void etene(int montakoPaivaa)
, joka siirtää päiväystä annetun päivien määrän verran. Käytä apuna edellisessä tehtävässä toteutettua metodia etene()
.
Lisätään Paivays
-olioon mahdollisuus edistää aikaa. Tee oliolle metodi Paivays paivienPaasta(int paivia)
, joka luo uuden Paivays
-olion, jonka päiväys on annetun päivien lukumäärän verran suurempi kuin oliolla, jolle sitä kutsuttiin. Voit edelleen olettaa, että jokaisessa kuukaudessa on 30 päivää. Huomaa, että vanhan päiväysolion on pysyttävä muuttumattomana!
Koska metodissa on luotava uusi olio, tulee rungon olla suunnilleen seuraavanlainen:
public Paivays paivienPaasta(int paivia) { Paivays uusiPaivays = new Paivays( ... ); // tehdään jotain... return uusiPaivays; }
Ohessa on esimerkki metodin toiminnasta.
public static void main(String[] args) { Paivays pvm = new Paivays(13, 2, 2015); System.out.println("Tarkistellun viikon perjantai on " + pvm); Paivays uusiPvm = pvm.paivienPaasta(7); for (int i = 1; i <= 7; ++i) { System.out.println("Perjantai " + i + " viikon kuluttua on " + uusiPvm); uusiPvm = uusiPvm.paivienPaasta(7); } System.out.println("Päivämäärä 790:n päivän päästä tarkistellusta perjantaista on ... kokeile itse!"); // System.out.println("Kokeile " + pvm.paivienPaasta(790)); }
Ohjelma tulostaa:
Tarkistellun viikon perjantai on 13.2.2015 Perjantai 1 viikon kuluttua on 20.2.2015 Perjantai 2 viikon kuluttua on 27.2.2015 Perjantai 3 viikon kuluttua on 4.3.2015 Perjantai 4 viikon kuluttua on 11.3.2015 Perjantai 5 viikon kuluttua on 18.3.2015 Perjantai 6 viikon kuluttua on 25.3.2015 Perjantai 7 viikon kuluttua on 2.4.2015 Päivämäärä 790:n päivän päästä tarkistellusta perjantaista on ... kokeile itse!
Huom! Sen sijaan, että muuttaisimme vanhan olion tilaa
palautamme uuden olion. Kuvitellaan, että Paivays
-luokalle on
olemassa metodi edista
, joka toimii vastaavasti kuin ohjelmoimamme
metodi, mutta se muuttaa vanhan olion tilaa.
Tällöin seuraava koodin pätkä tuottaisi ongelmia.
Paivays nyt = new Paivays(13, 2, 2015); Paivays viikonPaasta = nyt; viikonPaasta.edista(7); System.out.println("Nyt: " + nyt); System.out.println("Viikon päästä: " + viikonPaasta);
Ohjelman tulostus olisi seuraavanlainen:
Nyt 20.2.2015 Viikon päästä 20.2.2015
Tämä johtuu siitä, että tavallinen sijoitus kopioi ainoastaan viitteen olioon. Siis itse asiassa ohjelman oliot nyt
ja viikonPaasta
viittavaat yhteen ja samaan Paivays
-olioon.
Jatketaan luokan Päiväys laajentamista. Tämä tehtävä ei riipu edellisestä tehtävästä, saat tehtäväpohjan mukana Paivays-luokan jossa ei ole edellisen tehtävän lisäyksiä.
Lisää päiväykselle metodi public int erotusVuosissa(Paivays verrattava)
, jonka avulla saadaan selville päiväyksen ja verrattavan päiväyksen ero vuosissa. Huomioi seuraavat:
Seuraava pääohjelma demonstroi metodin käyttöä:
public class Paaohjelma { public static void main(String[] args) { Paivays eka = new Paivays(24, 12, 2009); Paivays toka = new Paivays(1, 1, 2011); Paivays kolmas = new Paivays(25, 12, 2010); System.out.println(toka + " ja " + eka + " ero vuosissa: " + toka.erotusVuosissa(eka)); System.out.println(kolmas + " ja " + eka + " ero vuosissa: " + kolmas.erotusVuosissa(eka)); System.out.println(toka + " ja " + kolmas + " ero vuosissa: " + toka.erotusVuosissa(kolmas)); } }
Tulos näyttää seuraavalta:
1.1.2011 ja 24.12.2009 ero vuosissa: 2 25.12.2010 ja 24.12.2009 ero vuosissa: 1 1.1.2011 ja 25.12.2010 ero vuosissa: 1
Vuosien laskenta ei edellisessä versiossa ollut vielä kovin tarkkaa. Esim. 1.1.2011 ja 25.12.2010 välillä ilmoitettiin olevan vuoden ero. Tarkennetaan metodin toiminta sellaiseksi, että se osaa laskea vuodet kunnolla. Laske erotukseen mukaan vain täydet vuodet. Eli vaikka päiväysten ero olisi 1 vuosi ja 364 päivää, ilmoittaa metodi eroksi vuoden.
Metodin tämänkin version tarvitsee toimia ainoastaan siten, että parametriksi annettava päivämäärä on aiempi kuin se päivämäärä jolle metodia kutsutaan.
Edellisen esimerkin tulos on nyt:
1.1.2011 ja 24.12.2009 ero vuosissa: 1 25.12.2010 ja 24.12.2009 ero vuosissa: 1 1.1.2011 ja 25.12.2010 ero vuosissa: 0
Laitetaan metodi toimimaan samoin riippumatta onko parametrina annettava päiväys myöhempi vai aiempi kuin päiväys mille metodia kutsutaan. Esimerkkipääohjelma:
public class Paaohjelma { public static void main(String[] args) { Paivays eka = new Paivays(24, 12, 2009); Paivays toka = new Paivays(1, 1, 2011); Paivays kolmas = new Paivays(25, 12, 2010); System.out.println(eka + " ja " + toka + " ero vuosissa: " + toka.erotusVuosissa(eka)); System.out.println(toka + " ja " + eka + " ero vuosissa: " + eka.erotusVuosissa(toka)); System.out.println(eka + " ja " + kolmas + " ero vuosissa: " + kolmas.erotusVuosissa(eka)); System.out.println(kolmas + " ja " + eka + " ero vuosissa: " + eka.erotusVuosissa(kolmas)); System.out.println(kolmas + " ja " + toka + " ero vuosissa: " + toka.erotusVuosissa(kolmas)); System.out.println(toka + " ja " + kolmas + " ero vuosissa: " + kolmas.erotusVuosissa(toka)); } }
24.12.2009 ja 1.1.2011 ero vuosissa: 1 1.1.2011 ja 24.12.2009 ero vuosissa: 1 24.12.2009 ja 25.12.2010 ero vuosissa: 1 25.12.2010 ja 24.12.2009 ero vuosissa: 1 1.1.2011 ja 25.12.2010 ero vuosissa: 0 25.12.2010 ja 1.1.2011 ero vuosissa: 0
Lisäsimme aiemmin henkilölle oliomuuttujaksi syntymäpäivän kertova Paivays-olio. Samalla huomattiin, että oliomuuttuja ika
kannattaa poistaa sillä iän pystyy laskemaan päiväyksen ja syntymäpäivän avulla.
Toteuta metodi ika
joka palauttaa henkilön iän.
Huom: edellisessä tehtävässä lisättiin luokalle Paivays
metodi public int erotusVuosissa(Paivays verrattava)
. Kannattaa kopioida metodi tässä tehtävässä olevaan luokkaan, se helpottaa tehtävän tekemistä oleellisesti!
import java.util.Calendar; public class Henkilo { private String nimi; private Paivays syntymaPaiva; public Henkilo(String nimi, int pp, int kk, int vv) { this.nimi = nimi; this.syntymaPaiva = new Paivays(pp, kk, vv); } public int ika() { // laske henkilön ikä syntymäpäivän ja tämän päivän perusteella // tämä päivä saadaan selville seuraavasti // Calendar.getInstance().get(Calendar.DATE); // Calendar.getInstance().get(Calendar.MONTH) + 1; // tammikuun numero on 0 joten lisätään 1 // Calendar.getInstance().get(Calendar.YEAR); return -1; } public String getNimi() { return this.nimi; } public String toString() { return this.nimi +", syntynyt "+ this.syntymaPaiva; } }
Voit testata Henkilöä seuraavalla pääohjelmalla. Lisää myös itsesi ohjelmaan ja varmista että ikäsi tulostuu oikein.
public class Main { public static void main(String[] args) { Henkilo joni = new Henkilo("Joni", 15, 1, 1993); Henkilo leo = new Henkilo("Leo", 1, 1, 1990); System.out.println(joni.getNimi() + " ikä " + joni.ika() + " vuotta"); System.out.println(leo.getNimi() + " ikä " + leo.ika() + " vuotta"); } }
Tulostus:
Joni ikä 22 vuotta Leo ikä 25 vuotta
Tee henkilölle metodi jonka avulla se vertaa ikäänsä parametrina annettuun henkilöön. Jos henkilö on vanhempi eli syntynyt aiemmin, palauttaa metodi true ja muuten false.
public class Henkilo { // ... public boolean vanhempiKuin(Henkilo verrattava) { // vertaa henklöiden ikiä käyttäen henkilöiden syntymäpäivää } }
Ja testaa laajennettua Henkilö-luokkaa esim. seuraavasti:
public class Main { public static void main(String[] args) { Henkilo pekka = new Henkilo("Pekka", 15, 2, 1983); Henkilo martin = new Henkilo("Martin", 1, 3, 1983); System.out.println(martin.getNimi() + " vanhempi kuin " + pekka.getNimi() + ": " + martin.vanhempiKuin(pekka)); System.out.println(pekka.getNimi() + " vanhempi kuin " + martin.getNimi() + ": " + pekka.vanhempiKuin(martin)); } }
Tulostus:
Martin vanhempi kuin Pekka: false Pekka vanhempi kuin Martin: true
Tee Henkilo-luokalle kaksi uutta konstruktoria:
public Henkilo(String nimi, Paivays syntymapaiva)
- jossa konstruktori käyttää annettua Paivays-oliota syntymäpäivänäpublic Henkilo(String nimi)
- jossa konstruktori määrittää syntymäpäiväksi tämänhetkisen päivänTestaa uusia konstruktoreja esim. seuraavasti:
public class Main { public static void main(String[] args) { Henkilo pekka = new Henkilo("Pekka", new Paivays(15, 2, 1983)); Henkilo sepe = new Henkilo("Sepe"); System.out.println(pekka); System.out.println(sepe); } }
Esimerkkitulostus:
Pekka, syntynyt 15.2.1983 Sepe, syntynyt 13.2.2015
Huom: jälkimmäinen rivi riippuu päivämäärästä, jolloin koodi ajetaan!
MUISTUTUS kun lisäät ohjelmaasi ArrayList:in, Scanner:in tai Random:in ei Java tunnista luokkaa ellet "importoi" sitä lisäämällä ohjelmatiedoston alkuun:
import java.util.ArrayList; // importoi ArrayListin import java.util.*; // importoi kaikki java.util:sissa olevat työkalut, mm. ArrayListin, Scannerin ja Randomin
Tehtävässä tehdään puhelinmuistio.
Tee ensin luokka Henkilo
Luokan pitää toimia seuraavan esimerkin osoittamalla tavalla:
public static void main(String[] args) { Henkilo pekka = new Henkilo("Pekka Mikkola", "040-123123"); System.out.println(pekka.haeNimi()); System.out.println(pekka.haeNumero()); System.out.println(pekka); pekka.vaihdaNumeroa("050-333444"); System.out.println(pekka); }
Tulostuu:
Pekka Mikkola 040-123123 Pekka Mikkola puh: 040-123123 Pekka Mikkola puh: 050-333444
Tee siis luokalle
public String toString()
, joka palauttaa henkilön merkkijonoesityksen (yo. esimerkin tapaan muotoiltuna)public String haeNimi()
, joka palauttaa nimenpublic String haeNumero()
, joka palauttaa puhelinnumeronpublic void vaihdaNumeroa(String uusiNumero)
, joka muuttaa henkilön puhelinnumeroaTee luokka Puhelinmuistio
joka tallettaa sisällään olevaan ArrayListiin Henkilo
-olioita. Tässä vaiheessa luokalle tehdään seuraavat metodit:
public void lisaa(String nimi, String numero)
luo Henkilo
-olion ja lisää sen puhelinmuistion ArrayListiin.public void tulostaKaikki()
, tulostaa puhelinmuistion sisällönEsimerkki muistion toiminnasta:
public static void main(String[] args) { Puhelinmuistio muistio = new Puhelinmuistio(); muistio.lisaa("Pekka Mikkola", "040-123123"); muistio.lisaa("Antti Laaksonen", "045-456123"); muistio.lisaa("Juhana Laurinharju", "050-222333"); muistio.tulostaKaikki(); }
Ohjelman tulostus oikein toteutetuilla luokilla on:
Pekka Mikkola puh: 040-123123 Antti Laaksonen puh: 045-456123 Juhana Laurinharju puh: 050-222333
Tehdään puhelinmuistiolle metodi public String haeNumero(String nimi)
, joka palauttaa parametrina annetun henkilön numeron. Jos henkilö ei ole muistiossa, palautetaan merkkijono "numero ei tiedossa". Esimerkki metodin toiminnasta:
public static void main(String[] args) { Puhelinmuistio muistio = new Puhelinmuistio(); muistio.lisaa("Pekka Mikkola", "040-123123"); muistio.lisaa("Antti Laaksonen", "045-456123"); muistio.lisaa("Juhana Laurinharju", "050-222333"); String numero = muistio.haeNumero("Pekka Mikkola"); System.out.println(numero); numero = muistio.haeNumero("Martti Tienari"); System.out.println(numero); }
Tulostuu:
040-123123 numero ei tiedossa
Maksukortti-tehtävässä käytimme rahamäärän tallettamiseen double-tyyppistä oliomuuttujaa. Todellisissa sovelluksissa näin ei kannata tehdä, sillä kuten jo olemme nähneet, doubleilla laskenta ei ole tarkkaa. Onkin järkevämpää toteuttaa rahamäärän käsittely oman luokkansa avulla. Seuraavassa on luokan runko:
public class Raha { private final int euroa; private final int senttia; public Raha(int euroa, int senttia) { this.euroa = euroa; this.senttia = senttia; } public int eurot() { return euroa; } public int sentit() { return senttia; } public String toString() { String nolla = ""; if (senttia <= 10) { nolla = "0"; } return euroa + "." + nolla + senttia + "e"; } }
Määrittelyssä pistää silmään oliomuuttujien määrittelyn yhteydessä käytetty sana final
, tällä saadaan aikaan se, että oliomuuttujien arvoa ei pystytä muuttamaan sen jälkeen kun ne on konstruktorissa asetettu. Raha-luokan oliot ovatkin muuttumattomia eli immutaabeleita, eli jos halutaan esim. kasvattaa rahamäärää, on luotava uusi olio, joka kuvaa kasvatettua rahasummaa.
Luomme seuraavassa muutaman operaation rahojen käsittelyyn.
Tee ensin metodi public Raha plus(Raha lisattava)
, joka palauttaa uuden raha-olion, joka on arvoltaan yhtä suuri kuin se olio jolle metodia kutsuttiin ja parametrina oleva olio yhteensä.
Metodin runko on seuraavanlainen:
public Raha plus(Raha lisattava) { Raha uusi = new Raha(...); // luodaan uusi Raha-olio jolla on oikea arvo // palautetaan uusi Raha-olio return uusi; }
Seuraavassa esimerkkejä metodin toiminnasta
Raha a = new Raha(10,0); Raha b = new Raha(5,0); Raha c = a.plus(b); System.out.println(a); // 10.00e System.out.println(b); // 5.00e System.out.println(c); // 15.00e a = a.plus(c); // HUOM: tässä syntyy uusi Raha-olio, joka laitataan "a:n langan päähän" // vanha a:n langan päässä ollut 10 euroa häviää ja Javan roskien kerääjä korjaa sen pois System.out.println(a); // 25.00e System.out.println(b); // 5.00e System.out.println(c); // 15.00e
Tee metodi public boolean vahemman(Raha verrattava)
, joka palauttaa true jos raha-olio jolle metodia kutsutaan on arvoltaan pienempi kuin raha-olio, joka on metodin parametrina.
Raha a = new Raha(10, 0); Raha b = new Raha(3, 0); Raha c = new Raha(5, 0); System.out.println(a.vahemman(b)); // false System.out.println(b.vahemman(c)); // true
Tee metodi public Raha miinus(Raha vahentaja)
, joka palauttaa uuden raha-olion, jonka arvoksi tulee sen olion jolle metodia kutsuttiin ja parametrina olevan olion arvojen erotus. Jos erotus olisi negatiivinen, tulee luotavan raha-olion arvoksi 0.
Seuraavassa esimerkkejä metodin toiminnasta
Raha a = new Raha(10, 0); Raha b = new Raha(3, 50); Raha c = a.miinus(b); System.out.println(a); // 10.00e System.out.println(b); // 3.50e System.out.println(c); // 6.50e c = c.miinus(a); // HUOM: tässä syntyy uusi Raha-olio, joka laitataan "c:n langan päähän" // vanha c:n langan päässä ollut 6.5 euroa häviää ja Javan roskien kerääjä korjaa sen pois System.out.println(a); // 10.00e System.out.println(b); // 3.50e System.out.println(c); // 0.00e
Javan String-oliot ovat Raha-luokan olioiden tyyliin muuttumattomia, eli immutaabelena. Jos esim. merkkijonon perään katenoidaan eli liitetään +-operaatiolla uusi merkkijono, ei alkuperäistä merkkijonoa pidennetä vaan syntyy uusi merkkijono-olio:
String jono = "koe"; jono + "häntä"; System.out.println(jono); // koe
Merkkijonoa ei siis voi muuttaa, mutta voimme ottaa katenoimalla syntyvän uuden merkkijonon talteen vanhaan muuttujaan:
String jono = "koe"; jono = jono + "häntä"; // tai jono += "häntä"; System.out.println(jono); // koehäntä
Nyt siis muuttuja jono
viittaa uuteen merkkijono-olioon, joka luotiin yhdistämällä muuttujan aiemmin viittaama merkkijono "koe" ja merkkijono "häntä". Merkkijono-olioon "koe" ei enää viitata.
Olemme käyttäneet kurssin aikana lukemattomia kertoja ArrayList:ejä erilaisten olioiden säilömiseen. ArrayList on helppokäyttöinen sillä se tarjoaa paljon valmiita työvälineitä jotka helpottavat ohjelmoijan elämää: muun muassa automaattisen listan kasvatuksen, jonka ansioista listalta ei lopu tila kesken (ellei lista kasva niin suureksi että se käyttää loppuun ohjelmalle varatun muistimäärän).
ArrayListin helppokäyttöisyydesta huolimatta ohjelmissa on joskus tarvetta ArrayListin esi-isälle eli taulukolle.
Taulukko on olio, joka voidaan käsittää eräänlaisena järjestettynä lokerikkona arvoille. Taulukon pituus tai koko on lokerikon paikkojen lukumäärä, eli kuinka monta arvoa taulukkoon voi laittaa. Taulukon arvoja kutsutaan taulukon alkioiksi. ArrayLististä poiketen taulukon kokoa (eli sen alkioiden määrää) ei voi muuttaa, taulukon kasvattaminen vaatii siis aina uuden taulukon luomista ja vanhassa olevien alkioiden kopiointia uuteen.
Taulukon voi luoda kahdella eri tavalla. Tutustutaan ensin tapaan jossa taulukolle annetaan sisältö luomisen yhteydessä. Kolmen alkion kokonaislukutyyppinen taulukko määritellään seuraavasti:
int[] luvut = {100, 1, 42};
Taulukko-olion tyyppi merkitään int[]
, joka tarkoittaa taulukkoa, jonka alkiot ovat tyyppiä int
. Taulukko-olion nimi on esimerkissä luvut
ja se sisältää kolme lukua {100, 1, 42}
. Taulukko alustetaan lohkolla, jossa taulukkoon asetettavat arvot on esitelty pilkulla eriteltyinä.
Taulukon arvot voivat olla mitä tahansa aikaisemmin nähtyjä muuttujatyyppejä. Alla on esitelty ensin merkkijonoja sisältävä taulukko, jonka jälkeen esitellään liukulukuja sisältävä taulukko.
String[] merkkijonotaulukko = {"Matti P.", "Matti V."}; double[] liukulukutaulukko = {1.20, 3.14, 100.0, 0.6666666667};
Taulukon alkioihin viitataan indeksillä, joka on kokonaisluku. Indeksi kertoo alkion paikan taulukossa. Taulukon ensimmäinen alkio on paikassa nolla, seuraava kohdassa yksi ja niin edelleen. Taulukon tietyssä indeksissä olevaa arvoa tutkittaessa indeksi annetaan taulukko-olion nimen perään hakasulkeiden sisällä.
// indeksi 0 1 2 3 4 5 6 7 int[] luvut = {100, 1, 42, 23, 1, 1, 3200, 3201}; System.out.println(luvut[0]); // tulostaa luvun taulukon indeksistä 0, eli luvun 100 System.out.println(luvut[2]); // tulostaa luvun taulukon indeksistä 2, eli luvun 42
Yllä olevan taulukon koko (eli pituus) on 8.
Huomaat todennäköisesti että ArrayListin metodi get
käyttäytyy hyvin samalla tavalla kuin taulukon tietystä indeksistä haku. Taulukon kohdalla vain syntaksi, eli merkintätapa, on erilainen.
Yksittäisen arvon asettaminen taulukon tiettyyn paikkaan tapahtuu kuten arvon asetus tavalliseen muuttujaan, mutta taulukkoon asetettaessa paikka eli indeksi tulee kertoa. Indeksi kerrotaan hakasulkeiden sisällä.
int[] luvut = {100,1,42}; luvut[0] = 1; // asetetaan luku 1 indeksiin 0 luvut[1] = 101; // asetetaan luku 101 indeksiin 1 // luvut-taulukko on nyt {1,101,42}
Jos indeksillä osoitetaan taulukon ohi, eli alkioon jota ei ole olemassa, niin saadaan virheilmoitus ArrayIndexOutOfBoundsException, joka kertoo että indeksiä johon osoitimme ei ole olemassa. Taulukon ohi, eli indeksiin joka on pienempi kuin 0 tai suurempi tai yhtäsuuri kuin taulukon koko ei siis saa viitata.
Huomaamme, että taulukko on selvästi sukua ArrayList:ille. Aivan kuten listoilla, myös taulukossa alkiot ovat tietyssä paikassa!
Taulukko-olion koon saa selville kirjoittamalla koodiin taulukko.length
, huomaa että ilmauksessa ei tule käyttää sulkuja eli taulukko.length()
ei toimi!
Taulukon alkioiden läpikäynti on helppo toteuttaa while
-komennon avulla:
int[] luvut = {1, 8, 10, 3, 5}; int i = 0; while (i < luvut.length) { System.out.println(luvut[i]); i++; }
Esimerkissä käydään muuttujan i
avulla läpi indeksit 0, 1, 2, 3, ja 4, ja tulostetaan taulukon kussakin indeksissä olevan muuttujan arvo. Ensin siis tulostuu luvut[0]
, sitten luvut[1]
jne. Muuttujan i
kasvatus loppuu kun koko taulukko on käyty läpi, eli kun sen arvo on yhtäsuuri kuin taulukon pituus.
Taulukon läpikäynnissä ei ole aina todellista tarvetta taulukon indeksien luetteluun, vaan ainoa kiinnostava asia ovat taulukon arvot. Tällöin voidaan käyttää aiemmin tutuksi tullutta for-each-rakennetta arvojen läpikäyntiin. Nyt toistolauseen rungossa annetaan vain muuttujan nimi, johon kukin taulukon arvo asetetaan vuorollaan, ja taulukon nimi kaksoispisteellä erotettuna.
int[] luvut = {1,8,10,3,5}; for (int luku : luvut) { System.out.println(luku); }
String[] nimet = {"Juhana L.", "Matti P.", "Matti L.", "Pekka M."}; for (String nimi : nimet) { System.out.println(nimi); } }
Huom: for-each-tyylisellä läpikäynnillä taulukon alkioihin ei voi asettaa arvoja! Seuraavaksi nähtävällä for-lauseen toisella muodolla sekin onnistuu.
Olemme toistaiseksi käyttäneet toistolauseissa whileä tai for-lauseen ns. "for-each"-muotoa. Toistolauseesta for on olemassa myös toinen muoto, joka on kätevä erityisesti taulukoiden käsittelyn yhteydessä. Seuraavassa tulostetaan for-toistolauseen avulla luvut 0, 1 ja 2:
for (int i = 0; i < 3; i++) { System.out.println(i); }
Esimerkin for toimii täsmälleen samalla tavalla kuin alla oleva while:
int i = 0; // toistossa käytettävän muuttujan alustus while (i < 3) { // toistoehto System.out.println(i); i++; // toistossa käytettävän muuttujan päivitys }
for-komento, kuten yllä esitelty for (int i = 0; i < 3; i++)
sisältää kolme osaa: looppimuuttujien alustus; toistoehto; looppimuuttujien päivitys:
i
lauseella int i=0
. Ensimmäinen osa suoritetaan vain kerran, juuri for:in suorituksen alussa.i < 3
. Toistoehdon voimassaolo tarkastetaan ennen jokaista for:in toistokertaa. Toistoehto toimii täsmälleen samoin kuin while:n toistoehto.i++
suoritetaan aina kertaalleen forin koodilohkon suorituksen jälkeen.for on hieman while:ä selkeämpi tapa toteuttaa toistoja joissa toistojen määrä perustuu esim. laskurin kasvatukseen. Taulukkojen läpikäynnissä tilanne on yleensä juuri tämä. Seuraavassa tulostetaan taulukon luvut
sisältö for:illa
int[] luvut = {1, 3, 5, 9, 17, 31, 57, 105}; for(int i = 3; i < 7; i++) { System.out.println(luvut[i]); }
Forilla voidaan aloittaa läpikäynti luonnollisesti muualtakin kuin nollasta ja läpikäynti voi edetä "ylhäältä alas". Esimerkiksi taulukon paikoissa 6, 5, 4, ja 3 olevat alkiot voidaan tulostaa seuraavasti:
int[] luvut = {1, 3, 5, 9, 17, 31, 57, 105}; for(int i = 6; i>2 ; i--) { System.out.println(luvut[i]); }
Kaikkien taulukon alkioiden läpikäynti for:in avulla onnistuu seuraavasti:
int[] luvut = {1, 8, 10, 3, 5}; for (int i = 0; i < luvut.length; i++) { System.out.println(luvut[i]); }
Huomaa, että toistoehdossa i < luvut.length
verrataan looppimuuttujan arvoa taulukolta kysyttyyn pituuteen. Ehtoa ei kannata missään tapauksessa "kovakoodata" tyyliin i < 5
sillä yleensä taulukon pituudesta ei ole etukäteen varmuutta.
Taulukkoja voidaan käyttää metodin parametrina aivan kuten muitakin olioita. Huomaa, että kuten kaikkien olioiden tapauksessa, metodi saa parametrina viitteen taulukkoon, eli kaikki metodissa tapahtuvat taulukon sisältöön vaikuttavat muutokset näkyvät myös pääohjelmassa.
public static void listaaAlkiot(int[] kokonaislukuTaulukko) { System.out.println("taulukon alkiot ovat: "); for(int luku : kokonaislukuTaulukko) { System.out.print(luku + " "); } System.out.println(""); } public static void main(String[] args) { int[] luvut = {1, 2, 3, 4, 5}; listaaAlkiot(luvut); }
Kuten jo tiedämme, parametrin nimi metodin sisällä voi olla aivan vapaasti valittu, nimen ei tarvitse missään tapauksessa olla sama kuin kutsuvassa. Edellä taulukkoa kutsutaan metodin sisällä nimellä kokonaislukuTaulukko
, metodin kutsuja taas näkee saman taulukon luvut
-nimisenä.
Huom: tämän tehtävän metodi samoin kuin muutamien seuraavien tehtävien taulukkoa käsittelevät metodit ovat viikkojen 2 ja 3 tapaan static
eli staattisia metodeja. Karkeasti ottaen tämä johtuu siitä, että metodi ei liity mihinkään olioon, vaan saa kaiken datan jota se käyttää eli tässä tapauksessa taulukon, parametrina. Palaamme seuraavalla viikolla tarkemmin aiheeseen staattiset vs. olioihin liittyvät metodit.
Tee metodi public static int laskeTaulukonLukujenSumma(int[] taulukko)
, joka palauttaa taulukossa olevien lukujen summan.
Ohjelman runko on seuraava:
public class Main { public static void main(String[] args) { // Tässä voit testata metodia int[] taulukko = {5, 1, 3, 4, 2}; System.out.println(laskeTaulukonLukujenSumma(taulukko)); } public static int laskeTaulukonLukujenSumma(int[] taulukko) { // Kirjoita koodia tänne return 0; } }
Ohjelman tulostus on seuraava:
15
Tee metodi public static void tulostaTyylikkaasti(int[] taulukko)
, joka tulostaa taulukossa olevat luvut tyylikkäästi. Lukujen väliin tulee pilkku ja välilyönti. Viimeisen luvun jälkeen ei pilkkua tule.
Ohjelman runko on seuraava:
public class Main { public static void main(String[] args) { // Tässä voit testata metodia int[] taulukko = {5, 1, 3, 4, 2}; tulostaTyylikkaasti(taulukko); } public static void tulostaTyylikkaasti(int[] taulukko) { // Kirjoita koodia tänne } }
Ohjelman tulostus on seuraava:
5, 1, 3, 4, 2
Jos taulukon koko ei ohjelmassa ole aina sama, eli se riippuu esim. käyttäjän syötteestä, ei äsken esitelty taulukon luontitapa kelpaa. Taulukko on mahdollista luoda myös siten, että sen koko määritellään muuttujan avulla:
int alkioita = 99; int[] taulukko = new int[alkioita];
Yllä luodaan int-tyyppinen taulukko, jossa on 99 paikkaa. Tällä vaihtoehtoisella tavalla taulukon luominen tapahtuu siis kuten muidenkin olioiden luominen, eli new
-komennolla. Komentoa new
seuraa taulukon sisältämien muuttujien tyyppi, ja hakasuluissa taulukon koko.
int alkioita = 99; int[] taulukko = new int[alkioita]; //luodaan muuttujan alkioita sisältämän arvon kokoinen taulukko if (taulukko.length == alkioita) { System.out.println("Taulukon pituus on " + alkioita); } else { System.out.println("Jotain epätodellista tapahtui. Taulukon pituus on eri kuin " + alkioita); }
Seuraavassa esimerkissä on ohjelma, joka kysyy käyttäjältä lukujen määrän ja joukon lukuja. Tämän jälkeen ohjelma tulostaa luvut uudestaan samassa järjestyksessä. Käyttäjän antamat luvut tallennetaan taulukkoon.
System.out.print("Kuinka monta lukua? "); int lukuja = Integer.parseInt(lukija.nextLine()); int[] luvut = new int[lukuja]; System.out.println("Anna luvut:"); for(int i = 0; i < lukuja; i++) { luvut[i] = Integer.parseInt(lukija.nextLine()); } System.out.println("Luvut uudestaan:"); for(int i = 0; i < lukuja; i++) { System.out.println(luvut[i]); }
Eräs ohjelman suorituskerta voisi olla seuraavanlainen:
Kuinka monta lukua? 4 Anna luvut: 4 8 2 1 Luvut uudestaan: 4 8 2 1
Koska metodit voivat palauttaa olioita, voivat ne palauttaa myös taulukkoja. Eräs merkkijonotaulukon palauttava metodi on seuraavannäköinen -- huomaa että taulukkoihin voi aivan hyvin siis laittaa myös olioita.
public static String[] annaMerkkijonoTaulukko() { String[] opet = new String[3]; opet[0] = "Bonus"; opet[1] = "Ihq"; opet[2] = "Lennon"; return opet; } public static void main(String[] args) { String[] opettajat = annaMerkkijonoTaulukko(); for (String opettaja : opettajat) { System.out.println(opettaja); } }
Tee metodi public static int[] kopioi(int[] taulukko)
joka luo kopion parametrina saadusta taulukosta. Vihje: koska metodin on luotava taulukosta kopio, tulee metodin sisällä luoda uusi taulukko ja kopioida vanhan taulukon sisältö uudelle taulukolle alkio alkiolta.
Seuraavassa esimerkki metodin käytöstä (koodissa myös Arrays-luokan tarjoama kätevä apuväline taulukon sisällön tulostamiseen):
public static void main(String[] args) { int[] alkuperainen = {1, 2, 3, 4}; int[] kopio = kopioi(alkuperainen); // muutetaan kopioa kopio[0] = 99; // tulostetaan molemmat System.out.println("alkup: " + Arrays.toString(alkuperainen)); System.out.println("kopio: " + Arrays.toString(kopio)); }
Kuten tulostuksesta huomaa, ei kopioon tehty muutos vaikuta alkuperäiseen:
alkup: [1, 2, 3, 4] kopio: [99, 2, 3, 4]
Tee metodi public static int[] kaanna(int[] taulukko)
joka luo käänteisessä järjestyksessä olevan kopion parametrinaan saamastaan taulukosta.
Eli jos parametrina on taulukko jossa esim. luvut 5, 6, 7 palauttaa metodi uuden taulukon jonka sisältönä luvut 7, 6, 5. Parametrina oleva taulukko ei saa muuttua.
Seuraavassa esimerkki metodin käytöstä:
public static void main(String[] args) { int[] alkuperainen = {1, 2, 3, 4}; int[] kaannetty = kaanna(alkuperainen); // tulostetaan molemmat System.out.println("alkup: " +Arrays.toString(alkuperainen)); System.out.println("käännetty: " +Arrays.toString(kaannetty)); }
Tulostuksesta pitäisi selvitä, että alkuperäinen taulukko on muuttumaton:
alkup: [1, 2, 3, 4] käännetty: [4, 3, 2, 1]
Kirjoita metodi public static void tulostaTaulukkoTahtina(int[] taulukko)
, joka tulostaa jokaista taulukossa olevaa lukua vastaavan pituisen rivin tähtiä.
Ohjelman runko on seuraava:
public class Main { public static void main(String[] args) { // Tässä voit testata metodia int[] taulukko = {5, 1, 3, 4, 2}; tulostaTaulukkoTahtina(taulukko); } public static void tulostaTaulukkoTahtina(int[] taulukko) { // Kirjoita tulostuskoodi tänne } }
Edellisen esimerkin mukaisella syötteellä ohjelman tulostus on seuraava:
***** * *** **** **
Eli koska taulukon nollannessa paikassa on luku 5, tulee ensimmäiselle riville 5 tähteä. Seuraavalla 1 tähti jne.
Luodaan ohjelma tähtitaivaan tulostamiseen. Tähtitaivaan tähtien määrä kerrotaan tiheyden avulla. Esimerkiksi jos tähtitaivaan tiheys on 0.2
, on noin 20% tähtitaivaasta peitettynä tähdillä. Pääset harjoittelemaan siis myös satunnaislukujen käyttöä.
Käytä tähtien tulostamiseen *
-merkkiä. Alla on esimerkki lopullisen Tahtitaivas
-luokan käytöstä ja käyttöä vastaavasti tulostuksesta.
Tahtitaivas tahtitaivas = new Tahtitaivas(0.1, 39, 10); tahtitaivas.tulosta(); System.out.println("Tähtiä: " + tahtitaivas.tahtiaViimeTulostuksessa()); System.out.println(""); tahtitaivas = new Tahtitaivas(0.2, 15, 6); tahtitaivas.tulosta(); System.out.println("Tähtiä: " + tahtitaivas.tahtiaViimeTulostuksessa());
* * * * * * * ** * * * * * * * * * * * * * * * * * * * ** * * * * * * Tähtiä: 36 * * * * * * * * * * * * * * * * * ** ** * Tähtiä: 22
Huom! tehtävissä kannattaa käyttää for
-lauseketta. Vaikka edellinen luku puhuukin sisäkkäisistä toistolauseista, tässä tehtävässä "sisempi" toisto piilotetaan metodin sisälle.
Luo luokka Tahtitaivas
, jolla on kolme oliomuuttujaa: tiheys (double
), leveys (int
), ja korkeus (int
). Luo luokalle myös kolme konstruktoria:
public Tahtitaivas(double tiheys)
Luo tähtitaivas-olion, jolla on parametrina annettu tiheys, leveys saa arvon 20
, korkeus saa arvon 10
.public Tahtitaivas(int leveys, int korkeus)
Luo tähtitaivas-olion, jolla on parametrina annetut leveys ja korkeus, tiheys saa arvon 0.1
.public Tahtitaivas(double tiheys, int leveys, int korkeus)
Luo tähtitaivas-olion, jolla on parametrina annetut tiheys, leveys ja korkeus.Lisää luokalle Tahtitaivas
metodi tulostaRivi
, joka tulostaa yhden rivin. Rivin leveyden määrää oliomuuttuja leveys
. Oliomuuttuja tiheys
kertoo todennäköisyyden tähdelle. Arvo jokaisen merkin kohdalla tulostetaanko tähti vai ei Random
-luokan nextDouble
-metodin avulla.
Testaa ohjelmaasi, esimerkkinä seuraava kutsu ja esimerkkitulostus.
Tahtitaivas tahtitaivas = new Tahtitaivas(0.1); tahtitaivas.tulostaRivi();
* * *
Luo Tahtitaivas
-luokalle metodi tulosta
, joka tulostaa koko tähtitaivaan. Käytä tässä hyödyksesi aiempaa tulostaRivi
-metodia.
Tahtitaivas tahtitaivas = new Tahtitaivas(8, 4); tahtitaivas.tulosta();
* * *
Lisää Tahtitaivas
-luokalle oliomuuttuja tahtiaViimeTulostuksessa (int
) ja metodi tahtiaViimeTulostuksessa()
, joka palauttaa viime tulostuksessa tulostuneiden tähtien lukumäärän. Toteuta ohjelmaasi tähtien laskeminen.
Tahtitaivas tahtitaivas = new Tahtitaivas(8, 4); tahtitaivas.tulosta(); System.out.println("Tähtiä: " + tahtitaivas.tahtiaViimeTulostuksessa()); System.out.println(""); tahtitaivas.tulosta(); System.out.println("Tähtiä: " + tahtitaivas.tahtiaViimeTulostuksessa());
* Tähtiä: 1 * * * Tähtiä: 3