1. Java–kielen ohjausrakenteista ja operaattoreista

Ihvilläpä ihmettele

silmukalla suorittele

lopetukset laskeskele

virityksii vierastele.

 

Alusta kun ehto jääpi

siit silmukka iänikuinen

aina suru ei surkeen suuri

joutaapa avuksi tääkin.

 

Katkoo saapi keskeltäkin

jatkaa vaikka muualtakin

paluu kelpo keino myöskin

kunhan kaikki katseltuna.

 

Mitä tässä luvussa käsitellään?

·        if-else –lause

·        loogiset operaattorit: &&, || ja !

·        bittitason operaattorit: &,|,^ ja ~

·        silmukat while, do-while ja  for

·        silmukan "katkaisu" break, continue, goto

·        sijoituslauseet: = += -= jne.

·        valintalause switch

 

Syntaksi:

lause  joko       ylause;                            // HUOM! Puolipiste

       tai        lohko                              // eli koottu lause           

ylause            yksinkertainen lause             

  esim              a = b + 4

                    vaihda(a,b)

lohko             { lause1 lause2 lause3 }           // lauseita 0-n

  esim              { a = 5; b = 7; }     

ehto              lauseke joka tuottaa false tai true

  esim              a < 5

                    ( 5 < a ) && ( a < 10 )

                    !(a == 0)                        // jos a=0 => 1, muuten 0

  HUOM!           Vertailu a == 5

 

if-else           if ( ehto ) lause1

                  else lause2                        // ei pakollinen

while             while ( ehto ) lause;

do-while          do lause while ( ehto );

for               for ( ylause1a,ylause2a; ehto ; ylause1k,ylause2k ) lause

  esim              for ( i=0,s=0; i<10; i++ ) s += i;  // ylause1a                

switch            switch ( lauseke ) {

                    case arvo1: lause1 break;        // valintoja 0-n  

                    case arvo2:                      // arvolla 2 ja 3 sama

                    case arvo3: lause2 break;

                    default:    laused break;        // ei pakollinen

                  }

 

Luvun esimerkkikoodit:

http://www.mit.jyu.fi/~vesal/kurssit/ohj2/moniste/esim/java-silm/

 

Ohjelma jossa ei ole minkäänlaista valinnaisuutta tai silmukoita on varsin harvinainen.  Kertaamme seuraavassa Java–kielen tarjoamat mahdollisuudet suoritusjärjestyksen ohjaamiseen.  Samalla näemme kuinka suomenkielisen algoritmin kääntäminen ohjelmointikielelle on varsin mekaanista puuhaa.

1.1 if–lause

 Mikäli meillä on kaksi lukua, jotka pitäisi olla suuruusjärjestyksessä, voisimme hoitaa järjestämisen seuraavalla algoritmilla:

1. Jos luvut väärässä järjestyksessä,

     niin vaihda ne keskenään

 

Tämän kirjoittamiseksi ohjelmaksi tarvitsemme ehto–lausetta:

if ( ehto ) ylause1;

lause2;

 

Huomattakoon, että tässä sulut ehdon ympärillä ovat pakolliset.  lause1 suoritetaan vain kun ehto on voimassa. lause2 suoritetaan aina.  Lause voitaisiin kirjoittaa myös muodossa

if(ehto) ylause1;

lause2;

 

muttei näin tehdä, jotta erottaisimme paremmin funktion ja if–lauseen toisistaan.  Saa tulee koskemaan myös for, while ja muita vastaavia rakenteita.

1.1.1 Ehdolla suoritettava yksi lause

Olkoon meillä aliohjelma nimeltään tulosta, joka parametrina viedyn luvun:

if ( a > b ) tulosta(a);

 

1.1.2 Ehdolla suoritettava useita lauseita

Jos esimerkiksi luvut pitäisi vaihtaa keskenään, täytyisi meidän voida suorittaa useita lauseita muuttujien vaihtamiseksi.  Java–kielessä voidaan lausesuluilla kasata joukko lauseita yhdeksi lauseeksi (lohko, koottu lause, block):

Vinkki
A

Sisennä kauniisti

if ( a > b ) {

  t = a;

  a = b;

  b = t;

}

 

Huomautus! Lauseiden kirjoittaminen samalle riville ei auttaisi mitään, sillä

if ( a > b ) t = a; a = b; b = t;

/*  vastaisi loogisesti rakennetta: */

if ( a > b ) t = a;

a = b;

b = t;

 

Koodia voidaan kuitenkin usein lyhentää kirjoittamalla asioita samalle riville:

if ( a > b ) {

  t = a; a = b; b = t;

}

/* tai joskus jopa */

if ( a > b ) { t = a; a = b; b = t; }

 

Niin kauan kuin todella hallitsee asian, voi olla helpointa laittaa aina if–lauseen ainoakin suoritettava lause lausesulkuihin

if ( a > b ) {

  tulosta(a);

}

 

Mikäli sulkuja ei olisi, täytyisi toisen lauseen lisäyksen yhteydessä muistaa lisätä myös sulut (tosin eihän hyvin suunniteltua ohjelmaa tarvinnut enää jälkeenpäin paikata?).

Tehtävä 10.1  vaihda

Esitä pöytätestin avulla miksei vaihtaminen onnistu pelkästään lauseilla:

      a = b; b = a;

Tehtävä 10.2  abs

Kirjoita funktio

      int itseisarvo(int i),

joka palauttaa i:n itseisarvon (negat. muutet. posit.).

Tehtävä 10.3  jarjesta2

Kirjoita aliohjelma

      void tulosta2(int a, int b),

joka tulostaa luvut suuruusjärjestyksessä .

Tehtävä 10.4  maksimi ja minimi

Kirjoita funktio

      int maksimi(int a, int b),

joka palauttaa suuremman kahdesta luvusta.

 

Kirjoita vastaava funktio minimi.

 

1.2 Loogiset lausekkeet

Java–kielessä vain boolean-arvoiset lausekeet käsitellään loogisina lausekkeina.  Arvo false on epätosi ja true on tosi.

a = 4;

if ( a == 4 ) ...

boolean samat;

samat = ( a == 4 );

if ( samat ) ...

 

1.2.1 Vertailuoperaattorit

Vertailuoperaattorin käyttö muodostaa loogisen lausekkeen, jonka arvo on 0 tai 1.  Vertailuoperaattoreita ovat: 

==  yhtäsuuruus

!=  erisuuruus

<   pienempi kuin

<=  pienempi tai yhtä kuin

>   suurempi kuin

>=  suurempi tai yhtä kuin

 

Esimerkkejä vertailuoperaattoreiden käytöstä:

