Helsingin yliopisto / Tietojenkäsittelytieteen laitos / 581258-1 Johdatus ohjelmointiin
Copyright © 1998 Arto Wikla. Tämän oppimateriaalin käyttö on sallittu vain yksityishenkilöille opiskelutarkoituksissa. Materiaalin käyttö muihin tarkoituksiin, kuten kaupallisilla tai muilla kursseilla, on kielletty.

3.4 Lauseita

(Muutettu viimeksi 8.11.1998)

Kuten edellisen luvun alussa todettiin, lauseke (expression) on ohjelmointikielen ilmaus, jolla on jokin arvo ja tuolla arvolla on jokin tyyppi. Lause (statement) puolestaan ilmaisee jonkin algoritmisen toiminnon, "tehdään jotakin"... Javassa on lisäksi lausekelauseita (expression statements), joita voi käyttää sekä lausekkeen, että lauseen tapaan. Laskettua arvoa ei jälkimmäisessä tapauksessa käytetä mihinkään. Laskennalla voi kuitenkin olla haluttuja (sivu-)vaikutuksia.

Ns. rakenteisten lauseiden tehtävä on valita suoritettavia lauseita, toistaa lauseita, ... Ne ovat rakenteisia, juuri siksi, että niiden rakenneosina on lauseita.

Yksinkertaiset lauseet päättyvät aina puolipisteeseen. Rakenteisilta lauseilta tätä ei vaadita. Sallittua se silti on, koska Javassa on ns. tyhjä lause.

Tämä luku esittelee tiiviisti useimmat Javan lauseet.

Lohkot ja muuttujien määrittelylauseet

Lohko on jono lauseita merkkien "{" ja "}" välissä. Lohkossa voi olla muiden lausetyyppien lisäksi paikallisten muuttujien määrittelyitä. Tällaiset määrittelyt ovat voimassa vain kyseisessä lohkossa ja vain määrittelykohdasta eteenpäin. Muuttujien määrittelyt voivat siis sijaita vapaasti muiden lauseiden joukossa! Muuttujien määrittelyt ovat suoritettavia lauseita: mahdollisen alkuarvon laskeminen ja sijoittaminen muuttujaan tehdään tavallisen sijoitusoperaation tapaan. Määrittelyt suoritetaan vasemmalta oikealle.
{ int a = 1, b, c = 2*a;
  b = a * 2;
  int d = a + b;   // d on käytössä vasta tästä alkaen!!
  { int e = d + b; // e on käytössä tästä alkaen
    d = a + e;
  }                // e:n käyttöalue loppuu tähän
  c = d + b;
}
Huom: Tavallisesti on toki selkeintä määritellä lohkon muuttujat lohkon alussa! Toisaalta periaate "määrittele mahdollisimman syvällä, mahdollisimman myöhään" on myös perusteltavissa. Miksi?

Huomattavaa:

Esimerkkejä muuttujien määrittelyistä (Esimerkit havainnollistavat määrittelyiden monia mahdollisuuksia, älkööt ne kuitenkaan ketään innostako vaikeaselkoisuuteen!):

long i;
int j = 1, k = 2, m, n = 0;

int eka=1, toka=eka+1, kolm=eka+2, nel=kolm+1;

double dd = 6.0, ee = dd*3.14;
float  ff = 3.21F;  // Liukulukuvakiot ovat
         // ----^!     oletusarvoisesti double-tyyppisiä!

int    ii = (int)ee, jj = '2';
char   cc = '#', bb = (char)dd;

String gg ="Miau!", hh = "tulos on "+ (ff+dd);
String nnn = 2 + 3 + "böö";   //nnn:n arvoksi tulee "5böö"
String mmm = 2 + (3 + "böö"); //mmm:n arvoksi tulee "23böö"

PikkuVarasto rr, pp = null, qq = new PikkuVarasto(10.0, "Mehu"); 

Metodeissa muuttujilla ei ole mitään oletusalkuarvoja (luokkien muuttujilla sellaiset sitävastoin on, tähän palataan luvussa 4.2).

Kääntäjä tarkistaa, ettei metodissa käytetä arvon antajana - esimerkiksi sijoitusoperaation oikena puolena tai tulostettavana - sellaista muuttujaa, jolle ei ole asetettu alkuarvoa.

