Tämä ei ole uusin versio kurssista. Katso myös Ohjelmoinnin MOOC 2019: https://ohjelmointi-19.mooc.fi.
Tehtävät

Johdanto

Ohjelmointi on nykyajan käsityöläistaito ja ohjelmointia työkseen tai harrastuksekseen tekevien määrä on jatkuvasti kasvussa. Ohjelmistojen ja ohjelmien lähdekoodin tallentamispalvelua tarjoava GitHub arvioi vuonna 2016 palvelun käyttäjien määräksi yli 20 miljoonaa, mutta -- koska kaikki ohjelmoijat eivät käytä kyseistä palvelua -- ohjelmoijia on todennäköisesti hyvin paljon enemmän. Tämän modernin käsityöläistaidon tarve työelämässä on akuutti -- esimerkiksi Tivi uutisoi 2016 aiheesta otsikolla "It-osaaja pääsee töihin vaikka heti". Samalla tiede perustuu yhä enemmän datan analyysissä käytettäviin ohjelmistoihin sekä ohjelmistoalan innovaatioihin. Esimerkiksi meteorologit, fyysikot ja kemistit käyttävät ohjelmistoja ja ohjelmoivat työssään. Myös kasvatustiede ja opetusala yleisemmin hyödyntää yhä enemmän digitalisaation tuomia mahdollisuuksia.

Ohjelmoinnin opettelua harkitseva tietää harvoin mikä kaikki yhteiskunnassamme nojautuu ohjelmoijien tuottamiin ohjelmistoihin. Ilman ohjelmointia yhteydenpito, kaupankäynti, matkustaminen, terveydenhuolto ja niin edelleen olisivat yksinkertaisesti heikommalla tasolla. Puhelimet eivät toimisi, verkkopankkeja saatikka pankki- ja luottokortteja ei olisi, matkojen varaaminen ja henkilöasiakirjojen käyttäminen ei onnistuisi verkon yli, lääketeollisuus ei pystyisi käymään suuria massoja dataa läpi parannuskeinoja etsimisessä, tiedon hakeminen tapahtuisi sana- ja tietokirjoista ja niin edelleen. Margaret Hamilton ei olisi myöskään koskaan kirjoittanut ihmisiä kuuhun vienyttä ohjelmaa.

Tällä kurssilla otat ensiaskeleet ohjelmointiin. Opit kirjoittamaan ohjelmia ja ymmärtämään niiden toimintaa. Kurssin jälkeen katsot yhteiskunnan palveluita myös ohjelmoijan näkökulmasta ja tiedät, että palvelut toimivat (tai ovat rikki!) ohjelmistojen ansiosta.

Ensimmäisen osan tavoitteet

Ensimmäisen osan jälkeen tunnet ohjelmoinnin peruskäsitteitä sekä niiden toimintaa. Tunnet muuttujat, ehtolauseet, sekä toistolauseet ja osaat kirjoittaa näitä käyttäviä ohjelmia. Tunnet loogiset operaatiot ja ja tai. Ymmärrät ohjelman suoritusjärjestyksen, ja osaat kirjoittaa ohjelmia, jotka lukevat käyttäjältä syötettä. Osaat käsitellä käyttäjän kirjoittamaa syötettä ja tehdä sen perusteella laskentaa.

Ohjelma ja lähdekoodi

Ohjelma on järjestetty joukko käskyjä, joita tietokone noudattaa yksi kerrallaan.

Nykypäivänä ohjelmoijat eivät ohjelmoi tietokoneen noudattamaksi tarkoitettuja käskyjä käyttäen. Ohjelmoinnissa käytetään ihmisen kirjoitettavaksi ja luettavaksi tarkoitettua ohjelmointikieltä, kuten tällä kurssilla käytettyä Javaa. Ohjelmoijan kirjoittamaa ohjelmakoodia kutsutaan lähdekoodiksi. Lähdekoodi käännetään ohjelmointikielen- ja ohjelmointiympäristön tarjoamien työvälineiden avulla konekieliseksi ohjelmaksi, jonka käskyjä tietokone noudattaa.

Lähdekoodi koostuu lauseista (statement) ja lausekkeista (expression), joita Java-kielessä voidaan lukea rivi riviltä ylhäältä alaspäin ja vasemmalta oikealle. Esimerkiksi tekstin "Hei maailma" tulostuksessa käytetään Java-ohjelmointikielellä lausetta:

System.out.println("Hei maailma");

Lause System.out.println on Java-ohjelmointikielen valmiiksi tarjoama komento, jota käytetään merkkijonon tulostamiseen. Komento käytännössä käskee tietokonetta tulostamaan sille sulkeiden sisällä hipsuissa annetun merkkijonon. Komennon pääte ln on lyhenne sanasta line, eli komentoa käyttämällä merkkijonon jälkeen tulostetaan myös rivinvaihto.

Lauseen loppuun kirjoitetaan puolipiste ;.

Ohjelmarunko

Java-ohjelmat vaativat toimiakseen kurssin aikana tutuksi tulevan rungon. Ohjelman runko on seuraavanlainen.

public class Esimerkki {
    public static void main(String[] args) {

        // Tänne kirjoitetaan ohjelman käyttämät lauseet
        System.out.println("Tulostettava teksti");

    }
}

Ohjelmoidessa yhdenkin merkin puuttuminen voi johtaa virhetilanteeseen. Ohjelmoija saattaa vahingossa esimerkiksi syöttää pilkun pisteen sijaan, kirjoittaa vaikkapa printin sanan println sijaan, tai jättää tulostettavasta merkkijonosta hipsut pois. Jokainen em. virheistä johtaa tilanteeseen, missä ohjelman suoritus ei onnistu.

public class Esimerkki { public static void main(String[] args) { // Tänne kirjoitetaan ohjelman käyttämät lauseet System.out.println("Tulostettava teksti"); } }
public class Esimerkki { public static void main(String[] args) { // Tänne kirjoitetaan ohjelman käyttämät lauseet // MARK } }

Ohjelmarunko sisältää Java-ohjelmointikielelle oleellisia osia. Eri ohjelmointikielillä on erilainen ohjelmarunko. Tulemme myöhemmin tutustumaan tarkemmin sanojen public class ja public static void merkitykseen.

Ohjelman suoritus alkaa riviä public static void main(String[] args) { seuraavalta riviltä ja päättyy sulkevaan aaltosulkuun }. Lauseet suoritetaan yksi kerrallaan. Tällä hetkellä ainoa suoritettava lause on System.out.println("Tulostettava teksti");, mikä tulostaa tekstin "Tulostettava teksti".

Jatkossa materiaalin esimerkeissä ei aina erikseen näytetä ohjelmarunkoa, mutta voit olettaa, että se tarvitaan.

Alla on kurssin ensimmäinen ohjelmointitehtävä. Ohjelmointitehtävät tehdään kurssilla käytössä olevassa Test My Code -ohjelmointiympäristössä, mutta tehtävänannot ovat kurssimateriaalissa. Saat tehtävänannon auki klikkaamalla alla olevaa otsikkoa "Ada Lovelace":

Ohjelmoinnin aloittaminen

Ohjelmoinnin aloittamiseen tarvitset seuraavat asiat.

  1. Käyttäjätunnuksen kurssilla käytettyyn TMC-järjestelmään.
  2. Javan (Java JDK).
  3. NetBeans with TMC-ohjelmointiympäristön.

Ohjeistus oleellisten työvälineiden asentamiseen sekä kurssilla tarvittavan käyttäjätunnuksen luomiseen löytyy osoitteesta https://materiaalit.github.io/tmc-asennus/netbeans/.

Huom! Jos teet kurssia Helsingin yliopiston opiskelijana, valitse organisaatioksi Helsingin yliopisto ja kurssiksi Ohjelmoinnin perusteet, kevät 2018. Jos taas teet Ohjelmoinnin MOOCia, valitse organisaatioksi MOOC ja kurssiksi joko Ohjelmoinnin MOOC 2018 tai Ohjelmoinnin MOOC 2018 (aikarajaton). Vain kurssilta Ohjelmoinnin MOOC 2018 voi hakea opiskelupaikkaa Helsingin yliopistolta.

Ohjelmointitehtävien avaaminen

Alla on kurssin ensimmäinen ohjelmointitehtävä. Ohjelmointitehtävien tehtävänannot löytyvät kurssimateriaalista (eli materiaalista mitä juuri luet). Tehtävänannon saa auki klikkaamalla alla tehtävänannon otsikkoa.

Tehtäväpohjat löytyvät TMC:stä, jonka asentamiseen annettiin ohjeet yllä.

Tehtäväpohjassa on seuraavanlainen ohjelmarunko:

public class Nimi {

    public static void main(String[] args) {
        // Kirjoita ohjelmasi tähän alle

    }
}

Rivi "// Kirjoita ohjelmasi tähän alle" on kommenttirivi, jota tietokone ei ota huomioon ohjelmaa suoritettaessa. Lisää kommenttirivin alle lause, joka tulostaa merkkijonon "Ada Lovelace" ja suorita ohjelma. Ohjelman tulostuksen tulee olla seuraavanlainen:

Ada Lovelace

Kun olet tehnyt tehtävän ja huomaat, että ohjelma tulostaa halutun merkkijonon, palauta tehtävä TMC:lle. Tutustu tämän jälkeen halutessasi lisää Ada Lovelaceen, joka oli yksi ensimmäisistä ohjelmoijista.

Lähdekoodin sijainti

Lähdekoodi ladataan ja tallennetaan tietokoneen kovalevylle. Näet lähdekoodin tarkemman sijainnin klikkaamalla projektin nimeä (esim. Osa01_01.AdaLovelace) hiiren oikealla näppäimellä ja valitsemalla Properties. Tämä avaa projektiin liittyvän asetusikkunan. Ikkunan Sources-valikossa löytyy tieto projektin kansiosta (Project Folder).

Kyseiseen kansioon voi mennä myös ilman NetBeansia. Huomaat, että projektin kansiossa on useita tiedostoja. Lähdekoodit, joita muokkaamme ja luomme tällä kurssilla sijaitsevat aina kansiossa src eli sources.

Java-kielisten lähdekooditiedostojen nimi päättyy merkkijonoon .java. Tiedoston nimi on ohjelmarungon public class -avainsanoja seuraava merkkijono. Esimerkiksi jos ohjelma alkaa sanoilla public class Esimerkki, tulee siihen liittyvän lähdekoodin sijaita tiedostossa Esimerkki.java.

Ohjelman osia

Kommentit

Lähdekoodia voi kommentoida selkeyttääkseen sitä tai lisätäkseen muistiinpanoja kahdella eri tavalla.

  • Yhden rivin kommentit aloitetaan kahdella vinoviivalla, //. Kaikki kahta vinoviivaa seuraava samalla rivillä oleva teksti tulkitaan kommentiksi.
  • Useamman rivin kommentit aloitetaan yhdellä vinoviivalla ja tähdellä /* ja lopetetaan tähdellä ja vinoviivalla */. Kaikki useamman rivin kommentin aloittavan ja lopettavan alueen välillä tulkitaan kommentiksi.

Alla on esimerkki ohjelmasta, jossa kumpikin kommenttityyppi on käytössä.

public class Kommentteja {
    public static void main(String[] args) {

        // Tulostetaan
        System.out.println("Tulostettava teksti");
        System.out.println("Lisää tulostettavaa!");

        /*
        Seuraavaksi:
         - lisää tulostamisesta
         - lisää harjoittelua
         - muuttujat
         - ...
        */

        // System.out.println("Muuta tulostettavaa");
    }
}

Esimerkin alin rivi esittelee erityisen kätevän käyttökohteen kommenteille. Kirjoitettua lähdekoodia ei tarvitse poistaa jos haluaa tilapäisesti kokeilla jotain.

Tee ohjelma, jonka tulostus on seuraava:

Hei Maailma!
(Ja Mualima!)

Tulostaminen

Käytimme edellä lausetta System.out.println("tulostettava"); merkkijonon tulostamiseen. Tulostuslause tulostaa sekä hipsuissa olevan merkkijonon että rivinvaihdon. Jos haluaa tulostaa merkkijonon ilman rivinvaihtoa, käytetään komentoa System.out.print("tulostettava");.

Yhteenvetona: tulostamiseen on kaksi lausetta:

  • System.out.println("sana"); tulostaa tekstin "sana" ja loppurivinvaihdon
  • System.out.print("sana"); tulostaa tekstin "sana" ilman loppurivinvaihtoa

Tulostettavan tekstin osana voi olla myös erikoismerkkejä, joista tärkein on rivinvaihto. Rivinvaihto ilmaistaan kenoviivalla ja n-merkillä seuraavasti: \n. Erikoismerkkejä on muitakin.

System.out.println("Ensimmäinen\nToinen\nKolmas");

Yllä oleva lause tulostaa seuraavaa:

Ensimmäinen
Toinen
Kolmas

Komennon parametrit

Tulostuslauseen tulostama tieto eli komennon parametrit annetaan tulostuskomennolle lisäämällä ne lauseen perässä olevien sulkujen () sisään. Esimerkiksi System.out.println -komennon parametriksi voidaan antaa merkkijono hei hipsujen sisällä seuraavasti: System.out.println("hei").

Puolipiste

Puolipisteellä ; erotetaan lauseet toisistaan. Voisimme oikeastaan kirjoittaa koko ohjelman yhdelle riville -- mikä ei kuitenkaan ole kovin ymmärrettävää.

System.out.print("Hei "); System.out.print("maailma"); System.out.print("!\n");
Hei maailma!

Vaikka yllä oleva esimerkki toimii, on rivinvaihtojen käyttö tärkeää muita ohjelmoijia ajatellen. Tällöin ohjelman lukija tietää, että kullakin rivillä tehdään vain yksi konkreettinen asia.

Lohko

Lohkolla tarkoitetaan aaltosulkujen rajaamaa aluetta. Ohjelmissamme näitä on tyypillisesti useita. Ohjelman sisältävä tiedosto sisältää merkkijonon public class Ohjelma, jota seuraa lohkon avaava aaltosulku. Lohko päättyy sulkevaan aaltosulkuun. Ohjelma -- tai oikeastaan luokan (tämä termi tulee myöhemmin tutuksi) -- sisällä voi olla myös muita lohkoja.

Esimerkiksi ohjelman käynnistämiskohdan määrittelevä merkkijono public static void main(String[] args) -- tai oikeastaan metodi (tämäkin termi tulee myöhemmin tutuksi) -- määrittelee oman lohkon, jonka sisällä oleva lähdekoodi suoritetaan kun ohjelma käynnistetään.

Alla olevassa kuvassa on näytettynä Ohjelma-nimisen luokan rajaama lohko. Lohko alkaa merkkijonon public class Ohjelma jälkeen alkavasta aaltosulusta ja päättyy viimeiseen aaltosulkuun.

 

Yllä olevan esimerkin lohko sisältää toisen lohkon. Tämä lohko alkaa merkkijonosta public static void main(String[] args) ja sisältää ohjelman käynnistymisessä suoritettavan lähdekoodin.

 

Laajemmin lohkojen merkitystä voi ajatella suoritettavan ohjelman rakenteen kuvaajina. Merkkijonosta public class Ohjelma alkava lohko sisältää koko ohjelman rakenteen, kun taas merkkijonosta public static void main(String[] args) alkava lohko sisältää ohjelman käynnistyksen jälkeen suoritettavan lähdekoodin.

Lohko rajataan aina aaltosuluilla, ja aaltosuluille tulee löytyä aina pari. Tietokone ei esimerkiksi ymmärtäisi seuraavanlaista ohjelmaa, sillä siitä puuttuu yksi aaltosulku.

public class Ohjelma {

    public static void main(String[] args) {

        // Tänne voit kirjoittaa ohjelmakoodia. Ohjelmasi voit ajaa
        // valitsemalla menusta Run->Run File tai painamalla Shift+F6


}

Ohjelmointityylistä

Vaikka tietokone ja käyttämämme ohjelmointikieli ei aseta rajoituksia kirjoitettavan ohjelmakoodin ulkoasulle, olemme huomanneet että ohjelmoijan -- tai opiskelevan ohjelmoijan -- kirjoittaman koodin ulkoasulla on merkitystä myös oppimisen kannalta. Luettavuus ja sisennyksen säännönmukaisuus ovat asioita, jotka vaikuttavat lähdekoodin ymmärrettävyyteen, ja sitä kautta myös oppimistuloksiin. Seuraava koodi on säännönmukaisesti sisennettyä.

public class Esimerkki {
    public static void main(String[] args) {
        System.out.println("Heippa vaan! Tämä koodi on siististi sisennetty.");
        System.out.println("public class -- ei sisennystä.");
        System.out.println("public static -- neljän merkin sisennys.");
        System.out.println("public static ... sisällä -- kahdeksan merkin sisennys -- tai enemmän.");
    }
}

Tämä koodi taas ei ole kovin ymmärrettävää.

         public class Esimerkki {
public static void main(String[] args) {
      System.out.println("Heippa vaan! Tämä koodi on siististi sisennetty.");
 System.out.println("public class -- ei sisennystä.");
                   System.out.println("public static -- neljän merkin sisennys.");
           System.out.println("public static ... sisällä -- kahdeksan merkin sisennys -- tai enemmän.");}}

Kurssilla käytettävä Test My Code -ympäristö sisältää Checkstyle-nimisen työvälineen. Checkstyle-työvälinettä voi käyttää mm. koodin sisennyksen ja muiden tyyliseikkojen automaattiseen tarkastamiseen. Tällä kurssilla Checkstyleä käytetään tyylin tarkastamiseen.

Tyylivirheet näytetään ohjelmointiympäristössä keltaisella, ja normaalit testi-ilmoitukset punaisella. Kurssilla tutuksi tuleva tehtävän edistymispalkki muuttuu myöskin keltaiseksi, jos koodissa havaitaan tyylivirheitä. Vaikkakin näppäinyhdistelmä alt + shift + f (macOS control + shift + f) auttaa useimpien tyylivirheiden korjaamiseen, on koodia syytä kirjoittaa oikein alusta alkaen.

Lähdekoodi tulee sisentää oikein

Javassa koodia sisennetään neljän välilyönnin tai yhden tabulaattorin verran jokaisen lohkon kohdalla. Käytä sisentämiseen joko välilyöntejä tai tabulaattoreita. Joissakin tapauksissa sisennys saattaa hajota mikäli käytät molempia. NetBeans auttaa tässä kun painat kirjainyhdistelmää "alt + shift + f" (macOS "control + shift + f").

Jatkossa ohjelmakoodi tulee sisentää oikein myös tehtävissä. Jos sisennys on väärin, ei ohjelmointiympäristö hyväksy tehtävää.

Tee ohjelma, jonka tulostus on seuraava:

    *
   ***
  *****
 *******
*********
    *
Lyhenne "sout"

Kirjoitit todennäköisesti aika monta kertaa System.out.println("..."). Kokeile kirjoittaa NetBeans:iin (main:in sisään) tyhjälle riville sout ja paina tabulaattoria (näppäin q:n vasemmalla puolella). Mitä tapahtuu? Tämä pieni apuväline säästänee jatkossa runsaasti aikaasi.

Ohjelma ja tieto

Muuttuja on keskeinen käsite ohjelmoinnissa. Muuttujia käytetään tiedon tallentamiseen myöhempää käyttöä varten. Myöhempää käyttöä on esimerkiksi tallennetun tiedon lukeminen, tulostaminen tai muuttaminen, sekä tiedon vertaileminen toiseen tietoon.

Muuttujien nimentä on ohjelmoijan vastuulla. Muuttujat nimetään tyypillisesti siten, että ne kuvaavat käyttötarkoitustaan -- esimerkiksi arvosanan sisältävän muuttujan nimeksi kannattaa asettaa arvosana.

Tiedon tyyppi

Ohjelman käsittelemä tieto on aina tietyn tyyppistä. Tyyppejä ovat esimerkiksi kokonaisluku (int), liukuluku (double) eli desimaaliluku ja totuusarvo (boolean). Kokonaisluvut ovat numeroita, esimerkiksi 42, liukuluvut desimaalilukuja, esimerkiksi 42.42 (desimaaliluvun erotusmerkki on piste), ja totuusarvot sisältävät joko arvon true, eli totta, tai arvon false, eli epätotta.

Muuttujan esittely

Muuttuja esitellään -- eli luodaan -- kertomalla ensin tiedon tyyppi, jota seuraa muuttujalle annettava nimi. Muuttujaan asetetaan arvo yhdellä yhtäsuuruusmerkillä (=).

int kuukausia = 12;

Yllä olevassa lauseessa luodaan kokonaisluku-tyyppinen muuttuja (int), jolle annetaan nimeksi kuukausia. Muuttujaan kuukausia asetetaan arvo 12. Lause luetaan "muuttuja kuukausia saa arvon 12".

Muuttujan arvo voidaan yhdistää tulostuslauseelle annettavaan parametriin +-merkillä seuraavan esimerkin mukaisesti.

public class Esimerkki {
    public static void main(String[] args) {
        int elamanTarkoitus = 123;
        double pii = 3.141592653;

        System.out.println("Elämän tarkoitus: " + elamanTarkoitus);
        System.out.println("Piin arvo on: " + pii);
    }
}

Tulostus:

Elämän tarkoitus: 123
Piin arvo on: 3.141592653
Ohjelman suorituksen visualisointi

Alla olevalla työvälineellä voi tarkastella ohjelman suorituksen etenemistä. Lähdekoodin vasemmalla laidalla oleva nuoli kertoo ohjelman suorituskohdan. Oikealla laidalla näkyy ohjelman muistiin tallennetut muuttujat sekä niiden arvot. Alla näkyy ohjelman tulostus.

Painamalla nappia "Next" ohjelman suoritus etenee.

Tehtäväpohja sisältää ohjelman, joka tulostaa seuraavaa.

Kanoja:
3
Pekonia (kg):
5.5

Tässä vielä tiivistelmä:
3
5.5

Muuta ohjelmaa annetuista kohdista niin että tuloste on:

Kanoja:
9000
Pekonia (kg):
0.1

Tässä vielä tiivistelmä:
9000
0.1

Muuttujien nimet ovat uniikkeja, eikä kahdella muuttujalla saa olla ohjelmassa samaa nimeä. Seuraavassa esimerkissä oleva ohjelma on virheellinen, koska muuttuja pii esitellään kahdesti.

public class Esimerkki {
    public static void main(String[] args) {
        double pii = 3.14;
        double pii = 3.141592653;

        System.out.println("Piin arvo on: " + pii);
    }
}

Muuttujaan asetetun arvon muuttaminen

Muuttuja on olemassa sen esittelyhetkestä lähtien, ja sen arvo säilyy kunnes muuttujaan asetetaan toinen arvo. Muuttujan arvon muuttaminen onnistuu lauseella, jossa on muuttujan nimi, yhtäsuuruusmerkki, ja muuttujan uusi arvo. Huomaa että muuttujan tyyppi kirjoitetaan vain kun muuttuja esitellään ohjelmassa ensimmäistä kertaa.

int luku = 123;
System.out.println("Muuttujan arvo on " + luku);

luku = 42;
System.out.println("Muuttujan arvo on " + luku);

Tulostus:

Muuttujan arvo on 123
Muuttujan arvo on 42

Tarkastellaan edellisen ohjelmakoodin suoritusta askel askeleelta. Kun muuttuja esitellään ohjelmakoodissa ensimmäistä kertaa, eli sekä muuttujan tyyppi (tässä int) että sen nimi (tässä luku) kerrotaan tietokoneelle, tietokone luo muuttujaa varten "nimetyn lokeron". Tämän jälkeen yhtäsuuruusmerkin oikealla puolella oleva arvo kopioidaan tähän nimettyyn lokeroon.

Kun ohjelmakoodissa viitataan muuttujaan sen nimellä -- tässä halutaan tulostaa merkkijono "Muuttujan arvo on " sekä muuttujan luku arvo, muuttujan luku arvo haetaan sen nimellä löytyvästä lokerosta.

Kun muuttujaan asetetaan arvo (tässä luku = 42), tarkistetaan ensin löytyykö muuttujan nimistä lokeroa. Jos lokero löytyy, uusi arvo kopioidaan lokeroon vanhan arvon tilalle ja vanha arvo katoaa. Jos muuttujan nimellä ei löydy lokeroa, ohjelman suoritus päättyy virheilmoitukseen tai ohjelmaa ei voida käynnistää.

Seuraavaksi ohjelmakoodissa viitataan taas muuttujaan sen nimellä -- tässäkin halutaan tulostaa merkkijono "Muuttujan arvo on " sekä muuttujan luku arvo. Toimitaan kuten normaalisti, eli haetaan muuttujan luku arvo sen nimellä löytyvästä lokerosta.

Kuten huomaat, ohjelman lopputilanteessa muuttujan alkuperäinen arvo on kadonnut. Muuttuja voi sisältää kerrallaan aina vain yhden arvon.

Muuttujan tyyppi pysyy

Kun muuttujan tyyppi on kertaalleen määritelty, ei sitä voi enää muuttaa. Totuusarvoa ei siis voi esimerkiksi asettaa kokonaislukutyyppiseen muuttujaan, eikä totuusarvomuuttujaan voi asettaa kokonaislukua.

boolean onnistuukoKokonaisLuvunAsetus = false;
onnistuukoKokonaisLuvunAsetus = 42; // Ei onnistu

int luku = 10;
onnistuukoKokonaisLuvunAsetus = luku; // Ei myöskään onnistu

Poikkeus kuitenkin löytyy: liukulukutyyppiseen muuttujaan voi asettaa kokonaisluvun, sillä Java osaa muuttaa kokonaisluvun liukuluvuksi asetuksen yhteydessä.

double liukuluku = 0.42;
liukuluku = 1; // Onnistuu

int luku = 10;
liukuluku = luku; // Onnistuu myös

Liukulukua ei kuitenkaan voi asettaa kokonaislukuun. Tämä johtuu siitä, että ohjelmointikielen suunnittelijat yrittävät suojella ohjelmoijaa tietoa kadottavilta ohjelmointivirheiltä.

int luku = 4.2; // Ei onnistu

double liukuluku = 0.42;
luku = liukuluku; // Ei myöskään onnistu

Muuttujan nimentä

Muuttujien nimentä on oleellinen osa ohjelman kuvausta. Tarkastellaan kahta esimerkkiä.

double a = 3.14;
double b = 22.0;
double c = a * b * b;

System.out.println(c);
1519.76
double pii = 3.14;
double sade = 22.0;
double pintaAla = pii * sade * sade;

System.out.println(pintaAla);
1519.76

Edellä olevat kaksi esimerkkiä sisältävät täsmälleen saman toiminnallisuuden ja tuottavat saman tulostuksen. Toinen esimerkeistä on kuitenkin paljon ymmärrettävämpi. Kyseessä on ympyrän pinta-alan laskevan ohjelman koodi. Ensimmäisellä rivillä määritellään piin arvo, toisella rivillä ympyrän säde, ja kolmannella rivillä lasketaan pinta-ala. Tämän jälkeen pinta-ala tulostetaan.

Muuttujat sanoittavat ohjelmaa ja ratkaistavaa ongelmaa

Ohjelmointi on ongelmanratkaisuväline. Ohjelmoidessa luodaan ratkaisua jonkinlaiseen ongelmaan kuten autojen automaattiseen ohjaamiseen. Kun ongelmaa ratkaistaan, ohjelmoija päättää termeistä, joilla ongelmaa kuvataan. Tämä termistö, esimerkiksi ohjelmassa käytettävien muuttujien nimet, tulevat kuvaamaan ongelmaa ohjelman parissa tulevaisuudessa työskenteleville.

Kun sanoitat ratkaistavaa ongelmaa, mieti ongelmaan liittyviä käsitteitä ja niitä kuvaavia sanoja. Jos et keksi sopivia termejä, pohdi ensin mitkä sanat eivät ainakaan kuvaa ongelmaa. Valitse tämän jälkeen jonkinlainen termistö -- voit tyypillisesti onneksi parantaa käyttämääsi termistöä myös jälkikäteen.

Muuttujan nimeämistä rajoittavat tietyt ehdot.

Muuttujan nimessä ei saa olla tiettyjä erikoismerkkejä, kuten huutomerkkejä (!). Välilyönti ei ole sallittu, sillä se erottaa komentojen osat toisistaan. Välilyönti kannattaa korvata camelCase<-tyylillä, jolloin nimi muistuttaneeKamelia. Huom! Muuttujien nimien ensimmäinen kirjain kirjoitetaan aina pienellä:

int camelCaseMuuttuja = 7;

Numeroita voidaan käyttää muuttujan nimessä, kunhan nimi ei ala numerolla. Nimi ei myöskään voi koostua pelkistä numeroista.

int 7muuttuja = 4; // Ei sallittu!
int muuttuja7 = 4; // Sallittu, mutta ei kuvaava muuttujan nimi

Muuttujan nimi ei saa olla jo entuudestaan käytössä. Tällaisia nimiä ovat mm. aikaisemmin määritellyt muuttujat ja Javan valmiit komennot, kuten System.out.print ja System.out.println.

int camelCase = 2;
int camelCase = 5; // Ei sallittu -- muuttuja camelCase on jo käytössä!

Muuttujien nimissä ei tule myöskään käyttää ääkkösiä. Voit korvata ääkköset aakkosilla, eli muuta ä -> a ja ö -> o.

Sallittuja muuttujien nimiä

  • kuukaudenViimeinenPaiva = 20
  • ensimmainenVuosi = 1952
  • nimi = "Essi"

Virheellisiä muuttujien nimiä

  • kuukauden viimeinen päivä = 20
  • 1paiva = 1952
  • varo! = 1910
  • 1920 = 1

Tietokone on laskin

Tietokone on käytännössä erittäin tehokas laskin. Tietokoneen suoritin hakee suoritettavaan ohjelmaan liittyvät konekieliset käskyt muistista ja suorittaa niitä yksi kerrallaan. Tietokoneen käyttöjärjestelmän -- joka sekin on ohjelma -- vastuulla on suoritettavan ohjelman valinta.

Tutustutaan seuraavaksi tyypillisimpiin laskuoperaatioihin.

Laskentaa

Laskuoperaatiot ovat tuttuja ja suoraviivaisia: yhteenlasku +, erotus -, kertolasku * ja jakolasku /. Laskentajärjestys on myös tuttu: laskenta tehdään vasemmalta oikealle sulut huomioon ottaen. Kuitenkin * ja / lasketaan ennen + ja - operaatioita, samoin kuin perus- tai kansakoulumatematiikassa on tullut tutuksi.

int eka = 2;
System.out.println(eka); // tulostaa 2
int toka = 4;
System.out.println(toka); // tulostaa 4

int summa = eka + toka; // muuttujaan summa asetetaan muuttujien eka ja toka arvojen summa
System.out.println(summa); // tulostaa 6

Laskujärjestys ja sulut

Laskujärjestykseen voi vaikuttaa sulkujen avulla. Sulkujen sisällä olevat laskuoperaatiot suoritetaan ennen niiden ulkopuolella olevia laskuoperaatioita.

int laskuSuluilla = (1 + 1) + 3 * (2 + 5);
System.out.println(laskuSuluilla); // tulostaa 23

int laskuSuluitta = 1 + 1 + 3 * 2 + 5;
System.out.println(laskuSuluitta); // tulostaa 13

Yllä olevan esimerkin voi jakaa myös osiin.

int laskuSuluilla = (1 + 1);
System.out.println(laskuSuluilla); // tulostaa 2
laskuSuluilla = laskuSuluilla + 3 * (2 + 5);
System.out.println(laskuSuluilla); // tulostaa 23

int laskuSuluitta = 1 + 1;
laskuSuluitta = laskuSuluitta + 3 * 2;
laskuSuluitta = laskuSuluitta + 5;
System.out.println(laskuSuluitta); // tulostaa 13

Täydennä tehtäväpohjassa olevaa ohjelmaa siten, että se laskee kuinka monta sekuntia on vuodessa. Voit olettaa, että vuodessa on 365 päivää.

Ohjelman tulostus on seuraava:

Vuodessa on X sekuntia.

X:n kohdalle tulee ohjelmasi laskema tulos. Huom! Hyödynnä tässä tehtävässä muuttujia.

Lauseke ja lause

Lauseke (expression) on arvojen yhdistelmä, joka muuntuu arvoksi laskuoperaation tai evaluaation yhteydessä. Alla oleva lause sisältää lausekkeen 1 + 1 + 3 * 2 + 5, joka evaluoidaan ennen arvon asetusta muuttujaan.

int laskuSuluitta = 1 + 1 + 3 * 2 + 5;

Lausekkeen evaluaatio tapahtuu aina ennen muuttujan arvon asetusta, eli yllä lasku "1 + 1 + 3 * 2 + 5" suoritetaan ennen tuloksen asetusta muuttujaan.

Lausekkeen evaluointi tapahtuu ohjelmakoodissa siinä kohtaa, missä lauseke on. Evaluointi onnistuu siis esimerkiksi myös tulostuslauseen yhteydessä, jos lauseketta käytetään tulostuslauseen parametrin arvon laskemisessa.

int eka = 2;
int toka = 4;

System.out.println(eka + toka); // tulostaa 6
System.out.println(2 + toka - eka - toka); // tulostaa 0

Lauseke ei muuta muuttujassa olevaa arvoa, ellei lausekkeen lopputulosta aseteta muuttujan arvoksi tai anneta parametrina esimerkiksi tulostukselle.

int eka = 2;
int toka = 4;

// alla oleva lauseke ei edes toimi, sillä lauseketta
// ei aseteta minkään muuttujan arvoksi tai anneta parametrina
// tulostuslauseelle
eka + toka;

Laskentaa ja tulostamista

Muuttujan arvon voi tulostaa komennolla System.out.println. Tulostettavaan hipsuilla merkittyyn merkkijonoon, esim. "Pituus ", voidaan lisätä muuta tulostettavaa operaation + avulla.

int pituus = 42;
System.out.println("Pituus " + pituus);
Pituus 42
System.out.println("tuossa on kokonaisluku --> " + 2);
System.out.println(2 + " <-- tuossa on kokonaisluku");
tuossa on kokonaisluku --> 2
2 <-- tuossa on kokonaisluku

Jos toinen operaation + kohteista on merkkijono, muutetaan myös toinen operaation kohteista merkkijonoksi ohjelman suorituksen yhteydessä. Alla olevassa esimerkissä kokonaisluku 2 on muutettu merkkijonoksi "2", ja siihen on yhdistetty merkkijono.

Aiemmin esitellyt laskusäännöt pätevät täälläkin:

System.out.println("Neljä: " + (2 + 2));
System.out.println("Mutta! kaksikymmentäkaksi: " + 2 + 2);
Neljä: 4
Mutta! kaksikymmentäkaksi: 22

Edellistä tietoa soveltamalla voimme luoda lausekkeen, joka sisältää tekstiä ja muuttujan, ja joka evaluoidaan tulostuksen yhteydessä:

int x = 10;

System.out.println("muuttujan x arvo on: " + x);

int y = 5;
int z = 6;

System.out.println("y on " + y + " ja z on " + z);

Tulostus:

muuttujan x arvo on: 10
y on 5 ja z on 6
Ratkaisumalli :: Laskeminen

Samankaltaiset ongelmat toistuvat ohjelmoinnissa. Tämän takia ohjelmoijan on hyvä opetella ratkaisumalleja, joita voi soveltaa ohjelmia luodessa. Ensimmäinen ratkaisumalli ohjelmaan, jonka tehtävänä on tehdä laskentaa muuttujilla on seuraavanlainen.