if ( a < 5 )  System.out.println("a alle viisi!");

if ( a > 5 )  System.out.println("a yli viisi!");

if ( a == 5 ) System.out.println("a tasan viisi!");

if ( a != 5 ) System.out.println("a ei ole viisi!");

 

1.2.2 Sijoitus palauttaa arvon!

Yhtäsuuruutta verrataan == operaattorilla, EI sijoituksella =.  Tämä on eräs tavallisimpia aloittelevan (ja kokeneenkin) C–ohjelmoijan virheitä:

/* Seuraava tulostaa vain jos a == 5 */

if ( a == 5 ) tulosta("a on viisi!\n");  /* Kääntyy Javassa ja C:ssä */

/* Seuraava sijoittaa aina a = 5 ja tulostaa AINA! */                  L

if ( a = 5 ) printf("a:ksi tulee AINA 5!\n");  /* Kääntyy vain C:ssä */

 

Sijoitus a=5 on myös lauseke, joka palauttaa arvon 5.  Siis sijoitus kelpaa tästä syystä vallan hyvin loogiseksi lausekkeeksi C-kielessä.  Onneksi Javassa tämä sijoituksen tuloksena synytynyt lausekkeen kokonaislukuarvo EI kelpaa boolean-arvoksi, joten kääntäjä ei hyväksy sijoitusta vahingossa yhtäsuuruuden vertailun tilalle..

Joskus ominaisuutta voidaan tarkoituksella käyttää hyväksikin.  Esimerkiksi halutaan sijoittaa AINA a=b ja sitten suorittaa jokin lause, mikäli b!=0.  Tämä voitaisiin kirjoittaa useilla eri tavoilla:

java-silm\Ifsij2.java - esimerkki tahallisesta sijoituksesta ehdossa

    int a,b=5;

    /*1*/  // a = b; if ( b ) tulosta("b ei ole nolla!");

    /*2*/  a = b; if ( b != 0 ) tulosta("b ei ole nolla!");

    /*3*/  // if ( a = b ) tulosta("b ei ole nolla!");

    /*4*/  if ( (a=b) != 0 ) tulosta("b ei ole nolla!");

 

Edellisistä tapa 3 on C–mäisin, mutta Java-kääntäjä ei onneksi hyväksy sitä.  Jotta C–mäinen tapa voitaisiin säilyttää, voidaan käyttää tapaa 4 jonka kääntäjä hyväksyy.  Oleellista on, että sijoitus on suluissa (muuten tulisi sijoitus a =(b!=0) ).  Mikäli asian toimimisesta on pieninkin epäilys kannattaa käyttää tapaa 2!

Tyypillinen esimerkki sijoituksesta ja testauksesta samalla on vaikkapa tiedoston lukeminen:

while ( ( rivi = f.readLine() ) != null ) { // jos sijoitus palauttaa null,

                                            // on tiedosto loppu

  ... käsitellään tiedoston riviä

}

 

Jos edellisen esimerkin tiedoston lukemisessa ei käytettäisi sijoitusta ja testiä samalla, pitäisi tämä kirjoittaa muotoon:

while ( true ) {

  rivi = f.readLine();

  if ( rivi == null ) break;

  ... käsitellään tiedoston riviä

}

 

1.3 Loogisten lausekkeiden yhdistäminen

Loogisia lauseita voidaan yhdistää loogisten operaatioiden avulla.  Tietysti lauseita voidaan yhdistää myös normaaleilla operaatioilla (+,,*,/), mutta tämä ei ole oikein hyvien tapojen mukaista.

1.3.1 Loogiset operaattorit &&, || ja !

&&  ja

||  tai

!   muuttaa ehdon arvon päinvastaiseksi (eli false–>true, true->false)

 

Mikäli yhdistettävät ehdot koostuvat esimerkiksi vertailuoperaattoreiden käytöstä, kannattaa ehtoja sulkea sulkuihin, jottei seuraa turhia epäselvyyksiä.

if ( ( rahaa > 50 ) && ( kello < 19 ) )  tulosta("Mennään elokuviin!");

if ( ( rahaa < 50 ) || ( kello >3 ) )    tulosta("Ei kannata mennä kapakkaan!");

if ( ( 8 <= kello ) && ( kello <= 16 ) ) tulosta("Pitäisi olla töissä!");

if ( ( rahaa == 0 ) || ( sademaara < 10 ) )  tulosta("Kävele!");

 

Usein tulee vastaan tilanne, jossa pitäisi testata onko luku jollakin tietyllä välillä.  Esimerkiksi onko

1900 <= vuosi <= 1999

 

palauttaisi C-kielisenä lauseena aina 1.  Miksikö?  Koska lause jäsentyy

( 1900 <= vuosi ) <= 1999  

     0 tai 1      <= 1999  eli aina 1

 

Javassa onneksi lauseke ei edes käänny, koska totuusarvoa ja kokonaislukua ei voi verrata keskenään. Oikea tapa kirjoittaa väli olisi:

if ( ( 1900 <= vuosi ) && ( vuosi <= 1999 ) ) ...

 

Huomattakoon edellä miten väliä korostettiin kirjoittamalla välin päätepisteet lauseen laidoille. 

Java–kielen sidontajärjestyksen ansiosta lause toimisi myös ilman sisimpiä sulkuja, mutta ne kannattaa pitää mukana varmuuden vuoksi.  Vertailtavat kannattaa kirjoittaa nimenomaan tähän järjestykseen, koska tällöin vertailu muistuttaa eniten alkuperäistä väliämme!

Vastaavasti jos arvon halutaan olevan välin ulkopuolella, kannattaa kirjoittaa:

if ( ( vuosi < 1900 ) || ( 1999 < vuosi ) ) ...

 

Tällöin epäyhtälöiden suuntaa ei joudu koskaan miettimään, vaan arvot ovat aina siinä järjestyksessä kuin lukusuorallakin:

          1900  vuosi   1999               1900<=vuosi && vuosi <=1999

-----------o==============o--------------------

 

  vuosi  1900          1999  vuosi         vuosi<1900 || 1999 <vuosi

===========o--------------o====================

 

1.3.2 Loogisen lausekkeen suoritusjärjestys

Loogiset lausekkeet suoritetaan AINA vasemmalta oikealle, kunnes ehdon arvo on selvinnyt.

Siis: Loogisen lausekkeen evaluoiminen lopetetaan heti kun ehdon arvo selviää (boolean expression shortcut).

Esimerkiksi:

if ( a != 0 || ( (b=c)==0 ) ) System.out.println("Kukkuu");

 