Kääntäjä tekee ns. tietovirta-analyysin (data flow analysis) hyvin epäluuloisena: Jos tuollaista muuttujaa jossain tilanteessa edes saatettaisiin käyttää, kääntäjä ei anna armoa!

Huom: Koska määrittely on suoritettava lause, alkuarvon antava lauseke lasketaan kaikkine sivuvaikutuksineen joka suorituskerralla:

int a = 1;
for (int i=1; i<=3; ++i) {
  PikkuVarasto c = new PikkuVarasto(i*10.0, "Mehu");
  int b = ++a;

  System.out.println(b);
  // ...
}
Joka toistokerralla luodaan uusi PikkuVarasto-olio ja ohjelmanpätkä tulostaa luvut 2, 3 ja 4.

Lausekelauseet

Eräitä lausekkeita voi käyttää lauseiden tapaan. Lausekkeen sivuvaikutukset tekevät jotakin (hyödyllistä?) ja lausekkeen varsinainen arvo jätetään kylmästi käyttämättä. Lauseke kirjoitetaan sellaisenaan ja päätetään puolipisteeseen.

Vain seuraavia lausekkeita voi käyttää lauseina:

Huom: Muita lausekkeita ei siis voi käyttää lauseina! (Eikä "void" C:n tapaan ole tyyppi, jolla "arvon voi jättää käyttämättä".)

Esimerkkejä:

  i = 1;
  j = i + 4;

  ++i; // Kun 1:llä kasvatus- tai vähennyslauseketta 
  j++; // käytetään lauseena, järjestyksellä ei ole väliä!

  mehua.otaVarastosta(15); //vaikka:
                           // public double otaVarastosta(double)
                           //        ^^^^^^

  new PikkuVarasto(); // konstruktorin suoritus voi joskus
                      // olla ainoa, mitä halutaan

Ehdolliset lauseet if ja if-else

  if (ehto)
    lause


  if (ehto)
    lause1
  else
    lause2

Valintalause switch

  switch (lauseke) {
    case vakio1: lause1;
                 break;
    case vakio2: case vakio3:
                 lause2;
                 lause3;
                 break;
    default:     lause4;
                 break;
  }

Ehdolliset toistolauseet while ja do

  while (ehto) 
    lause


  do
    lause
  while (ehto);

For-toisto

  for (alustuslauseke; ehto; kasvatuslauseke)
    lause
For-lause vastaa rakennetta:
  {
    alustuslauseke;
    while (ehto) {
      lause
      kasvatuslauseke;
    }
  }
(Paitsi: continue-lauseella keskeytetty toisto suorittaa kasvatuslausekkeen ennen ehdon uutta testausta; continue-lause käsitellään seuraavana.)

For-lause voidaan nähdä "toiston yleisenä neliparametrisena rakenteena, johon kuuluu alkutoimet, päättöehto, päivitystoimet (kunkin toiston jälkeen) ja toistettava" (Tomi Silander).

Keskeytyslauseet break, continue ja return

Keskeytyslauseella keskeytetään rakenteisen lauseen suoritus: Javassa lausetta voi edeltää osoite. Break- ja continue-lauseilla voi rakenteisen lauseen osoitteeseen viittamaalla keskeyttää myös ulompien tasojen lauseita:
  ulompi: while (jotakin) {
            int i = 1;
            ...
  sisempi:  while (jotain muuta) {
              int a = 1;
              ...
              if (meni vähän pieleen)
                break sisempi;
              ...
              if (kaikki meni pieleen)
                break ulompi;
              ...
            }
          }

Keskeytyslauseet voivat joskus olla näppäriä esimerkiksi virhetilanteiden hoitamisessa. Ohjelman normaalin etenemisen ohjaamisessa niitä on syytä käyttää harkiten.

Muita lauseita

Ns. Poikkeukset (exceptions) ovat "poikkeuksellisia tilanteita" kesken normaalin ohjelmansuorituksen: tiedosto loppuu, merkkijono ei kelpaa kokonaisluvuksi, odotetun olion tilalla onkin null-arvo, taulukon indeksi menee ohjelmointivirheen takia sopimattomaksi, ... Poikkeustenkäsittelyvälineitä, try-catch- ja throw-lauseita, nähdään luvussa 5 tiedostojen käsittelyn yhteydessä.

Ns. rinnakkaisohjelmointia ("threadit") ja synchronized-lausetta ei tällä kurssilla käsitellä.


Takaisin luvun 3 sisällysluetteloon.