  1. Määrittele ohjelman syötteet ja luo niitä varten muuttujat. Ohjelman syötteitä ovat laskemisessa käytettävät arvot. Syötteet tunnistaa tyypillisesti ongelma-alueen kuvauksesta.
  2. Selvitä tehtävä laskuoperaatio ja luo laskuoperaation tulokselle muuttuja. Tee ohjelman syötteiden perusteella lasku, jonka arvo asetetaan laskuoperaation tulokselle varattuun muuttujaan. Myös tehtävän laskuoperaation tunnistaa ongelma-alueen kuvauksesta.
  3. Tulosta laskuoperaation tulos.

Esimerkiksi tehtävän Tee ohjelma, jonka avulla voidaan laskea kahden kokonaisluvun summa. Ohjelman alussa määritellään kaksi muuttujaa, jotka sisältävät summattavat luvut. Voit tarvittaessa käyttää myös muita muuttujia. ratkaisumalli on seuraava.

// 1. määritellään syötteet ja luodaan niitä varten muuttujat
int eka = 1;
int toka = 2;

// 2. selvitetään laskuoperaatio ja luodaan laskuoperaation tulokselle muuttuja
int summa = eka + toka;

// 3. tulostetaan laskuoperaation tulos
System.out.println("Lukujen " + eka + " ja " + toka + " summa on " + summa);  

Tee ohjelma, jonka avulla voidaan laskea kahden kokonaisluvun summa. Ohjelman alussa määritellään kaksi muuttujaa, jotka sisältävät summattavat luvut. Voit tarvittaessa käyttää myös muita muuttujia.

Esimerkiksi jos muuttujissa on luvut 5 ja 4, ohjelman tulostus on seuraava:

5 + 4 = 9

Jos taas muuttujissa on luvut 73457 ja 12888, ohjelman tulostus on seuraava:

73457 + 12888 = 86345

Tee edellistä ohjelmaa vastaava ohjelma, joka laskee kahden kokonaislukumuuttujaan sijoitetun arvon kertolaskun.

Esimerkiksi jos muuttujissa on luvut 2 ja 8, ohjelman tulostus on seuraava:

2 * 8 = 16

Jos taas muuttujissa on luvut 277 ja 111, ohjelman tulostus on seuraava:

277 * 111 = 30747

Kokeile myös kuinka suuren kertolaskun ohjelmasi pystyy laskemaan!

Jakolasku

Kokonaislukujen jakolasku on hieman hankalampi operaatio. Jakolausekkeessa käytettyjen muuttujien tyyppi määrää evaluaation tuloksena saatavan arvon tyypin. Jos kaikki jakolausekkeessa olevat muuttujat ovat kokonaislukuja, on tulos myös kokonaisluku.

int tulos = 3 / 2;
System.out.println(tulos); // Huom! tulostaa 1 (kokonaisluku), sillä 3 ja 2 ovat myös kokonaislukuja
int eka = 3:
int toka = 2;
double tulos = eka / toka;
System.out.println(tulos); // nytkin tulostus on 1, sillä eka ja toka ovat kokonaislukuja

Jos jakolaskun jakaja tai jaettava (tai molemmat!) ovat liukulukuja, tulee tulokseksi myös liukuluku.

double kunJaettavaOnLiukuluku = 3.0 / 2;
System.out.println(kunJaettavaOnLiukuluku); // tulostaa 1.5

double kunJakajaOnLiukuluku = 3 / 2.0;
System.out.println(kunJakajaOnLiukuluku); // tulostaa 1.5

Kokonaisluku voidaan tarvittaessa muuttaa liukuluvuksi lisäämällä sen eteen tyyppimuunnosoperaatio (double):

int eka = 3;
int toka = 2;

double tulos1 = (double) eka / toka;
System.out.println(tulos1); // tulostaa 1.5

double tulos2 = eka / (double) toka;
System.out.println(tulos2); // tulostaa 1.5

double tulos3 = (double) (eka / toka);
System.out.println(tulos3); // tulostaa 1.0

Jälkimmäisessä esimerkissä tulos pyöristyy väärin sillä laskuoperaatio kokonaisluvuilla suoritetaan ennen tyyppimuunnosta.

Jos jakolausekkeen tulos asetetaan kokonaislukutyyppiseen muuttujaan, on tulos automaattisesti kokonaisluku.

// tulos automaattisesti kokonaisluku: 1
int tulosKokonaislukuKoskaTyyppiKokonaisluku = 3.0 / 2;

Seuraava esimerkki tulostaa "1.5", sillä jaettavasta tehdään liukuluku kertomalla se liukuluvulla (1.0 * 3 = 3.0) ennen jakolaskua.

int jaettava = 3;
int jakaja = 2;

double tulos = 1.0 * jaettava / jakaja;
System.out.println(tulos);

Tehtäväpohjassa on ohjelma, jossa on kolme muuttujaa. Ohjelman tulostus on tällä hetkellä seuraava.

eka: 9
toka: 7
kolmas: 6

Muokkaa ohjelmaa siten, että ohjelma tulostaa myös muuttujien keskiarvon.

eka: 9
toka: 7
kolmas: 6
keskiarvo: 7.333333333333333

Huom! Jos muuttujien arvoja muutetaan, tulee myös tulostuksen muuttua.

eka: 5
toka: 7
kolmas: 4
keskiarvo: 5.333333333333333

Tehtäväpohjassa on ohjelma, jossa on kaksi muuttujaa. Ohjelman tulostus on tällä hetkellä seuraava.

5 + 3 = 8

Muokkaa ohjelmaa siten, että ohjelma laskee myös lukujen erotuksen, tulon, ja jakolaskun.

5 + 3 = 8
5 - 3 = 2
5 * 3 = 15
5 / 3 = 1.6666666666666667

Huom! Jos muuttujien arvoja muutetaan, tulee myös tulostuksen muuttua.

1 + 3 = 4
1 - 3 = -2
1 * 3 = 3
1 / 3 = 0.3333333333333333

Tehtävässä ei ole testejä jotka kertovat onko tulostus oikein vai ei. Tarkista, että ohjelmasi toimii oikein ennen tehtävän palautusta suorittamalla se useammalla muuttujien arvoilla.

Muuttujan arvoon liittyviä väärinkäsityksiä

Kun tietokone suorittaa ohjelmakoodia, suorittaa se sitä käsky kerrallaan, edeten aina täsmälleen siten, kuin ohjelmakoodissa sanotaan. Kun muuttujaan asetetaan arvo, tapahtuu aina sama asia, eli yhtäsuuruusmerkin oikealla puolella oleva arvo kopioidaan yhtäsuuruusmerkin vasemmalla puolella olevan muuttujan arvoksi, eli muuttujan nimeämään paikkaan.

On tärkeää, että ohjelmoija ymmärtää, että arvon asettaminen muuttujaan tekee aina saman asian.

Kolme yleistä väärinkäsitystä, jotka liittyvät muuttujan arvon asettamiseen ovat seuraavat:

  • Muuttujan asettamisen näkeminen siirtona kopioimisen sijaan: ohjelmakoodin eka = toka suorituksen jälkeen ajatellaan, että muuttujan toka arvo on siirtynyt muuttujan eka arvoksi, jonka jälkeen muuttujalla toka ei ole enää arvoa, tai sen arvo on esimerkiksi nolla. Tämä ei pidä paikkansa, sillä ohjelmakoodin eka = toka suorituksessa muuttujan toka nimeämässä paikassa oleva arvo kopioidaan muuttujan eka nimeämään paikkaan. Muuttujan toka arvo ei siis muutu.
  • Muuttujan asettamisen näkeminen riippuvuutena kopioimisen sijaan: ohjelmakoodin eka = toka suorituksen jälkeen ajatellaan, että mikä tahansa muutos muuttujaan toka vaikuttaa automaattisesti myös muuttujaan eka. Tämä ei pidä paikkansa, sillä asetus -- kopiointi -- on yksittäinen tapahtuma. Se tapahtuu vain silloin, ohjelmakoodi eka = toka suoritetaan.
  • Kolmas väärinkäsitys liittyy kopioimisen suuntaan: ohjelmakoodin eka = toka suorituksessa ajatellaan, että muuttujan toka arvoksi kopioidaan muuttujan eka arvo. Tämä näkyy myös tilanteina, missä ohjelmoija voi vahingossa kirjoittaa esimerkiksi 42 = arvo -- onneksi ohjelmointiympäristöt tukevat myös tässä.

Ehkäpä paras tapa tietokoneen ohjelmakoodin suorittamisen ymmärtämiseen on paperin ja kynän käyttäminen. Kun luet ohjelmakoodia, kirjoita paperille uusien muuttujien nimet, sekä kirjoita ylös rivi riviltä, miten ohjelmakoodissa olevien muuttujien arvot muuttuvat. Havainnollistetaan suoritusta seuraavalla ohjelmakoodilla:

rivi 1: int eka = (1 + 1);
rivi 2: int toka = eka + 3 * (2 + 5);
rivi 3:
rivi 4: eka = 5;
rivi 5:
rivi 6: int kolmas = eka + toka;
rivi 7: System.out.println(eka);
rivi 8: System.out.println(toka);
rivi 9: System.out.println(kolmas);

Alla on kirjoitettu yllä olevan ohjelmakoodin suoritus auki.

rivi 1: luodaan muuttuja eka
rivi 1: kopioidaan muuttujan eka arvoksi laskun 1 + 1 tulos
rivi 1: muuttujan eka arvo on 2

rivi 2: luodaan muuttuja toka
rivi 2: lasketaan 2 + 5, 2 + 5 ->  7
rivi 2: lasketaan 3 * 7, 3 * 7 -> 21
rivi 2: lasketaan eka + 21
rivi 2: kopioidaan muuttujan eka arvo laskuun, muuttujan eka arvo on 2
rivi 2: lasketaan 2 + 21, 2 + 21 -> 23
rivi 2: kopioidaan muuttujan toka arvoksi 23
rivi 2: muuttujan toka arvo on 23

rivi 3: (tyhjä, ei tehdä mitään)

rivi 4: kopioidaan muuttujan eka arvoksi 5
rivi 4: muuttujan eka arvo on 5

rivi 5: (tyhjä, ei tehdä mitään)

rivi 6: luodaan muuttuja kolmas
rivi 6: lasketaan eka + toka
rivi 6: kopioidaan muuttujan eka arvo laskuun, muuttujan eka arvo on 5
rivi 6: lasketaan 5 + toka
rivi 6: kopioidaan muuttujan toka arvo laskuun, muuttujan toka arvo on 23
rivi 6: lasketaan 5 + 23 -> 28
rivi 6: kopioidaan muuttujan kolmas arvoksi 28
rivi 6: muuttujan kolmas arvo on 28

rivo 7: tulostetaan muuttuja eka
rivi 7: kopioidaan muuttujan eka arvo tulostettavaksi, muuttujan eka arvo on 5
rivi 7: tulostetaan arvo 5

rivi 8: tulostetaan muuttuja toka
rivi 8: kopioidaan muuttujan toka arvo tulostettavaksi, muuttujan toka arvo on 23
rivi 8: tulostetaan arvo 23

rivi 9: tulostetaan muuttuja kolmas
rivi 9: kopioidaan muuttujan kolmas arvo tulostettavaksi, muuttujan kolmas arvo on 28
rivi 9: tulostetaan arvo 28

Alla edellinen ohjelma askeleittain visualisoituna. Käytössä oleva askeleittainen visualisointi käsittelee ohjelmakoodia riveittäin -- pohdi askeleiden kohdalla miten ohjelma päätyy sen tulostamaan lopputulokseen.

Tässä tehtävässä harjoittelet ensimmäistä kertaa tuntemattoman ohjelman muokkaamista. Vaikka suurin osa ohjelmasta tuntuu kryptiseltä, etkä tunne lähdekoodissa käytettyjä sanoja lainkaan, huomaat sieltä todennäköisesti myös tuttuja asioita.

Tehtäväpohjaan on toteutettuna graafinen (eli ohjelma avautuu ikkunassa) jakolaskin. Ohjelmassa on kuitenkin pientä häikkää, kuten alla olevasta esimerkistä huomaat.

Etsi vika ja korjaa se. Huomaa, että tässä tehtävässä (ja muissa käyttöliittymiin liittyvissä tehtävissä) automaattiset testit käyttävät hiirtäsi. Älä siis käytä hiirtäsi testien ajon aikana.

Huom! Isolla resoluutiolla varustelluissa koneissa on huomattu ongelmia hiirtä liikuttavan testikirjaston kanssa. Jos huomaat, että ohjelmasi toimii kun käynnistät sen itse ja kokeilet sen toimintaa, mutta testien ajaminen epäonnistuu, lähetä tehtävä palvelimelle arvioitavaksi.

Käyttäjän syötteen lukeminen

Edellisissä ohjelmissamme tietokonetta on käytetty lähes poikkeuksetta hyvin yksinkertaisena laskimena. Laskuoperaatioiden käsittelemät luvut on syötetty lähdekoodiin, eikä käyttäjä ole päässyt syöttämään niitä itse.

Tutustutaan seuraavaksi syötteen lukemiseen käyttäjältä. Syötteen lukemiseen käytetään Javan valmista Scanner-apuvälinettä. Apuväline tuodaan käyttöön lisäämällä komento import java.util.Scanner; ennen pääohjelmarungon aloitusta (public class ...).

import java.util.Scanner; // tuodaan lukemiseen käytetty apuväline Scanner käyttöömme

public class Esimerkki {

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