Tai-operaattorin (||) oikealla puolella oleva sijoitus suoritetaan vain mikäli a==0:

a

b

c

 

sij.suor

tulostetaan

 

0

0

5

5

?

?

?

?

0

3

0

3

 

kyllä

kyllä

ei

ei

kyllä

ei

kyllä

kyllä

 

 

Tätä ominaisuutta voidaan käyttää hyväksi esimerkiksi jos on vaara että olion arvo on null:

    if ( (jono != null) && jono.equals("kissa") ) tulosta("On kissa");

 

Tällöin testissä ei turhaan tule null-viittausta koska ehtoa jono.equals ei suoriteta muuta kuin jonon ollessa viite todelliseen olioon.

1.3.3 Loogiset operaattorit & ja |

Ja (&&) ja tai (||) -operaattoreista on myös versiot, joilla aina evaluoidaan (suoritetaan) kaikki lausekkeen osat, vaikka ehdon arvo selviäisi jo aikaisemminkin.

&  ja - suorittaa aina lauskekkeen molemmat puolet

|  tai - suorittaa aina lausekkeen molemmat puolet

 

Aikasempaa esimerkkiä mukaellen:

if ( a != 0 | ( (b=c)==0 ) ) System.out.println("Kukkuu");

 

Tai-operaattorin (|) oikealla puolella oleva sijoitus suoritetaan riippumatta a: n arvosta:

a

b

c

 

sij.suor

tulostetaan

 

0

0

5

5

?

?

?

?

0

3

0

3

 

kyllä

kyllä

kyllä

kyllä

kyllä

ei

kyllä

kyllä

 

 

Vastaavasti olisi paha virhe kirjoittaa:

    if ( (jono != null) & jono.equals("kissa") ) tulosta("On kissa");  L

 

1.4 Bittitason operaattorit

Yksi C–kielen vahvoista piirteistä erityisesti alemman tason ohjelmoinnissa on mahdollisuus käyttää bittitason operaattoreita.

Loogisia operaattoreita &&,|| ja! ei pidä sotkea vastaaviin bittitason operaattoreihin:

&   bittitason AND

|   bittitason OR

^   bittitason XOR

~   bittitason NOT

<<  rullaus vasemmalle, 0 sisään oikealta

>>  rullaus oikealle, 0 sisään vasemmalta (unsigned int ja int >=0)

                    , voi tulla 0 tai 1 sisään vasemmalta (int joka <0)

                      (laiteriippuva, esim. Turbo C:ssä tulee 1).

 

Bittitason operaattoreita voidaan käyttää vain kokonaisluvuiksi muuttuviin operandeihin. 

Operaattoreiden toimintaa voidaan kuvata seuraavasti.  Olkoon meillä sijoitukset a=5; b=14;.  Kuvitellaan kokonaisluvut tilapäisesti 8 bitin mittaisiksi (oikeasti yleensä 16 tai 32 bittiä):

     

  Binäärisenä

desim.

        

a    

  0000 0101  

  5  

 

b    

  0000 1110  

 14  

 

a & b  

  0000 0100  

  4  

 

a | b  

  0000 1111  

 15  

 

a ^ b  

  0000 1011  

 11  

 

~a   

  1111 1010  

 -6  

 

a<<2 

  0001 0100  

 20  

 

b>>3 

  0000 0001  

  1  

 

a && b 

  0000 0001  

  1  

Toimii vain C:ssä

a || b 

  0000 0001  

  1  

Toimii vain C:ssä

!a   

  0000 0000  

  0   

Toimii vain C:ssä

 

Huomautus! Tyypillinen ohjelmointivirhe on sotkea keskenään loogiset ja bittitason operaattorit.  Javassa onneksi kääntäjä tekee tämän vaikeammaksi.

Tehtävä 10.5  Loogiset/bittitason operaattorit

Mitä tulostaa seuraava ohjelman osa.

 

      int a=5, b=2;

      if ( a != 0 && b != 0 ) tulosta("On ne!");

      if ( (a&b) != 0)  tulosta("Ei ne ookkaan!");

      if ( a != 0 ) tulosta("a on!");

      if ( ~b != 0) tulosta("b ehkä on!");

      if ( !(b == 0) ) tulosta("b ei ole!");

 

Tehtävä 10.6  Luku parilliseksi

Kirjoita funktio parilliseksi, joka palauttaa parametrinään olevan kokonaisluvun pienemmäksi parilliseksi luvuksi "katkaistuna".  Eli esim. 3 –> 2.  5 –> 4.  4 –> 4.

 

1.5 ifelse –rakenne

if –lauseesta on myös versio, jossa jotakin voidaan tehdä ehdon ollessa epätosi:

if ( ehto ) ylause1;

else ylause2;

 

Jälleen, mikäli jommassa kummassa osassa tarvitaan useampia lauseita, suljetaan lausejoukko lausesuluilla.  Tosin kannattaa taas harkita lausesulkujen käyttöä aina myös yhdenkin lauseen tapauksessa.

    if ( a < 5 ) tulosta("a alle viisi!");

    else tulosta("a vähintään viisi!");

 

    // Eri riville:

    if ( a < 5 )

      tulosta("a alle viisi!");

    else

      tulosta("a vähintään viisi!");

 

    // Lausesulkujen käyttö:

    if ( a < 5 ) {

      tulosta("a alle viisi!");

    }

    else {

      tulosta("a vähintään viisi!");

    }

 

    // Seuraavaa tyyliä käytetään myös usein:

    if ( a < 5 ) {

      tulosta("a alle viisi!");

    } else {

      tulosta("a vähintään viisi!");

    }

 

1.5.1 Sisäkkäiset if–lauseet

Meillä oli aikaisemmin tehtävänä kirjoittaa funktio, joka palauttaa toisen asteen yhtälön ax2+bx+c=0 toisen juuren.  Tällöin oletuksena oli, että a<>0 ja D>=0.  Mikäli ratkaisukaavaa sovelletaan sellaisenaan ja a=0 tai D<0, niin tällöin ohjelman suoritus päättyy ajonaikaiseen virheeseen.

Voisimme muuttaa tehtävän määrittelyä siten, että kumpikin juuri pitää palauttaa ja funktion nimessä palautetaan tieto siitä, tuliko ratkaisussa virhe, eli jollei juuret olekaan reaalisia.

if ( a != 0 ) {

  D = b*b – 4*a*c;

  if ( D > 0 ) {

    ...

  }

  else {

    ...

  }

}

else {

  ...

}

 