        // ohjelmakoodi
    }
}

Älä hätäile vaikka pääohjelmarunko saattaa näyttää vaikeaselkoiselta! Jatkamme yhä ohjelmointia kommentilla ohjelmakoodi merkittyyn kohtaan.

Kokonaisluvun lukeminen

Kokonaislukujen lukeminen tapahtuu lukemalla käyttäjältä syöterivi (komento lukija.nextLine()), joka annetaan komennolle Integer.parseInt. Komento Integer.parseInt muuntaa sille annetun syöterivin kokonaislukumuuttujaksi, olettaen että tämä on mahdollista.

System.out.print("Anna kokonaisluku: ");
int kokonaisluku = Integer.parseInt(lukija.nextLine());

System.out.println("Annoit " + kokonaisluku);

Jatkossa esimerkkitulostuksissa merkitään punaisella käyttäjän syöttämät arvot. Edeltävän ohjelman suoritus olisi seuraavanlainen, olettaen, että käyttäjä syöttää arvon 25.

Anna kokonaisluku: 25

Annoit 25
import java.util.Scanner; public class Esimerkki { public static void main(String[] args) { // Luodaan lukemiseen käytettävä apuväline Scanner lukija = new Scanner(System.in); } }
import java.util.Scanner; public class Esimerkki { public static void main(String[] args) { // Luodaan lukemiseen käytettävä apuväline // MARK } }
import java.util.Scanner; public class Esimerkki { public static void main(String[] args) { // Luodaan lukemiseen käytettävä apuväline Scanner lukija = new Scanner(System.in); // Luetaan luku käyttäjältä ja tulostetaan se int luku = Integer.parseInt(lukija.nextLine()); System.out.println(luku); } }
import java.util.Scanner; public class Esimerkki { public static void main(String[] args) { // Luodaan lukemiseen käytettävä apuväline Scanner lukija = new Scanner(System.in); // Luetaan luku käyttäjältä ja tulostetaan se // MARK } }

Tee ohjelma, joka kysyy käyttäjältä lukua ja tulostaa syötetyn luvun arvon.

Anna luku: 42

Syötit: 42

Esimerkin punaisella värjätty teksti tarkoittaa käyttäjän kirjoittamaa tekstiä.

Useamman luvun lukeminen onnistuu myös luontevasti. Alla olevassa esimerkissä ohjelma kysyy käyttäjältä kolme lukua ja tulostaa niiden keskiarvon.

System.out.println("Ohjelma kysyy kolme kokonaislukua ja tulostaa niiden keskiarvon.");
System.out.print("Anna kokonaisluku: ");
int eka = Integer.parseInt(lukija.nextLine());
System.out.print("Anna kokonaisluku: ");
int toka = Integer.parseInt(lukija.nextLine());
System.out.print("Anna kokonaisluku: ");
int kolmas = Integer.parseInt(lukija.nextLine());

double keskiarvo = (eka + toka + kolmas) / 3.0;

System.out.println("Syötettyjen lukujen keskiarvo " + keskiarvo);
Ohjelma kysyy kolme kokonaislukua ja tulostaa niiden keskiarvon.
Anna kokonaisluku:
1
Anna kokonaisluku:
3
Anna kokonaisluku:
5
Syötettyjen lukujen keskiarvo 3.0

Jokaista muuttujaa ei tarvitse aina kirjoittaa auki erikseen. Esimerkiksi edellisen ohjelman voi toteuttaa myös niin, että ohjelmassa käytetään vain yhtä muuttujaa, jonka tehtävänä on syötettyjen lukujen summan ylläpito.

System.out.println("Ohjelma kysyy kolme kokonaislukua ja tulostaa niiden keskiarvon.");
System.out.print("Anna kokonaisluku: ");
int summa = Integer.parseInt(lukija.nextLine());
System.out.print("Anna kokonaisluku: ");
summa = summa + Integer.parseInt(lukija.nextLine());
System.out.print("Anna kokonaisluku: ");
summa = summa + Integer.parseInt(lukija.nextLine());

System.out.println("Syötettyjen lukujen keskiarvo " + (1.0 * summa / 3));

Tee ohjelma, joka kysyy käyttäjältä kaksi kokonaislukua ja tulostaa niiden summan.

Anna ensimmäinen luku: 6
Anna toinen luku: 2

Lukujen summa: 8

Kuten aiemminkin, esimerkin punaisella värjätty teksti tarkoittaa käyttäjän kirjoittamaa tekstiä.

Tee ohjelma, joka kysyy käyttäjältä kolme kokonaislukua ja tulostaa niiden summan.

Anna ensimmäinen luku: 5
Anna toinen luku: 2
Anna kolmas luku: 12

Lukujen summa: 19

Kuten aiemminkin, esimerkin punaisella värjätty teksti tarkoittaa käyttäjän kirjoittamaa tekstiä.

Tee ohjelma, joka kysyy käyttäjältä kaksi kokonaislukua ja tulostaa niiden osamäärän. Varmista, että 3 / 2 = 1.5. Jos desimaaliosa katoaa, lue uudelleen Jakolaskuun liittyvä kohta materiaalista.

Anna ensimmäinen luku: 3
Anna toinen luku: 2

Jakolasku: 3 / 2 = 1.5

Ympyrän kehän pituus lasketaan kaavalla 2 * pii * säde. Tee ohjelma, joka kysyy käyttäjältä ympyrän säteen ja laskee sen perusteella ympyrän kehän pituuden. Voit käyttää joko omaa muuttujaa piin arvon tallentamiseen, tai voit käyttää Javan valmiiksi tarjoamaa piin arvoa. Javan valmiin piin arvon saa käyttöön kirjoittamalla Math.PI laskutoimitukseen.

Anna ympyrän säde: 20

Ympyrän kehä: 125.66370614359172

Päätösten tekeminen

Ohjelmamme ovat toistaiseksi edenneet suoraviivaisesti lauseesta seuraavaan, toimien jokaisella suorituskerralla samalla tavalla. Haluamme mahdollisuuden erilaisille ohjelman suorituspoluille.

Ehtolause

Jotta ohjelman suoritus voisi haarautua esimerkiksi käyttäjän antaman syötteen perusteella, tarvitsemme käyttöömme ehtolauseen.

Ehtolause alkaa avainsanalla if, jota seuraa sulut. Sulkujen sisälle asetetaan lauseke, joka evaluoidaan kun ehtolause saavutetaan. Sulkuja seuraa lohko, joka määritellään avaavan aaltosulun { ja sulkevan aaltosulun } sisään. Lohko suoritetaan jos sulkujen sisälle asetettu lauseke evaluoidaan todeksi.

int luku = 11;

if (luku > 10) {
    System.out.println("Luku oli suurempi kuin 10");
}

Jos ehtolauseen lauseke evaluoidaan todeksi, yllä "jos muuttujassa luku oleva arvo on suurempi kuin 10", ohjelman suoritus siirtyy ehtolauseen määrittelemään lohkoon. Jos taas lauseke on epätotta, ohjelman suoritus siirtyy ehtolauseeseen liittyvän lohkon päättävän aaltosulun jälkeiseen lauseeseen.

Huomaa, että if -lauseen perään ei tule puolipistettä, sillä lause ei lopu ehto-osan jälkeen.

public class Esimerkki { public static void main(String[] args) { int luku = 11; if (luku > 10) { System.out.println("Luku oli suurempi kuin 10"); } } }
public class Esimerkki { public static void main(String[] args) { // MARK } }
Ohjelmakoodin sisennys

Lohkojen sisällä oleva koodi sisennetään. Esimerkiksi ehtolauseeseen liittyvän lohkon sisältämä lähdekoodi sisennetään neljä välilyöntiä sisemmälle kuin ehtolauseen aloittava if-komento. Neljä merkkiä saa myös tabulaattorimerkillä (q:n vasemmalla puolella oleva näppäin). Kun lohko sulkeutuu, eli tulee }-merkki, sisennys loppuu. }-merkki on samalla tasolla kuin ehtolauseen aloittanut if-komento.

VäärinOikein
if (luku > 10) {
luku = 9;
}
if (luku > 10) {
    luku = 9;
}

Tee ohjelma, joka kysyy käyttäjältä kokonaisluvun ja tulostaa merkkijonon "Ylinopeussakko!" jos luku on suurempi kuin 120.

Kerro nopeus: 15
Kerro nopeus: 135

Ylinopeussakko!

Vertailuoperaattorit

Vertailuoperaattoreita ovat seuraavat:

  • >suurempi kuin
  • >=suurempi tai yhtä suuri kuin
  • <pienempi kuin
  • <= pienempi tai yhtä suuri kuin
  • == yhtä suuri kuin
  • != erisuuri kuin
int luku = 55;

if (luku != 0) {
    System.out.println("Luku oli erisuuri kuin 0");
}

if (luku >= 1000) {
    System.out.println("Luku oli vähintään 1000");
}
Luku oli erisuuri kuin 0

Tee ohjelma, joka kysyy käyttäjältä kokonaisluvun ja tulostaa merkkijonon "Orwell" jos luku on täsmälleen 1984.

Anna luku: 1983
Anna luku: 1984

Orwell

Tee ohjelma, joka kysyy käyttäjältä vuosilukua. Jos käyttäjä syöttää luvun, joka on pienempi kuin 2015, ohjelma tulostaa merkkijonon "Wanha!".

Anna vuosiluku: 2017
Anna vuosiluku: 2013

Wanha!

Muulloin eli else

Jos ehtolauseen sulkujen sisällä oleva lauseke evaluoituu epätodeksi, ohjelmakoodin suoritus siirtyy ehtolauseen lohkon lopettavan aaltosulun seuraavaan lauseeseen. Tämä ei aina ole toivottua, vaan usein halutaan luoda vaihtoehtoinen toiminta tilanteeseen, missä ehtolauseen lauseke on epätotta.

Tämä onnistuu if-komennon yhteydessä käytettävän else-komennon avulla.

int luku = 4;

if (luku > 5) {
    System.out.println("Lukusi on suurempi kuin viisi!");
} else {
    System.out.println("Lukusi on viisi tai alle!");
}
Lukusi on viisi tai alle!

Jos ehtolauseeseen on määritelty else-haara, suoritetaan else-haaran määrittelemä lohko jos ehtolauseen ehto ei ole totta. Komento else tulee samalle riville if-komennon määrittelemän lohkon lopettavan aaltosulun kanssa.

Huom! Jos et sisennä em. tavalla, tyylitarkastaja valittaa "Line xx: '}' should be on the same line."

Tee ohjelma, joka kysyy käyttäjältä kokonaisluvun ja kertoo, onko se positiivinen (eli suurempi kuin nolla) vai ei.

Anna luku: 5

Luku on positiivinen.
Anna luku: -2

Luku ei ole positiivinen.

Tee ohjelma, joka kysyy käyttäjän ikää ja kertoo, onko tämä täysi-ikäinen (eli 18-vuotias tai vanhempi).

Kuinka vanha olet? 12

Et ole täysi-ikäinen!
Kuinka vanha olet? 32

Olet täysi-ikäinen!

Lisää vaihtoehtoja: else if

Jos vaihtoehtoja on useampia käytetään else if-komentoa. Komento else if on kuin else, mutta lisäehdolla. else if tulee if-ehdon jälkeen, ja niitä voi olla useita.

int luku = 3;

if (luku == 1) {
    System.out.println("Luku on yksi");
} else if (luku == 2) {
    System.out.println("Lukuna on kaksi");
} else if (luku == 3) {
    System.out.println("Kolme lienee lukuna!");
} else {
    System.out.println("Jotain muuta!");
}
Kolme lienee lukuna!

Luetaan yllä oleva esimerkki: 'Jos luku on yksi, tulosta "Luku on yksi", muuten jos luku on kaksi, tulosta "Lukuna on kaksi", muuten jos lukuna on kolme, tulosta "Kolme lienee lukuna!". Muulloin, tulosta "Jotain muuta!"'.

Yllä olevan ohjelman askeleittainen visualisointi:

Tee ohjelma, joka kysyy käyttäjältä kaksi kokonaislukua ja tulostaa niistä suuremman. Jos luvut ovat yhtä suuret, ohjelma huomaa myös tämän.

Esimerkkitulostuksia:

Anna ensimmäinen luku: 5
Anna toinen luku: 3

Suurempi luku: 5
Anna ensimmäinen luku: 5
Anna toinen luku: 8

Suurempi luku: 8
Anna ensimmäinen luku: 5
Anna toinen luku: 5

Luvut ovat yhtä suuret!

Vertailujen suoritusjärjestys

Vertailut suoritetaan järjestyksessä ylhäältä alaspäin. Kun suorituksessa päästään ehtolauseeseen, jonka ehto on totta, suoritetaan lohko ja lopetetaan vertailu.

int luku = 5;

if (luku == 0) {
    System.out.println("Luku on nolla.");
} else if (luku > 0) {
    System.out.println("Luku on suurempi kuin nolla.");
} else if (luku > 2) {
    System.out.println("Luku on suurempi kuin kaksi.");
} else {
    System.out.println("Luku on pienempi kuin nolla.");
}
Luku on suurempi kuin nolla.

Yllä oleva esimerkki tulostaa merkkijonon "Luku on suurempi kuin nolla." vaikka myös ehto luku > 2 on totta. Vertailu lopetetaan ensimmäiseen valintakäskyyn, jonka ehto on totta.

Tee ohjelma, joka ilmoittaa kurssiarvosanan seuraavan taulukon mukaisesti.

pistemäärä arvosana
< 0 mahdotonta!
0-69 hylätty
70-75 1
76-80 2
81-85 3
86-90 4
91-100 5
> 100 uskomatonta!

Esimerkkitulostuksia:

Anna pisteet [0-100]: 37

Arvosana: hylätty
Anna pisteet [0-100]: 76

Arvosana: 2
Anna pisteet [0-100]: 95

Arvosana: 5
Anna pisteet [0-100]: -3

Arvosana: mahdotonta!

Tehtävän graafiseen käyttöliittymään on lisätty liukuri sekä tekstikenttä.

Tutustu ohjelman koodiin ja muokkaa ohjelmaa siten, että tekstikentän arvo muuttuu liukurista saatavien arvojen perusteella seuraavasti:

  • Jos liukurin arvo on 0, tekstin tulee olla "Ei lainkaan."
  • Jos liukurin arvo on 1-25, tekstin tulee olla "Vähän."
  • Jos liukurin arvo on 26-74, tekstin tulee olla "Kohtalaisesti."
  • Jos liukurin arvo on 75-99, tekstin tulee olla "Paljon."
  • Jos liukurin arvo on 100, tekstin tulee olla "Kaikki."

Huomaa, ettei ohjelmakoodista tarvitse ymmärtää kokonaisuudessaan -- opimme luomaan graafisia käyttöliittymiä Ohjelmoinnin jatkokurssilla.

Ehtolauseen lauseke ja totuusarvomuuttuja

Ehtolauseen sulkuihin asetettavan arvon tulee olla lausekkeen evaluoinnin jälkeen totuusarvotyyppinen. Totuusarvomuuttujan tyyppi on boolean ja arvo true tai false.

boolean onkoTotta = true;
System.out.println("Totuusarvomuuttujan arvo on " + onkoTotta);
Totuusarvomuuttujan arvo on true

Ehtolauseen voi suorittaa myös seuraavasti:

boolean onkoTotta = true;

if (onkoTotta) {
    System.out.println("Aika vinhaa!");
}
Aika vinhaa!

Vertailuoperaattoreita voi käyttää myös ehtojen ulkopuolella. Tällöin vertailun tuloksena saatu totuusarvo asetetaan talteen totuusarvomuuttujaan myöhempää käyttöä varten.

int eka = 1;
int toka = 3;

boolean onkoSuurempi = eka > toka;

Yllä olevassa esimerkissä totuusarvomuuttuja onkoSuurempi sisältää nyt totuusarvon false. Yllä olevaa esimerkkiä voi myös jatkaa ja ottaa siihen mukaan ehtolauseen.

int eka = 1;
int toka = 3;

boolean onkoPienempi = eka < toka;

if (onkoPienempi) {
    System.out.println("1 on pienempi kuin 3!");
}

Yllä olevassa kuvassa ohjelmakoodia on suoritettu niin pitkään, että ohjelman muuttujat on luotu ja niihin on asetettu arvot. Muuttujassa onkoPienempi on arvona true. Seuraavana suoritetaan vertailu if (onkoPienempi) -- muuttujaan onkoPienempi liittyvä arvo löytyy sen lokerosta, ja lopulta ohjelma tulostaa:

1 on pienempi kuin 3!
Jakojäännös

Jakojäännös on hieman harvemmin käytetty operaatio, joka on kuitenkin varsin näppärä kun halutaan tarkistaa esimerkiksi luvun jaollisuutta. Jakojäännösoperaation merkki on %.

int jakojaannos = 7 % 2;
System.out.println(jakojaannos); // tulostaa 1

System.out.println(5 % 3); // tulostaa 2
System.out.println(7 % 4); // tulostaa 3
System.out.println(8 % 4); // tulostaa 0
System.out.println(1 % 2); // tulostaa 1

Jos haluamme tietää onko käyttäjän syöttämä luku jaollinen neljälläsadalla, tarkastamme onko syötetyn luvun jakojäännös neljänsadan suhteen nolla.

Scanner lukija = new Scanner(System.in);
int luku = Integer.parseInt(lukija.nextLine());
int jakojaannos = luku % 400;

if (jakojaannos == 0) {
    System.out.println("Luku " + luku + " on jaollinen neljälläsadalla.");
} else {
    System.out.println("Luku " + luku + " ei ole jaollinen neljälläsadalla.");
}

Koska jakojäännös on samanlainen operaatio kuin muutkin laskut, voi sen asettaa osaksi valintakäskyä.

Scanner lukija = new Scanner(System.in);
int luku = Integer.parseInt(lukija.nextLine());

if (luku % 400 == 0) {
    System.out.println("Luku " + luku + " on jaollinen neljälläsadalla.");
} else {
    System.out.println("Luku " + luku + " ei ole jaollinen neljälläsadalla.");
}

Tee ohjelma, joka kysyy käyttäjältä luvun ja ilmoittaa, onko syötetty luku parillinen vai pariton.

Anna luku: 2
Luku 2 on parillinen.
Anna luku: 7
Luku 7 on pariton.

Vihje: Luvun jakojäännös 2:lla kertoo, onko luku parillinen vai pariton. Jakojäännös taas saadaan %-operaattorilla, tehtäväpohjassa on lisää ohjeita miten parittomuustarkastus hoituu jakojäännöksen avulla.

Nea ja Vilma järjestävät reiluja pitsabileitä. Reilut pitsabileet ovat kuin normaalit pitsabileet, mutta reiluissa pitsabileissä kaikki saavat täsmälleen saman määrän pitsapaloja. Tehtävänäsi on kirjoittaa ohjelma, joka laskee ylijäävien pitsan palojen määrän.

Montako osallistujaa? 5
Montako pitsaa? 2
Montako palaa per pitsa? 6

Paloja jää yli: 2
Montako osallistujaa? 14
Montako pitsaa? 2
Montako palaa per pitsa? 6

Paloja jää yli: 12

Loogiset operaatiot

Materiaalin esimerkeissä ja tehtävissä käytetyt ehtolauseet ovat tähän mennessä käyttäneet yksinkertaisia lausekkeita, joilla on tarkasteltu ehtolauseeseen ja toistolauseeseen liittyvän lähdekoodin suorittamista. Esim.

if (lauseke) {
    System.out.println("Suoritetaan jos lausekkeen arvo on true");
}
int luku = 2;

if (luku % 2 == 0) {
    System.out.println("Luku on parillinen");
}
Luku on parillinen

Ehtolauseen lauseke voi koostua myös useammasta osasta, joissa käytetään loogisia operaatioita ja && ja tai ||. Kaksi ehtoa sisältävä lauseke, jossa on ja-operaatio on totta jos ja vain jos kummatkin ehdoista ovat tosia. Toisaalta, kaksi ehtoa sisältävä lauseke, jossa on tai-operaatio on totta jos jompikumpi tai molemmat ehdoista ovat tosia.

Seuraavassa yhdistetään &&:lla eli ja-operaatiolla kaksi yksittäistä ehtoa. Koodilla tarkistetaan, onko muuttujassa oleva luku suurempi kuin 4 ja pienempi kuin 11, eli siis välillä 5-10:

System.out.println("Onkohan luku väliltä 5-10: ");
int luku = 7;

if (luku > 4 && luku < 11) {
    System.out.println("On! :)");
} else {
    System.out.println("Ei ollut :(")
}
Onkohan luku väliltä 5-10:
On! :)

Seuraavassa annetaan ||:n eli tai-operaation avulla kaksi vaihtoehtoa, onko luku pienempi kuin 0 tai suurempi kuin 100. Ehto toteutuu jos luku täyttää jommankumman ehdon:

System.out.println("Onkohan luku pienempi kuin 0 tai suurempi kuin 100");
int luku = 145;

if (luku < 0 || luku > 100) {
    System.out.println("On! :)");
} else {
    System.out.println("Ei ollut :(")
}
Onkohan luku pienempi kuin 0 tai suurempi kuin 100
On! :)
  • Looginen operaatio ja: lauseke1 && lauseke2 lausekkeen arvo on tosi kun molemmat ehdoista ovat tosia
  • Looginen operaatio tai: lauseke1 || lauseke2 lausekkeen arvo on tosi jos jompikumpi tai molemmat ehdoista tosia

Tee ohjelma, joka kysyy käyttäjän iän ja tarkistaa, että se on mahdollinen (ainakin 0 ja korkeintaan 120).

Kuinka vanha olet? 10
OK
Kuinka vanha olet? 55
OK
Kuinka vanha olet? -3
Mahdotonta!
Kuinka vanha olet? 150
Mahdotonta!

Ongelman ratkaiseminen osa kerrallaan

Tutustutaan klassiseen ohjelmointiongelmaan:

'Kirjoita ohjelma, joka kysyy käyttäjältä lukua yhden ja sadan väliltä ja tulostaa luvun. Jos luku on kolmella jaollinen, luvun sijaan tulostetaan "Fizz". Jos luku on viidellä jaollinen, luvun sijaan tulostetaan "Buzz". Jos luku on sekä kolmella että viidellä jaollinen, luvun sijaan tulostetaan "FizzBuzz"'.

Ohjelmoija lähtee ratkaisemaan tehtävää lukemalla ongelmakuvauksen, ja luomalla ohjelmakoodia ongelmakuvausta seuraten. Koska ohjelman suoritusehdot esitellään ongelmassa annetussa järjestyksessä, muodostuu ohjelman rakenne järjestyksen perusteella. Ohjelman rakenne muodostuu seuraavien askelten perusteella:

  1. Tee ohjelma, joka lukee luvun käyttäjältä ja tulostaa sen.
  2. Jos luku on jaollinen kolmella, tulosta luvun sijaan merkkijono "Fizz".
  3. Jos luku on jaollinen viidellä, tulosta luvun sijaan merkkijono "Buzz".
  4. Jos luku on jaollinen kolmella ja viidellä, tulosta luvun sijan merkkijono "FizzBuzz".

Jos-tyyppiset ehdot on helppo toteuttaa if - else if - else -valintakäskyjen avulla. Alla oleva koodi on toteutettu yllä olevien askelten perusteella, mutta se ei kuitenkaan toimi oikein. Kokeile!

Scanner lukija = new Scanner(System.in);

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

if (luku % 3 == 0) {
    System.out.println("Fizz");
} else if (luku % 5 == 0) {
    System.out.println("Buzz");
} else if (luku % 3 == 0 && luku % 5 == 0) {
    System.out.println("FizzBuzz");
} else {
    System.out.println(luku);
}

Valintakäskyjen suoritusjärjestyksestä

Edellisessä lähestymistavassa ongelmana on se, että valintakäskyjen läpikäynti lopetetaan ensimmäiseen ehtoon, jonka arvo on totta. Esimerkiksi luvulla 15 tulostetaan merkkijono "Fizz", sillä luku on kolmella jaollinen (15 % 3 == 0).

Yksi lähestymistapa yllä olevan ajatusketjun kehittämiseen on ensin etsiä vaativin ehto ja toteuttaa se. Tämän jälkeen toteutettaisiin muut ehdot. Yllä olevassa esimerkissä ehto "jos luku on jaollinen kolmella ja viidellä" vaatii kahden tapauksen toteutumista. Nyt ajatusketju olisi muotoa.

  1. Tee ohjelma, joka lukee luvun käyttäjältä ja tulostaa sen.
  2. Jos luku on jaollinen kolmella ja viidellä, tulosta luvun sijan merkkijono "FizzBuzz".
  3. Jos luku on jaollinen kolmella, tulosta luvun sijaan merkkijono "Fizz".
  4. Jos luku on jaollinen viidellä, tulosta luvun sijaan merkkijono "Buzz".

Nyt ongelmakin tuntuu ratkeavan.

Scanner lukija = new Scanner(System.in);

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

if (luku % 3 == 0 && luku % 5 == 0) {
    System.out.println("FizzBuzz");
} else if (luku % 3 == 0) {
    System.out.println("Fizz");
} else if (luku % 5 == 0) {
    System.out.println("Buzz");
} else {
    System.out.println(luku);
}
2
2
5
Buzz
30
FizzBuzz

Vuosi on karkausvuosi, jos se on jaollinen 4:llä. Kuitenkin jos vuosi on jaollinen 100:lla, se on karkausvuosi vain silloin, kun se on jaollinen myös 400:lla.

Tee ohjelma, joka lukee käyttäjältä vuosiluvun, ja tarkistaa, onko vuosi karkausvuosi.

Anna vuosi: 2011
Vuosi ei ole karkausvuosi.
Anna vuosi: 2012
Vuosi on karkausvuosi.
Anna vuosi: 1800
Vuosi ei ole karkausvuosi.
Anna vuosi: 2000
Vuosi on karkausvuosi.

Vihje: mieti ongelmaa if, else if, else if, ... -vertailujen ketjuna ja aloita ohjelman rakentaminen tilanteesta, missä voit olla varma, että ohjelma ei ole karkausvuosi.

Scanner lukija = new Scanner(System.in);
int luku = Integer.parseInt(lukija.nextLine());

if (luku % 4 != 0) {
    System.out.println("Vuosi ei ole karkausvuosi.");
} else if (...) {
    ...
} ...

Toistaminen

Tietokone on erittäin tehokas asioiden toistaja.

Toistolause ja ikuinen toisto

Toistolause sisältää lausekkeen, jonka perusteella päätellään jatketaanko toistoa, sekä lohkon, joka sisältää toistettavan lähdekoodin. Toistolauseen muoto on seuraava.

while (lauseke) {
    // lohkon sisältö
}

Lausekkeen arvon tulee evaluoitua totuusarvoiseksi muuttujaksi. Jos lausekkeen arvoksi asettaa arvon true, toistoa jatketaan ikuisesti. Seuraava ohjelma tulostaa merkkijonoa osaan ohjelmoida! ikuisesti eli "äärettömän monta kertaa":

while (true) {
    System.out.println("osaan ohjelmoida!");
}

Ikuisen toiston sisältävä ohjelma ei sammu itsestään. Ohjelman sammutus tapahtuu NetBeansissa tulostusikkunan vasemmalla puolella olevaa punaista nappia painamalla.

public class Esimerkki { public static void main(String[] args) { // Tänne kirjoitetaan ohjelman käyttämät lauseet while (true) { System.out.println("Uudestaan!"); } } }
public class Esimerkki { public static void main(String[] args) { // Tänne kirjoitetaan ohjelman käyttämät lauseet // MARK } }

Toistolauseen päättäminen

Toistolauseen saa päätettyä komennolla break. Kun tietokone suorittaa komennon break, siirtyy se toistolauseen lohkoa seuraavan komennon suorittamiseen.

Scanner lukija = new Scanner(System.in);

while (true) {
    System.out.println("osaan ohjelmoida!");

    System.out.print("jatketaanko (positiivinen luku jatkaa)? ");
    int komento = Integer.parseInt(lukija.nextLine());
    if (komento <= 0) {
        break;
    }
} // lohko päättyy

// toistolauseen lohkoa seuraava komento
System.out.println("kiitos ja kuulemiin.");

Yllä olevassa esimerkissä toisto etenee siten että ensin tulostuu osaan ohjelmoida! ja tämän jälkeen ohjelma kysyy käyttäjältä jatketaanko vielä. Jos käyttäjä syöttää nollan tai negatiivisen luvun, suoritetaan komento break. Tällöin suoritus siirtyy toistolausetta seuraavaan komentoon, joka tulostaa merkkijonon kiitos ja kuulemiin.

osaan ohjelmoida!
jatketaanko (negatiivinen luku lopettaa)? 5
osaan ohjelmoida!
jatketaanko (negatiivinen luku lopettaa)? 2
osaan ohjelmoida!
jatketaanko (negatiivinen luku lopettaa)? -1
kiitos ja kuulemiin.

Kirjoita edellä olevaa toistolause-esimerkkiä mukaillen ohjelma, joka kysyy käyttäjältä lukuja kunnes käyttäjä syöttää luvun 4.

Syötä luku 5
Syötä luku 744
Syötä luku 22
Syötä luku -1
Syötä luku 4

Muuttujat toistolauseen ulkopuolella

Toistolauseissa halutaan usein laskea asioita. Tällöin ohjelmoijan tulee määritellä laskettavien asioiden ylläpitoon muuttuja ennen toistolauseen alkua, jotta muuttujan arvoa voidaan päivittää toistolauseessa. Alla olevassa esimerkissä ohjelma laskee syötettyjen ykkösten lukumäärän. Syötteiden lukeminen lopetetaan kun käyttäjä syöttää luvun 0.

Scanner lukija = new Scanner(System.in);

int ykkosia = 0;

while (true) {
    System.out.print("Syötä luku (0 lopettaa): ");
    int luku = Integer.parseInt(lukija.nextLine());
    if (luku == 0) {
        break;
    }

    if (luku == 1) {
        ykkosia = ykkosia + 1;
    }
}

System.out.println("Ykkösiä yhteensä: " + ykkosia);
Syötä luku 1
Syötä luku 2
Syötä luku 1
Syötä luku -1
Syötä luku 0
Ykkösiä yhteensä: 2

Tehtäväpohjassa on toistolausetta käyttävä ohjelma, joka lukee käyttäjältä viisi lukua ja tulostaa niiden summan. Muokkaa ohjelmaa siten, että ohjelma voi lukea lähes rajattoman määrän lukuja: lukeminen tulee lopettaa vasta kun käyttäjä syöttää luvun 0.

Yhteenveto

Ensimmäinen osa käsitteli ohjelmoinnin ja tietokoneiden toiminnan kannalta oleellisia ydinasioita. Näitä ovat muuttujat ja tieto, laskeminen, syötteen käsittely ja lukeminen, vertailu ja päätösten tekeminen sekä toistaminen.

Tehdään ensimmäisen osan loppuun vielä ohjelma, missä kerrataan ydinasioita.

Paroni von Münchhausen oli Saksan Hannoverissa syntynyt 1700-luvulla elänyt herrasmies. Hänet muistetaan ensisijaisesti sotakertomuksistaan, joista yksi liittyi tykinkuulalla lentämiseen. Oletetaan tässä, että Paronin istuimena käyttämä kuula ammuttiin tykillä suoraan ylöspäin ja tykinkuulan lähtönopeus on 1700-luvulle tyypillinen noin 400 metriä sekunnissa. Kirjoitetaan ohjelma, joka kertoo Paronin korkeuden ja nopeuden sekunti sekunnilta. Ohjelman suorituksen tulee loppua kun Paroni palaa takaisin maahan. Tämän jälkeen ohjelman tulee vielä kertoa suurin Paronin saavuttama korkeus.

Yllä kuvatun ongelman ratkaisu kannattaa tehdä useammassa osassa. Tarvitsemme toistolauseen, missä korkeuden muutosta tarkastellaan sekunti sekunnilta. Tarvitsemme ohjelmaan myös Paronin lentoon vaikuttavan painovoiman. Lopulta tarvitsemme muuttujan, mitä käytetään suurimman korkeuden tarkasteluun.

Tehdään ensin ikuisesti jatkuva ohjelma, joka tulostaa korkeuden sekunti sekunnilta. Tässä kohdassa emme vielä ota painovoimaa huomioon emmekä pyri selvittämään suurinta korkeutta.

int sekunteja = 0;
int nopeus = 400;
int korkeus = 0;

System.out.println("Sekunnit: " + sekunteja);
System.out.println("Nopeus: " + nopeus);
System.out.println("Korkeus: " + korkeus);

while (true) {
    korkeus = korkeus + nopeus;
    sekunteja = sekunteja + 1;

    System.out.println("");
    System.out.println("Sekunnit: " + sekunteja);
    System.out.println("Nopeus: " + nopeus);
    System.out.println("Korkeus: " + korkeus);
}
Sekunnit: 0
Nopeus: 400
Korkeus: 0

Sekunnit: 1
Nopeus: 400
Korkeus: 400

Sekunnit: 2
Nopeus: 400
Korkeus: 800

...

Ensimmäinen osa toimii toivotulla tavalla. Lisätään seuraavaksi ohjelmaan painovoima.

Saatamme muistaa fysiikan oppitunneilta, että maan painovoima on noin 9,81 m/s2. Käytännössä siis painovoima hidastaa tykinkuulan (ja Paronin) nopeutta joka sekunti noin 9,81 metrillä -- ohjelmallisesti tämän voi toteuttaa vähentämällä nopeus-muuttujasta 9.81 jokaisella toiston kierroksella.

while (true) {
    korkeus = korkeus + nopeus;
    sekunteja = sekunteja + 1;
    nopeus = nopeus - 9.81;
    // ...
}

Mutta! Muuttuja nopeus on kokonaisluku. Emme voi vähentää kokonaisluvusta liukulukua. Muutetaan ohjelmaa siten, että muuttuja nopeus on liukuluku -- vastaava muutos tehdään muuttujalle korkeus, sillä myös siihen lisätään liukuluku.

int sekunteja = 0;
double nopeus = 400;
double korkeus = 0;

System.out.println("Sekunnit: " + sekunteja);
System.out.println("Nopeus: " + nopeus);
System.out.println("Korkeus: " + korkeus);

while (true) {
    korkeus = korkeus + nopeus;
    sekunteja = sekunteja + 1;
    nopeus = nopeus - 9.81;

    System.out.println("");
    System.out.println("Sekunnit: " + sekunteja);
    System.out.println("Nopeus: " + nopeus);
    System.out.println("Korkeus: " + korkeus);
}
Sekunteja: 0
Nopeus: 400.0
Korkeus: 0.0

Sekunnit: 1
Nopeus: 390.19
Korkeus: 400.0

Sekunnit: 2
Nopeus: 380.38
Korkeus: 790.19

...

Ohjelmassa on nyt sekä sekuntikohtainen nopeuden ja korkeuden tarkastelu sekä painovoima. Ohjelman suoritus ei kuitenkaan koskaan lopu.

Lisätään toistolauseeseen lopetusehto, missä toistolauseesta poistutaan jos korkeus on negatiivinen. Tämä tarkoittaa käytännössä sitä, että Paroni on päässyt takaisin maan pinnalle.

int sekunteja = 0;
double nopeus = 400;
double korkeus = 0;

System.out.println("Sekunnit: " + sekunteja);
System.out.println("Nopeus: " + nopeus);
System.out.println("Korkeus: " + korkeus);

while (true) {
    if (korkeus < 0) {
        break;
    }

    korkeus = korkeus + nopeus;
    sekunteja = sekunteja + 1;
    nopeus = nopeus - 9.81;

    System.out.println("");
    System.out.println("Sekunnit: " + sekunteja);
    System.out.println("Nopeus: " + nopeus);
    System.out.println("Korkeus: " + korkeus);
}
Sekunteja: 0
Nopeus: 400.0
Korkeus: 0.0

Sekunnit: 1
Nopeus: 390.19
Korkeus: 400.0

Sekunnit: 2
Nopeus: 380.38
Korkeus: 790.19

... monta riviä

Sekunnit: 83
Nopeus: -414.23000000000013
Korkeus: -183.4300000000065

Ohjelma käy nyt sekunti sekunnilta Paronin korkeuden ja nopeuden. Edellä annetun esimerkkitulosteen perusteella Paroni palaa maahan hieman yli 400 metrin sekuntivauhtia (eli hieman yli 1400 kilometriä tunnissa).

Selvitetään vielä lopuksi Paronin lennon suurin korkeus. Haluamme tulostaa korkeuden ohjelman lopussa, eli toistolauseen jälkeen. Tarvitsemme käytännössä uuden muuttujan, jonka tehtävänä on säilöä suurin korkeus. Muuttujan arvo päivitetään tarvittaessa toistolauseessa aina korkeuden päivityksen jälkeen.

double suurinkorkeus = 0;

int sekunteja = 0;
double nopeus = 400;
double korkeus = 0;

System.out.println("Sekunnit: " + sekunteja);
System.out.println("Nopeus: " + nopeus);
System.out.println("Korkeus: " + korkeus);

while (true) {
    if (korkeus < 0) {
        break;
    }

    korkeus = korkeus + nopeus;
    sekunteja = sekunteja + 1;
    nopeus = nopeus - 9.81;

    if (korkeus > suurinkorkeus) {
        suurinkorkeus = korkeus;
    }

    System.out.println("");
    System.out.println("Sekunnit: " + sekunteja);
    System.out.println("Nopeus: " + nopeus);
    System.out.println("Korkeus: " + korkeus);
}

System.out.println("");
System.out.println("Suurin korkeus: " + suurinkorkeus);
Sekunteja: 0
Nopeus: 400.0
Korkeus: 0.0

Sekunnit: 1
Nopeus: 390.19
Korkeus: 400.0

Sekunnit: 2
Nopeus: 380.38
Korkeus: 790.19

... monta riviä

Sekunnit: 83
Nopeus: -414.23000000000013
Korkeus: -183.4300000000065

Suurin korkeus: 8355.8

Paroni olisi päässyt esimerkissämme siis lähes 83 sekunnin lentomatkalle sekä yli kahdeksan kilometrin korkeuteen.

Tässä tehtävässä luot edellä kuvatun ohjelman suoraan ylöspäin ammutun tykinkuulan suurimman korkeuden selvittämiseen. Ohjelmassa on kuitenkin muutamia parannuksia: käyttäjä voi syöttää sekä lähtönopeuden että painovoiman. Tämän lisäksi tulostuksessa arvot on eroteltu sarkaimilla, mikä mahdollistaa niiden helpon siirtämisen esimerkiksi taulukkolaskentaohjelmiin.

Tässä muutamia vinkkejä tehtävän tekemisen helpottamiseen.

Vinkki 1. Saat luettua käyttäjältä liukuluvun komennolla Double.parseDouble(lukija.nextLine()). Ohjelmassa tämä tapahtuu seuraavasti.

Scanner lukija = new Scanner(System.in);

System.out.println("Syötä liukuluku");
double luku = Double.parseDouble(lukija.nextLine());
System.out.println("Syötetty: " + luku);
Syötä liukuluku
8.91
Syötetty: 8.91

Vinkki 2. Saat tulostettua arvoja sarkaimilla erotettuna erikoismerkin "\t" avulla.

int sekunteja = 0;
double korkeus = 0;
double suurinkorkeus = 0;

System.out.println(sekunteja + "\t" + korkeus + "\t" + nopeus);
0    0.0    0.0

Tehtävänäsi on siis toteuttaa ohjelma, joka kysyy käyttäjältä tykinkuulan lähtönopeutta ja painovoimaa. Ohjelman tulee tulostaa tykinkuulan korkeus sekunti sekunnilta kunnes tykinkuula palaa maahan. Ohjelman tulee lisäksi ohjelman lopussa kertoa tykinkuulan suurin korkeus.

Ohjelman tulostuksen tulee olla seuraavanlainen. Alla olevassa esimerkissä lähtönopeudeksi on syötetty 42.0 ja painovoimaksi 9.81.

Syötä tykinkuulan lähtönopeus:
42.0
Syötä painovoima:
9.81

0	0.0	42.0
1	42.0	32.19
2	74.19	22.379999999999995
3	96.57	12.569999999999995
4	109.13999999999999	2.7599999999999945
5	111.89999999999998	-7.050000000000006
6	104.84999999999997	-16.860000000000007
7	87.98999999999995	-26.67000000000001
8	61.31999999999994	-36.48000000000001
9	24.839999999999932	-46.29000000000001

Tykinkuulan suurin korkeus oli 111.89999999999998

Alla olevassa esimerkissä taas oletetaan, että lähtönopeus on 15 ja painovoima 3.5.

Syötä tykinkuulan lähtönopeus:
15
Syötä painovoima:
3.5

0	0.0	15.0
1	15.0	11.5
2	26.5	8.0
3	34.5	4.5
4	39.0	1.0
5	40.0	-2.5
6	37.5	-6.0
7	31.5	-9.5
8	22.0	-13.0
9	9.0	-16.5

Tykinkuulan suurin korkeus oli 40.0

Huom! Vaikka edellä on syötettynä lähtönopeudeksi kokonaisluku, voi sen silti ohjelmassa toteuttaa niin, että luku asetetaan desimaalilukuun. Komento Double.parseDouble(lukija.nextLine()) siis toimi, vaikka käyttäjä syöttäisi kokonaisluvun.

Kun ohjelman suoritus on valmis, voit kokeilla lukujen syöttämistä taulukkolaskentaohjelmaan. Alla oleva tykinkuulan korkeuden kuvaaja on luotu edellisen esimerkin tulosteesta Google Driven avulla.

Sisällysluettelo