Tosin yhtälö pystytään mahdollisesti ratkaisemaan myös kun a==0.  Tällöin tehtävä jakautuu useisiin eri tilanteisiin kertoimien a,b ja c eri kombinaatioiden mukaan:

  

  

  

  

 

            

juuret  

         

         

 

a

b

c

D

 

yhtälön muoto

reaalisia

x1     

x2     

 

0

0

0

?

 

 0 = 0    

juu   

0     

0     

 

0

0

c

?

 

 c = 0    

ei   

0     

0     

 

0

b

?

?

 

 bx - c = 0

juu   

-c/b   

-c/b   

 

a

?

?

>=0

 

 ax2 + bx + c = 0

juu  

(-b-SD)/2a

(-b+SD)/2a

 

a

?

?

<0

 

 - " -    

ei  

         

         

 

 

Algoritmiksi kirjoitettuna tästä seuraisi:

1.  Jos a=0, niin

      Jos b=0

         Jos c=0 yhtälö on muotoa 0=0 joka on aina tosi

           palautetaan vaikkapa x1=x2 =0

         muuten (eli c<>0) yhtälö on muotoa c=0 joka on

           aina epätosi, palautetaan virhe

      muuten (eli b<>0) yhtälö on muotoa bx=c

          joten voidaan palauttaa vaikkapa x1=x1=–c/b

2.  Jos a<>0, niin

      Jos D>=0 kyseessä aito 2. asteen yhtälö ja käytetään

        ratkaisukaavaa

      muuten (eli D<0) ovat juuret imaginaarisia

 

Funktio ja sen testiohjelma voisi olla esimerkiksi seuraavanlainen:

java-silm\P2_2.java - esimerkki 2. asteen yhtälön ratkaisemiseta

/**

 * Ohjelmalla testataan 2. asteen polynomin juurien etsimistä

 * @author Vesa Lappalainen

 * @version 1.0, 16.02.2003

 */

public class P2_2 {

 

  public static void testi(double a, double b, double c) {

    Polynomi2 p = new Polynomi2(a,b,c);

    System.out.print("Polynomi: " + p);

    if ( p.getReaalijuuria() <= 0 ) {

      System.out.println("  Ei yhtään reaalijuuria! ");

      return;

    }

    System.out.print("  juuret: ");

    System.out.print("x1 = " + p.getX1() + " => P(x1) = " + p.f(p.getX1()) );

    System.out.print("  ja  ");

    System.out.print("x2 = " + p.getX2() + " => P(x2) = " + p.f(p.getX2()) );

    System.out.println();

  }

 

  public static void main(String[] args)  {

    testi(1,2,1);

    testi(2,1,0);

    testi(1,-2,1);

    testi(2,-1,0);

    testi(2,1,1);

    testi(2,0,0);

    testi(0,2,1);

    testi(0,0,1);

  }

}

 

 

 

/**

 * Luokka toisen asteen polynomille ja sen nollakohdille

 * @author Vesa Lappalainen

 * @version 1.0, 16.02.2003

 */

class Polynomi2 {

 

  private double a,b,c,x1,x2;

  private int reaalijuuria;

 

  public Polynomi2(double a, double b, double c) {

    this.a = a; this.b = b; this.c = c;

    reaalijuuria = ratkaise_2_asteen_yhtalo();

  }

 

  private int ratkaise_2_asteen_yhtalo() {

    double D,SD;

    x1 = x2 = 0;

    if ( a==0 ) {                       /*       bx + c = 0 */

      if ( b==0 ) {                     /*            c = 0 */

        if ( c==0 ) {                   /*            0 = 0 */

          return 1;                     /* id. tosi         */

        }                 /* c==0 */

        else {            /* c!=0 */    /*       0 != c = 0 */

          return 0;                     /* Aina epät.       */

        }                 /* c!=0 */

      }                   /* b==0 */

      else {              /* b!=0 */    /*       bx + c = 0 */

        x1 = x2 = -c/b;

        return 1;

      }                   /* b!=0 */

    }                     /* a==0 */

    else {                /* a!=0 */    /* axx + bx + c = 0 */

      D = b*b - 4*a*c;

      if ( D>=0 ) {                     /* Reaaliset juuret */

        SD  = Math.sqrt(D);

        x1 = (-b-SD)/(2*a);

        x2 = (-b+SD)/(2*a);

        return 2;

      }                   /* D>=0 */

      else {                            /* Imag. juuret     */

        return -1;

      }                   /* D<0  */

    }                     /* a!=0 */

  }

 

  public static double P2(double x, double a, double b, double c) {

    return (a*x*x + b*x + c);

  }

 

  public double f(double x) { return P2(x,a,b,c); }

  public double getX1() { return x1; }

  public double getX2() { return x2; }

  public int getReaalijuuria() { return reaalijuuria; }

 

  public String toString() { return a + "x^2 + " + b + "x + " + c; }

 

}

 

Edellinen metodi ratkaise_2_asteen_yhtalo on äärimmäinen esimerkki sisäkkäisistä if–lauseista.  Jälkeenpäin sen luettavuus on erittäin heikko ja myös kirjoittaminen hieman epävarmaa.  Parempi kokonaisuus saataisiin lohkomalla tehtävää pienempiin osasiin aliohjelmien tai makrojen avulla. 

Sisäkkäisten if–lauseiden kirjoittamista voidaan helpottaa kirjoittamalla niitä si­se­ne­västi, eli aloittamalla ensin tekstistä:

  if ( a == 0 ) {                     /*       bx + c = 0 */

  }                     /* a==0 */

  else {                              /* axx + bx + c = 0 */

    D = b*b – 4*a*c;

  }                     /* a!=0 */

 

Sitten täydennetään vastaavalla ajatuksella sekä if–osan että else–osan toiminta.

Jos funktiosta karsitaan kaikki ylimääräinen (kommentit ja ylimääräiset lausesulut) pois, saamme seuraavan näköisen kokonaisuuden:

java-silm\P2_2l.java - karsittu versio 2. asteen yhtälöstä

  private int ratkaise_2_asteen_yhtalo() {

    double D,SD;

    x1 = x2 = 0;

    if ( a == 0 )

      if ( b == 0 ) {

        if ( c == 0 ) return 1;

        else return 0;

      }

      else {

        x1 = x2 = -c/b;

        return 1;

      }

    else {

      D = b*b - 4*a*c;

      if ( D >= 0 ) {

        SD  = Math.sqrt(D);

        x1 = (-b-SD)/(2*a);

        x2 = (-b+SD)/(2*a);

        return 2;

      }

      else return 0;

    }

  }

 

Joskus kannattaa harkita olisiko luettavuuden kannalta paras esitystapa sellainen, että käsitellään "normaaleimmat" tapaukset ensin:

java-silm\P2_2n.java - normaalit tapaukset ensin ratkaisussa

  private int ratkaise_2_asteen_yhtalo() {

    double D,SD;

    x1 = x2 = 0;

    if ( a != 0 ) {

      D = b*b - 4*a*c;

      if ( D >= 0 ) {

        SD  = Math.sqrt(D);

        x1 = (-b-SD)/(2*a);

        x2 = (-b+SD)/(2*a);

        return 2;

      }

      else return -1;

    }

    else /* a==0 */

      if ( b != 0 ) {

        x1 = x2 = c/b;

        return 1;

      }

      else { /* a==0, b==0 */

        if ( c == 0 ) return 1;

        else return 0;

      }

  }

 

Usein aliohjelman return–lauseen ansiosta else osat voidaan jättää poiskin: 

java-silm\P2_2r.java - else -osat pois

  private int ratkaise_2_asteen_yhtalo() {

    double D,SD;

    x1 = x2 = 0;

    if ( a == 0 ) {

      if ( b == 0 ) {

        if ( c == 0 ) return 1;

        return 0;

      }

      x1 = x2 = -c/b;

      return 1;

    }

 

    D = b*b - 4*a*c;

    if ( D < 0 ) return -1;

 

    SD  = Math.sqrt(D);

    x1 = (-b-SD)/(2*a);

    x2 = (-b+SD)/(2*a);

    return 2;

  }

 

Edellä oli useita eri ratkaisuja saman ongelman käsittelemiseksi.  Liika kommenttien määrä saattaa myös sekoittaa luettavuutta kuten 1. esimerkissä.  Toisaalta liian vähillä kommenteilla ei ehkä kirjoittaja itsekään muista jälkeenpäin mitä tehtiin ja miten.  Jokainen valitkoon edellä olevista itselleen sopivimman kultaisen keskitien.

Huomattakoon vielä lopuksi, että rakenne

if ( c == 0 ) return true;

else return false;

 

voitaisiin korvata rakenteella

return ( c != 0 );

 

Tehtävä 10.7  else –osat pois

Kirjoita ratkaise_2_asteen_yhtalo P2_2n.java  ilman else –osia.

 

1.5.2 Useat peräkkäiset ehdot

Vaikka rakenne

if (ehto1) lause1;

else

  if (ehto2) lause2;

  else

    if (ehto3) lause3;

    else lause4;

 

jossain mallissa sisennetäänkin ylläkuvatulla tavalla, on ajatus useimmiten lähempänä seuraavaa sisennystä:

java-silm\Postimaksu.java - esimerkki samanarvoisista ehtolauseista

  static double postimaksu(double paino)

  {

    if      ( paino < 50 )   return  0.60;

    else if ( paino < 100 )  return  0.90;

    else if ( paino < 250 )  return  1.30;

    else if ( paino < 500 )  return  2.10;

    else if ( paino < 1000 ) return  3.50;

    else if ( paino < 2000 ) return  5.50;

    else                     return  0.00;

  }

 

Sovimme siis, että rakenne onkin muotoa:

if      ( ehto1 ) lause1

else if ( ehto2 ) lause2

else if ( ehto3 ) lause3

else              lause4

 

Tehtävä 10.8  elset pois

Voiko aliohjelmasta  postimaksu jättää if-lauseiden else-osat pois?  Päteekö väittämä yleisesti?

Tehtävä 10.9  Lääni

Kirjoita aliohjelma

      void laani(string rekisteri)

joka tulostaa missä läänissä auto on rekisteröity.  (Ennen oli Suomessa monta lääniä ja rekisterinumeron 1. kirjain määräsi missä läänissä auto oli rekisteröity).

Kirjaimen yhtäsuuruutta testataan if ( c == 'a' ) ...

Merkkijonon 1. merkki saadaan c = rekisteri[0]; edellyttäen tietysti että rekisteri != ””.

Tehtävä 10.10     if–else

Mitä ovat muuttujien arvot seuraavien ohjelmanpätkien jälkeen (pöytätesti!)?

 

if (a<5)           

/*1*/ a=1; b=2; c=3;

  b=3;             

  a=6;             

c=7;               

 

if (a<0) a=3; else 

/*5*/ a=1; b=2; c=3;

if (a>2) b=3; a=6; 

c=7;               

 

 

 

 

 

 

/*2*/ a=1; b=2; c=3;  

if (a<5) b=3; a=6; c=7;

 

 

/*6*/ a=1; b=2; c=3;  

if (a<–5) if (a<0) a=6;

else a=2; c=7;

 

 

 

 

 

/*3*/ a=1; b=2; c=3;

if (a<5) {b=3; a=6;}

c=7;               

 

 

/*7*/ a=1; b=2; c=3;

if (a<–5) b=3;     

  if (a<5) a=6;    

else a=2; c=7;     

 

 

 

 

 

/*4*/ a=1; b=2; c=3; if (a<5)

b=3; else { a=6; c=7; }     

 

 

/*8*/ a=1; b=2; c=3;

if (a<0) a=3; else;

if (a>2) b=3; a=6; 

c=7;               

 

 

Sisennä ohjelmanpätkät "asianmukaisesti".

1.6 do–while –silmukka

Aikaisemmin olemme tutustuneet erääseen algoritmiin selvittää onko luku alkuluku vai ei.  Koska algoritmi on valmis, voimme kirjoittaa vastaavan ohjelman (% –operaattori antaa jakojäännöksen, 10 % 3 == 1 ):

java-alk\Alkuluku.java - testataan onko luku alkuluku

**

 *  Ohjelmalla testataan onko_alkuluku-aliohjelmaa

 *  @author Vesa Lappalainen

 *  @version 1.0, 17.01.2002

 */

public class Alkuluku {

 

  /**

   * Aliohjelmalla tutkitaan onko parametrina tuotu

   * luku alkuluku vai ei<br>

   * Algoritmi: Jaetaan tutkittavaa lukua jakajilla 2,3,5,7...luku/2.

   * Jos jokin jako menee tasan, niin ei alkuluku:

   * @param luku tutkittava luku

   * @return tieto siitä, onko luku alkuluku vai ei

   */

  public static String onko_alkuluku(int luku)

  {

    int jakaja=2, kasvatus=1;

    if ( luku == 2 ) return "alkuluku";

 

    do {

      int jakojaannos = luku % jakaja;

      if ( jakojaannos == 0 )

        return "jaollinen";

      jakaja += kasvatus;

      kasvatus = 2;

    } while ( jakaja < luku/2 );

 

    return "alkuluku";

  }

 

  public static void main(String[] args) {

    String tulos;

    tulos = onko_alkuluku(25);

    System.out.println(tulos);

    tulos = onko_alkuluku(123);

    System.out.println(tulos);

    tulos = onko_alkuluku(7);

    System.out.println(tulos);

  }

}

 

Käytimme tässä silmukkaa:

do

  lause

while (ehto);

 

Koska esimerkin silmukassa oli useita suoritettavia lauseita, oli lauseet suljettu lausesuluilla.  Jälleen voi olla hyvä tapa käyttää AINA lausesulkuja.

Huomautus! Silmukoiden kanssa on syytä olla tarkkana sekä 1. kierroksen että viimeisen kierroksen kanssa.  Myös silmukan lopetusehdon on syytä muuttua silmukan suorituksen aikana.

Eräs tyypillinen esimerkki do–while silmukan käytöstä olisi seuraava:

java-silm\Dowhile.java - lukujen lukeminen kunnes halutulla välillä

import fi.jyu.mit.ohj2.Syotto;

/**

 * Ohjelmalla luetaan luk, kunnes se on halutulla välillä

 * @author Vesa Lappalainen

 * @version 1.0, 07.02.2003

 */

public class Dowhile {

 

  public static void main(String[] args)  {

    int luku;

    do {

      luku = Syotto.kysy("Anna luku väliltä [0-20]",0);

    } while ( luku < 0 || 20 < luku );

    System.out.println("Annoit luvun " + luku);

 

  }

}

 

1.7 while –silmukka

do–while –silmukka suoritetaan aina vähintään 1. kerran.  Joskus on tarpeen silmukka, jonka runkoa ei suoriteta yhtään kertaa.  Muutamme edellisen esimerkkimme käyttämään while –silmukkaa:

while ( ehto ) lause

 

Muutamme samalla algoritmia siten, että 2:lla jaolliset käsitellään erikoistapauksena.  Näin pääsemme eroon "inhottavasta" kasvatus–muuttujasta.

java-silm\Alkuluku2.java - alkulukutesti while-silmukalla

  public static int pienin_jakaja(int luku)

  {

    int jakaja=3;

    if ( luku == 2 ) return 1;

    if ( luku % 2 == 0 ) return 2;

 

    while ( jakaja < luku/2 ) {

      if ( luku % jakaja == 0 ) return jakaja;

      jakaja += 2;

    }

 

    return 1;

  }

 

1.8 for –silmukka, tavallisin muoto

Eräs C–kielen hienoimmista rakenteista on for–silmukka.  Usein C–hakkereiden tavoite on saada kirjoitettua koko ohjelma yhteen for–silmukkaan.  Tätä ei tietenkään tarvitse tavoitella, mutta se osoittaa for–silmukan mahdollisuuksia.

Tyypillisesti for–silmukkaa käytetään silloin, kun silmukan kierrosten lukumäärä on ennalta tunnettu:

java-silm\Valinsum.java - esimerkki for-silmukasta

  /**

   * Lasketaan yhteen luvut 1..ylaraja

   * @param ylaraja summan yläraja

   * @return summa

   */

  public static int valin_summa(int ylaraja)

  {

    int i,summa=0;

    for (i=1; i<=ylaraja; i++)

      summa += i;

    return summa;

  }

 

Tehtävä 10.11     valin_summa

Muuta valin_summa –aliohjelmaa siten, että myös alaraja viedään parametrinä.  Kirjoita pääohjelma, jolla toiminta voidaan testata.

 

Käytännössä tällaisia silmukoita ei saa tehdä, koska ongelman ratkaisuun on valmis kaava.  Millainen?

 

1.9 Java–kielen lauseista

1.9.1 Sijoitusoperaattori =

Olemme tutustuneet jo Java–kielen "normaaliin" sijoitusoperaattoriin =

Sen ansiosta, että myös sijoitus palauttaa arvon, pystyimme tekemään mm seuraavia temppuja:

if ( (b=a) != 0 ) ... /* Suoritetaan jos a!=0 */

a = b = c = 0;

 

Sijoitus monelle muuttujalle yhtäaikaa onnistuu, koska sijoitus jäsentyy seuraavasti:

1.  a = ( b = (c = 0) ); –   sijoitus c=0 palauttaa arvon 0

2.  a = ( b =    0 );    –   sijoitus b=0 palauttaa arvon 0

3.  a =     0;

 

1.9.2 Sijoitusoperaattori +=

valin_summa aliohjelmassa meillä esiintyi myös kaksi uutta sijoitusoperaattoria, jotka ovat lyhenteitä tavallisille sijoituksille:

lyhenne

tavallinen sijoitus

summa += i; 

i++

summa = summa + i;

i = i + 1;

 

+= sijoituksessa + voidaan korvata millä tahansa operaattoreista:

+   –   *   /   %   <<   >>   ^   &  |

 

Esimerkiksi luvun kertominen ja jakaminen 10:llä voitaisiin suorittaa:

luku *= 10;

luku /= 10;

 

Siis muuttuja O= operandi voidaan ajatella korvattavaksi seuraavasti:

0.  laita sulut operandin ympärille

      muuttuja O= (operandi)

1.  kirjoita muuttujan nimi kahteen kertaan

      muuttuja muuttuja O= (operandi)

2.  siirrä = –merkki muuttujien nimien väliin

      muuttuja = muuttuja O (operandi)

 

Tehtävä 10.12     +=

Mitä ovat muuttujien arvot seuraavien sijoitusten jälkeen:

 

int a=10,b=3,c=5;

a %= b;

b *= a+c;

b >>= 2;

 

1.9.3 Lisäysoperaattori ++

Erittäin tyypillisiä C–operaattoreita ovat ++ ja––

Nämä operaattorit lisäävät tai vähentävät operandin arvoa yhdellä.  Operandin tyypin tulee olla numeerinen tai osoitin. 

Operandeista on kaksi eri versiota: esilisäys ja jälkilisäys.

lyhenne

vastaa lauseita

a = i++;

a = i—

a = ++i;

a = --i;

a = i;   i = i+1;

a = i;   i = i-1;

i = i+1; a = i;

i = i-1; a = i;

 

Vaikka C–hakkerit rakentavatkin mitä ihmeellisimpiä kokonaisuuksia ++ –operaattorin avulla, kannattaa operaattorin liikaa käyttöä välttää.  Esimerkiksi lauseet joissa esiintyy samalla kertaa useampia lisäyksiä samalle muuttujalle, saattavat olla jopa määrittelemättömiä:

java-silm\Plusplus.java - esimerkki ei-yksikäsitteisestä ++ operaattorin käytöstä

/**

 * Esimerkki epäselvästä ++-operaattorin käytöstä

 * @author Vesa Lappalainen

 * @version 1.0, 16.02.2003

 */

public class Plusplus {

 

  public static void main(String[] args)  {

    double i=1.0,a;

    a = i++/i++;

    System.out.println("(a = " + a + ", i = " + i);

  }

}

 

Ohjelma saattaa Java–kääntäjän toteutuksesta riippuen tulostaa mitä tahansa seuraavista a:n ja i:in kombinaatioista:

a: 0.5 1.0 2.0

i: 2.0 3.0

 

Aluksi ++ –operaattoria kannattaa ehkä käyttää vain yksinäisenä lauseena lisäämään (tai vähentämään) muuttujan arvoa.

i++;

 

Lisäysoperaattoria EI PIDÄ käyttää jos muuttuja johon lisäysoperaattori kohdistuu, esiintyy samassa lausekkeessa useammin kuin kerran.

Kiellettyjä on siis esimerkiksi:

a = ++i + i*i;

ali(i++,i);

 

1.10 for –silmukka, yleinen muoto

Yleensä ohjelmointikielissä for–silmukka on varattu juuri siihen tarkoitukseen, kuin ensimmäinen esimerkkimmekin; tasan tietyn kierrosmäärän tekemiseen.

Java–kielen for–silmukka on kuitenkin yleisempi:

/*     1.             2.  5.          4.  7.           3.  6.  */

for (alustus_lauseet; suoritus_ehto; kasvatus_lauseet) lause;

 

for–silmukka vastaa melkein while–silmukkaa (ero tulee continue–lauseen käyttäytymisessä):

alustus_lauseet;               /* 1.     */

while ( suoritus_ehto ) {      /* 2.  5. */

  lause;                       /* 3.  6. */

  kasvatus_lauseet;            /* 4.  7. */

}

 

Mikäli esimerkiksi alustuslauseita on useita, erotetaan ne toisistaan pilkulla:

java-silm\Valinsum.java - useita alustuslauseita for-silmukassa

  public static int valin_summa_2(int ylaraja) {

    int i,summa;

    for (summa=0, i=1; i<=ylaraja; i++)

      summa += i;

    return summa;

  }

 

Erittäin C:mäinen tapa tehdä yhteenlasku olisi:

java-silm\Valinsum.java - C:mäinen silmukka

  public static int valin_summa_3(int i) {

    int s;

    for (s=0; i >= 0; s += i--);

    return s;

  }

 

Tämä viimeinen esimerkki on juuri niitä C–hakkereiden suosikkeja, joita ehkä kannattaa osin vältellä.

Tehtävä 10.13     1+2+..+i

Miksi valin_summa_3 laskee yhteen luvut 1..i?

 

1.11 break ja continue

1.11.1 break

Joskus kesken silmukan tulee vastaan tilanne, jossa silmukan suoritus haluttaisiin keskeyttää.  Tällöin voidaan käyttää C–kielen break–lausetta, joka katkaisee sisimmän silmukan suorituksen.

java-silm\Break.java - silmukan katkaisu keskeltä

private static void break_testi1() {

  int summa=0,luku;

  System.out.println("Anna lukuja.  Summaan niitä kunnes annat 0 tai summa>20");

  do {

    luku = Syotto.kysy("Summa on " + summa + ".  Anna luku",0);

    if ( luku == 0 ) break;

    summa += luku;

  } while ( summa <= 20 );

  System.out.println("Lukujen summa on " + summa);

}

 

Koska 0:lla lisääminen ei  muuta summaa, olisi tietenkin  do-while –silmukan ehto voitu kirjoittaa muodossa

    do {

      luku = Syotto.kysy("Summa on " + summa + ".  Anna luku",0);

      summa += luku;

    } while ( luku != 0 && summa <= 20 );

 

mutta aina ei voida break –lausetta korvata näin yksinkertaisesti. Perus break –lauseen vika on lähinnä siinä, ettei siitä suoraan nähdä sisäkkäisten silmukoiden tapauksessa sitä, mihin saakka suoritus katkeaa.  Epäselvissä tapauksissa silmukan katkaisu voidaan hoitaa nimeämällä silmukat ja ilmoittamalla break-lauseessa mikä silmukka katkaistaan:

java-silm\Break.java - ulomman silmukan katkaisu keskeltä

  private static void break_testi3() {

    int valisumma, loppusumma = 0,luku;

    System.out.println("Anna lukuja.");

    System.out.println("Summaan niitä kunnes annat 99.");

    System.out.println("Antamalla 0, näet välisumman");

    System.out.println("Välisumman näet myös jos välisumma > 20");

    laskeloppusummaa: do {

      valisumma = 0;

      do {

        luku = Syotto.kysy("Anna luku",0);

        if ( luku == 0 ) break;

        if ( luku == 99 ) break laskeloppusummaa;

        valisumma += luku;

      } while ( luku != 0 && valisumma <= 20 );

      System.out.println("Lukujen välisumma on " + valisumma);

      loppusumma += valisumma;

      System.out.println("Kaikkien summa on " + loppusumma);

    } while ( loppusumma < 100 );

    System.out.println("Lukujen loppusumma on " + loppusumma);

  }

 

Silmukka voidaan katkaista tietenkin myös muuttamalla silmukan lopetusehtoon vaikuttavia muuttujia.  Varsinkin for–lauseen tapauksessa silmukan indeksin arvon muuttaminen muualla kuin kasvatus–lauseessa on todella väkivaltaista ja rumaa, eikä tällaista pidä mennä tekemään.

Hyvin usein aliohjelmassa break voidaan korvata return-lauseella.

Lisäksi näkyviä sisäkkäisiä silmukoita voidaan välttää tekemällä sisäsilmukasta oma aliohjelma:

while ( ulkoehto ) {

  while ( sisaehto ) {

    hommia();

  }

}

 

Eli sisäkkäisten silmukoiden tilalle kirjoitetaan:

void sisahommat() {

  while ( sisaehto ) {

    hommia();

  }

}

...

while ( ulkoehto ) {

  sisahommat();

}

 

Tehtävä 10.14     Tarvitaanko sisäkkäisiä silmukoita?

Tarvitaanko aliohjelmassa break_testi3 todella sisäkkäisiä silmukoita?  Esitä ratkaisu jossa on vain yksi silmukka.

 

1.11.2 continue

Vastaavasti saattaa tulla tilanteita, jolloin itse silmukan suoritusta ei haluta katkaista, mutta menossa oleva kierros halutaan lopettaa.  Tällöin continue –lauseella voidaan suoritus siirtää suoraan silmukan loppuun ja näin lopettaa tämän kierroksen suoritus:

java-silm\Continue.java - silmukan lopun ohittaminen

/**

 * Esitellään continue-lauseen käyttöä

 * @author Vesa Lappalainen

 * @version 1.0, 07.02.2003

 */

public class Continue {

 

  public static void main(String[] args)  {

    int alku= -5, loppu=5,i;

    double inv_i;

    System.out.println("Tulostan lukujen " + alku + " - " + loppu +

                       "käänteisluvut");

    for (i = alku; i<=loppu; i++ ) {

      if ( i == 0 ) continue;

      inv_i = 1.0/i;

      System.out.println(i + ":n käänteisluku on " + inv_i);

    }

  }

}

 

Vastaavasti myös continue:n kanssa voi käyttää nimettyä silmukkaa, jos pitääkin siirtyä jatkamaan muuta kuin sisintä silmukkaa.

Tehtävä 10.15     continuen korvaaminen

Kirjoita käänteislukujen tulostusohjelma ilman continue–lausetta.

 

Tehtävä 10.16     Eri silmukoiden vertailu

Kirjoita lukujen alaraja-yläraja summausfunktio käyttäen

      a)  while -lausetta

      b)  do–while -lausetta

      c)  goto –lausetta

Muista, että alaraja saattaa olla suurempi kuin yläraja, eli summa väliltä [3,0] on 0!

1.12 switch –valintalause

Jäsenrekisteriohjelmamme päävalinta olisi näppärintä toteuttaa switch –lauseella:

menut_3\Naytto.java - päävalinta switch -lauseella

  /**

   * Silmukka jossa odotetaan näppäint ja suoritetaan vastaava toiminto.

   * 0:n painaminen lopettaa silmukan ja palaa kutsuvaan ohjelmaan.

   * @return palauttaa 0 jos kaikki meni hyvin, 1 jos tuli virhe

   */

  public int paavalinta() {

    char nappain;

 

    while ( true ) {

 

      paamenu();

 

      nappain = IO.odota_nappain("?012345",IO.EI_OLETUSTA,IO.MERKKI_ISOKSI);

 

      switch (nappain) {

        case '?': avustus(nappain);                break;

        case '0': return 0;

        case '1': lisaa_uusi_jasen(nappain);       break;

        case '2': etsi_jasenen_tiedot(nappain);    break;

        case '3': tulosteet(nappain);              break;

        case '4': tietojen_korjailu(nappain);      break;

        case '5': paivita_jasenmaksuja(nappain);   break;

        default : tulosta("Näin ei voi käydä!");  return 1;

      }

 

    }

  }

 

switch –lauseessa case osien lopuksi break on yleensä välttämätön. break estää suorittamasta seuraavia rivejä. 

Joskus harvoin breakin puuttumista voidaan käyttää hyväksi, mutta tällöin pitää olla todella tarkkana:

java-silm\Switch.java - switch, jossa break tahallaan jätetty pois

  public static int switch_testi(int x,int operaatio) {

    switch (operaatio) {

      case 5:                 /* Operaatio 5 tekee saman kuin 4 */

      case 4: x *= 2; break/*           4 laskee x=2*x       */

      case 3: x += 2;         /*           3 laskee x=x+4       */

      case 2: x++;            /*           2 laskee x=x+2       */

      case 1: x++; break;     /*           1 laskee x=x+1       */

      default: x=0; break;    /* Muut nollaavat x:än            */

    }

    return x;

  }

 

Lause default suoritetaan jos mikään case–osista ei ole täsmännyt (tai tietysti jos jokin break puuttuu). default–lauseen ei tarvitse olla viimeisenä, mutta tällöin vaaditaan taitavaa breakin käyttöä, siis paras pitää default viimeisenä!

Yleistä switch–lausetta ei voi korvata joukolla if–lauseita käyttämättä goto–lausetta.  Mikäli kuitenkin jokaisen case rakenteen perässä on break, voidaan switch– korvata sisäkkäisillä if–else –rakenteilla.

Tehtävä 10.17     switch –> if

Kirjoita Switch.java ohjelmanpätkä käyttäen if–rakenteita muuttamatta itse suoritettavia lauseita.

Tehtävä 10.18     Päävalinta

Kirjoita paavalinta käyttäen vain if ja else rakenteita.

Tehtävä 10.19     lääni, versio 2

Kirjoita laani–aliohjelma käyttäen Switch–rakennetta.

 

1.12.1 | ei toimi switch –lauseessa!

On huomattava, että jos halutaan suorittaa jokin switch–lauseen osista kahdella eri arvolla, EI voida käyttää rakennetta:

switch (operaatio) {  /* VÄÄRIN: */                                      

  case 4 | 5: x *= 2; break;   /*    5 tai  4 laskee x=2*x       */    L

  case 3: x += 2;              /*           3 laskee x=x+4       */

  case 2: x++;                 /*           2 laskee x=x+2       */

  default: x=0; break;         /* Muut nollaavat x:än            */

}

 

Kääntäjä ei tästä varoita, koska kaikki on aivan kieliopin mukaista. 4 | 5 on kahden bittilausekkeen OR eli 5.  Siis

case 4 | 8:

on sama kuin

case 12:

 

1.13 Ikuinen silmukka

Usein silmukat lipsahtavat tahottomasti sellaisiksi, ettei niistä koskaan päästä ulos.  Ikuisen silmukan huomaa heti esimerkiksi siitä, ettei silmukan rungossa ole yhtään lausetta joka muuttaa silmukan ehdon totuusarvoa.

Joskus kuitenkin Java–kielessä tehdään tarkoituksella "ikuisia" –silmukoita:

for (;;) {

  ...

  if (lopetus_ehto) break;

  ...

}

 

while ( true ) {

  ...

  if (lopetus_ehto) break;

  ...

}

 

do {

  ...

  if (lopetus_ehto) break;

  ...

} while ( true );

 

Näissä kahdessa ensimmäisessä korostuu silmukan ikuisuus.  Viimeinen ei ole hyvä vaihtoehto.

Tällaiset ikuiset silmukat ovat hyväksyttävissä silloin, kun silmukan lopetusehto on luonnollisesti keskellä silmukkaa.  Usein kuitenkin lauseiden uudelleen järjestelyllä lopetusehto voidaan sijoittaa silmukan alkuun tai loppuun, jolloin tavallinen while– , do–while – tai for –silmukka kelpaa.

1.13.1 Yhteenveto silmukoista