1. Java –kielen alkeita

Kommenttit jo käyttämäksi

muistiksipa merkit muille

selvennykseksi sepille

omaksikin ovat iloksi.

 

Vakioksi alkuun tiedot

kevenee koodin korjaaminen

mukavampi muutos aina

sulavampi säätäminen.

 

Koodi ensin käännettävä

syntaksikin syynättävä

tuo tulkilla tulkattava

siitä sitten suorittava.

 

 

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

·      Java-kielisen ohjelman peruskäsitteet

·      kääntämisen ja linkittämisen merkitys

·      paketin käyttöönotto

·      vakioarvot

 

Syntaksi:

kommentti:         /* vapaata tekstiä, vaikka monta riviäkin */

kommentti:         // loppurivi vapaata tesktiä

luokan ottaminen: import paketin_nimi.Luokka; import paketin_nimi.*;

vakio:            static final tyyppi nimi = arvo;

tulostus:         System.out.println(merkijono);

merkkijono:       "merkkejä"

 

Luvun esimerkkikoodit:

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

 

Ohjelman toteuttamista varten täytyy valita jokin todellinen ohjelmointikieli.  Lopullisesta ohjelmasta ei valintaa toivottavasti huomaa.  Valitsemme käyttökielen tällä kurssilla puhtaasti "markkinaperustein": paljon käytetyn ja työelämässä kysytyn - Java.

1.1 Hello World! Java –kielellä

java-alk\Hello.java - ensimmäinen Java ohjelma

// Ohjelma tulostaa tekstin Hello world!

class Hello {

  public static void main(String[] args) {

    System.out.println("Hello world!");

  }

}

 

Tehtävä 7.1    Nimi ja osoite

Kirjoita Java–ohjelma joka tulostaa:

Terve! 

Olen Matti Meikäläinen 25 vuotta.

Asun Kortepohjassa.

Puhelinnumeroni on 603333.

 

1.2 Tekstitiedostosta toimivaksi konekieliseksi versioksi

1.2.1 Kirjoittaminen

Ohjelmakoodi kirjoitetaan millä tahansa tekstieditorilla tekstitiedostoon vaikkapa nimelle Hello.java.  Yleensä tiedoston tarkennin määrää ohjelman tyypin.

1.2.2 Kääntäminen

Valmis tekstitiedosto käännetään ko. kielen kääntäjällä.  Käännöksestä muodostuu usein objektitiedosto, joka on jo lähellä lopullisen ohjelman konekielistä versiota.  Objektitiedostosta puuttuu kuitenkin mm. kirjastorutiinit.  Kirjastorutiinien kutsujen kohdalla on "tyhjät" kutsut. 

Java-kielen tapauksessa käännöksen tuloksena syntyy Java-virtuaalikoneen (JVM) ymmärtämää tavukoodia.  Esimerkin tiedosto kääntyy esimerkiksi komennolla:

javac Hello.java

 

Käännöksen tuloksena syntyvässä Hello.class-tiedossa on siis Java-tulkin ymmärtämää tavukoodia.  Kuitenkin siitäkin puuttuu itse kirjastorutiinit.  Erona muihin kieliin on se, että käännetty tiedosto toimii niissä ympäristöissä, joissa on JVM ja nuo puuttuvat rutiinit.

Varsinaisissa käännettävissä  kielissä käännös pitää suorittaa uudelleen jos ohjelma halutaan siirtää toiseen ympäristöön.

1.2.3 Linkittäminen

Linkittäjällä (kielestä riippumaton ohjelma) liitetään kirjastorutiinit käännettyyn objektitiedostoon. Linkittäjä korvaa tyhjät kutsut varsinaisilla kirjastorutiinien osoitteilla kunhan saa selville mihin kohti muistia kirjastorutiinit sijoittuvat. Näin saadaan valmis ajokelpoinen konekielinen versio alkuperäisestä ohjelmasta.

Javan tapauksessa varsinaista linkittämistä ei tarvita, vaan ohjelman suorituksen aikana etsitään tarpeellisia luokkia.  Luokkien etsiminen voi tapahtua heti kun ensimmäistä luokkaa ladataan muistiin ("static" resolution) tai vasta kun luokkaan viitataan ("laziest" resolution) .

1.2.4 Ohjelman ajaminen

Käännetty ohjelma ajetaan käyttöjärjestelmästä riippuen yleensä kirjoittamalla ohjelman alkuperäinen nimi.  Tällöin käyttöjärjestelmän lataaja–ohjelma lataa ohjelman konekielisen version muistiin ja siirtää prosessorin ohjelmalaskurin ohjelman ensimmäisenä suoritettavaksi tarkoitettuun käskyyn.  Vielä tässäkin vaiheessa osa aliohjelmakutsujen osoitteista voidaan muuttaa vastaamaan sitä todellista osoitetta, johon aliohjelma muistiin ladattaessa sijoittui.  Tämän jälkeen vastuu koneen käyttäytymisestä on ohjelmalla.  Onnistunut ohjelma päättyy aina ennemmin tai myöhemmin käyttöjärjestelmän kutsuun, jossa ohjelma pyydetään poistamaan muistista.

Kuva 7.1  Ohjelman kääntäminen ja linkittäminen

Javan tapauksessa ajaminen suoritetaan antamalla .class tai .jar tiedosto Java-virtuaalikoneelle (Java Virtual Machine, JVM). Esimerkkimme tapauksessa komennolla

java Hello

 

Jos luokasta Hello löytyy julkinen luokkametodi (staattinen metodi) nimeltä main, niin ohjelman suoritus aloitetaan siitä.  Mikäli metodia ei löydy, tulee virheilmoitus:

Exception in thread "main" java.lang.NoSuchMethodError: main

 

 

Kuva 7.2  Ohjelman kääntäminen ja linkittäminen

 

1.2.5 Varoitus

Alkuperäisellä editorilla kirjoitetulla ohjelmakoodilla ei ole tavallista kirjettä kummempaa virkaa ennen kuin teksti annetaan kääntäjäohjelman tutkittavaksi.  Käännöksen jälkeen alkuperäinen teksti voitaisiin periaatteessa vaikka hävittää - käytössä tietysti alkuperäinen teksti säilytetään ylläpidon takia!  Siis me kirjoitamme tekstiä, joka ehkä (toivottavasti) muistuttaa Java–kielen syntaksin mukaista ohjelmaa.  Vasta käännös ja linkkaus tekevät todella toimivan ohjelman.

1.2.6 Integroitu ympäristö

On olemassa ohjelmankehitysympäristöjä, joissa editori, kääntäjä ja linkkeri (sekä mahdollisesti debuggeri, virheenjäljitin) on yhdistetty käyttäjän kannalta yhdeksi toimivaksi kokonaisuudeksi.  Esimerkkeinä Borland Jbuilder, NetBeans, Microsoftin Visual–Studio ja Borland–C++ Builder . Kaikissa listassa mainituissa kehittimissä on myös tuki käyttöliittymän suunnittelulle.

Esimerkiksi Borlandin ympäristöissä ohjelma kirjoitetaan tekstinä ja kun ohjelmakoodi on valmis, saadaan koodi käännettyä, linkitettyä ja ladattua ajoa varten vain painamalla [F9](tai [Ctrl-F9] versiosta riippuen) .

Mahdollisia muita integroitujen ympäristöjen ominaisuuksia ovat mm: UML-kaavioiden ja muiden dokumenttien automaattinen tuottaminen (esim. Delphin ModelMaker, JBuilderin luokkakaaviot, JavaDoc-yhteistoiminta Java-kehittimissä), jotka perinteisesti ovat olleet CASE-suunnitteluohjelmien aluetta. Lisäksi myös koodin generointi kaavioista onnistuu rajoitetusti.

1.3 Ohjelman yksityiskohtainen tarkastelu

Seuraavaksi tutkimme ohjelmaa lause kerrallaan:

java-alk\Hello2.java - malliohjelma

import java.lang.System;

/**

 *

 * Ohjelma tulostaa tekstin Hello world!

 * @author Vesa Lappalainen

 * @version 1.0, 03.01.2003

 */

class Hello2 {

  public static void main(String[] args) {

    System.out.println("Hello world!");

  }

}

 

1.3.1 Tarvittavien luokkien esittely

Harvoin voi tehdä ohjelman joka tulee täysin toimeen ilman muiden apua. Javan tapauksessa ilman muiden luokkien apua.  Jotta kääntäjä tietäisi mistä puhutaan, pitää kertoa mistä paketista luokka löytyy.  Paketista java.lang löytyy System-niminen luokka, josta löytyy tarvitsemamme out-olio.  Eli pitäisi oikeastaan kirjoittaa:  

    java.lang.System.out.println("Hello world!");

 

Olioihin ja luokkiin paneudumme tarkemmin luvussa 9.

Jos kuitenkin samaan luokkaa tarvitaan useasti ja halutaan lyhentää kirjoittamista, voidaan import-lauseella kertoa ennen varsinaista koodin aloittamista apuna tarvittavat luokat. 

import java.lang.System;

 

Jos haluttaisiin ottaa kaikki tietyn paketin luokat käyttöön, tämä voitaisiin tehdä rivillä:

import java.lang.*;

 

Poikkeuksen muodostaa paketti java.lang jota ei tarvitse välttämättä erikseen esitellä lainkaan.  Näinhän oli tehty ensimmäisessä esimerkissämme.

1.3.2 Kommentti

// Ohjelma tulostaa tekstin Hello world!

tai

/* Ohjelma tulostaa tekstin Hello world! */

 

Ohjelman  alussa on kommentoitu mitä ohjelma tekee.  Yleensä ohjelmakoodit on hyvä varustaa kuvauksella siitä, mitä ohjelma tekee, kuka ohjelman on tehnyt, milloin ja miksi.  Milloin ohjelmaa on viimeksi muutettu, kuka ja miten.

Lisäksi jokainen vähänkin ei–triviaali lause tai lauseryhmä kommentoidaan.  Kommenttien tarkoituksena on kuvata ohjelmakoodia lukevalle lukijalle se mistä on kyse.

Lohkokommentti alkaa /* –merkkiyhdistelmällä ja päättyy */ –merkkiyhdistelmään.  Lohkokommentteja voidaan sijoittaa Java–koodissa mihin tahansa mihin voitaisiin pistää myös välilyönti.  Rivin loppuminen ei sinänsä lopeta lohkokommenttia.  Kommentin sisällä SAA esiintyä / ja * –merkkejä yhdessä tai erikseen, muttei lopettavaa yhdistelmää */.

Yleinen virhe on unohtaa lohkokommentin loppusulku pois.  Mikäli esimerkissämme puuttuisi kommentin loppusulku, olisi koko loppuohjelma kommenttia ja mitään ohjelmaa ei siis olisikaan.  Mikäli kääntäjä antaa vyöryn ihmeellisiä virheilmoituksia, kannattaa aina ensin tarkistaa kommenttisulkujen täsmäävyys.  Tosin tähän auttaa nykyisten ohjelmointiympäristöjen värikoodien käyttö eri ohjelman osille, eli esimerkiksi kommentit näkyvät eri värisinä ja puuttuva komenttisulku paljastuu välittömästi.

Javassa yhden rivin kommentti voidaan ilmaista myös // –merkkiyhdistelmällä, jolloin rivinloppu lopettaa kommentin. 

1.3.3 JavaDoc

/**

 *

 * Ohjelma tulostaa tekstin Hello world!

 * @author Vesa Lappalainen

 * @version 1.0, 03.01.2003

 */

 

Jos tiedot annetaan Javan dokumentoinnin standardimuodossa, niin tiedostoista saadaan sitten koostettua helposti HTML-muotoinen dokumentti.  JavaDocin mukainen kommentti alkaa ”sululla” /** ja päättyy normaaliin kommentin loppumerkkiin.

Kommentointi kannattaa käytännössä tehdä yksittäisten metodien tarkkuudella.  Katso esimerkiksi tämän luvun viimeinen esimerkki.

Katso lisää JavaDoc:in käytöstä esimerkiksi:

 http://java.sun.com/j2se/javadoc/writingdoccomments/index.html

 

1.3.4 Luokan esittely

class Hello2 {

 

Jokainen Java-ohjelma sisältää vähintään yhden julkisen luokan.  Kunkin tiedoston nimi on oltava sama kuin tiedostossa olevan julkisen luokan nimi + ’.java’. Palaamme luokkiin ja olioihin tarkemmin hieman myöhemmin.  Usein olio-ohjelmoinnissa on tapana että luokkien nimet aloitetaan isolla kirjaimella.

Luokan esittely ja toteutus alkaa aaltosululla { ja päättyy toiseen lopettavaan aaltosulkuun }.

1.3.5 Pääohjelman esittely

public static void main(String[] args) {

 

Kun Java-tavukoodi ladataan muistiin, etsitään ensin ladatusta luokasta (tai muuten erikseen ilmoitetusta luokasta) pääohjelmaa, josta koodin suoritus aloitetaan.  Pääohjelman nimi on aina oltava main.  Oikeassa ohjelmassa on pääohjelman lisäksi useita luokkia ja metodeita (luokkien sisällä olevia aliohjelmia). 

main-­metodi voi olla myös useammassa luokassa, jolloin kullakin main-metodilla voidaan testata kyseisen luokan toiminta.  Näin helpotetaan yksikkötestausta (modulitestausta).  Tästä lisää kun pääsemme tarkemmin olioiden ja luokkien kimppuun.

Seuraavaksi esitellään ohjelman pääohjelma ("oikea" ohjelma koostuu isosta kasasta aliohjelmia ja yhdestä pääohjelmasta, jonka nimi on main). 

public      tarkoittaa, että metodi on julkisesti näkyvä.  Muuten metodi ei näkyisi luokan ulkopuolelle eikä sitä voitaisi suorittaa.

static      tarkoittaa että metodi on ns. luokkametodi, eli se voidaan suorittaa, vaikkei luokasta olisi olemassa yhtään esiintymää eli oliota.  Luokkametodi ei voi käyttää luokan olioiden attribuutteja suoraan (koska oliota ei välttämättä ole).

void        ilmoittaa, että metodi jota kirjoitamme ei palauta mitään arvoa (eng. void = mitätön).

main        tarkoittaa pääohjelman nimeä.  Tämä TÄYTYY aina olla main.  Muut metodit voidaan nimetä vapaasti.

(           Metodin parametrilistan (argumenttilistan) alkusulku.

String[]           ilmoittaa että metodi saa parametrinaan taulukollisen (hakasulut tarkoittavat taulukkoa) merkkijonoja.  Nämä ovat merkkijonot tulevat ohjelmaan käynnistyksen yhteydessä olevina parametreinä. Käynnistys parametrejä voi olla nolla tai useita.

args        itse keksitty nimi jolla merkkijonotaulukkoon viitataan.  Tämä nimi voi olla mikä tahansa.

)           Metodin parametrilistan (argumenttilistan) loppusulku.

Ohjelma

java-alk\Hello3.java - tervehdys parametrina

/**

 * Ohjelma tulostaa kutsun mukana tulleet parametrit

 * @author Vesa Lappalainen

 * @version 1.0, 03.01.2003

 */

class Hello3 {

  public static void main(String[] args) {

    for (int i=0; i<args.length; i++)

      System.out.println("Parametri " + i + ": " + args[i]);

  }

}

 

Tulostaisi seuraavalla tavalla:

E:\kurssit\ohj2\moniste\esim\java-alk>java Hello3 eka toka kolmas

Parametri 0: eka

Parametri 1: toka

Parametri 2: kolmas

 

1.3.6 Lausesulut

{ }                         Javassa isompi joukko lauseita kootaan yhdeksi lauseeksi sulkemalla lauseet aaltosulkuihin.  Metodin täytyy aina sisältää aaltosulkupari, vaikka siinä olisi vain 0 tai 1 suoritettavaa lausetta.

1.3.7 Tulostuslause

  System.out.println("Hello world!")

 

System      on paketista java.lang löytyvä luokka, jossa on joukko hyödyllisiä oliota ja metodeja.

out         on System luokan olio, joka sisältää mm. tulostukseen tarvittavia metodeja.

println("?") tulostaa ajonaikana sen tekstin, joka on lainausmerkkien välissä.  Tulostuksen jälkeen vaihdetaan uudelle riville. Jos tarvitsee tulostaa useita eri tekstejä tai muuttujia välissä, voidaan niistä muodostaa +-operaatiolla uusi merkkijono, esimerkiksi:

System.out.println("Parametri " + i + ": " + args[i]);

 

1.3.8 Lauseen loppumerkki ;

;                            puolipiste lopettaa lauseen.  Puolipiste voidaan sijoittaa mihin tahansa lopetettavaan lauseeseen nähden.  Sen eteen voidaan jättää välilyöntejä tai jopa tyhjiä rivejä.  Sen pitää kuitenkin esiintyä ennen uuden lauseen alkua.   Näin Java–kieli ei ole rivisidonnainen, vaan Java–kielinen lause voi jakaantua usealle eri riville tai samalla rivillä voi olla useita Java-kielisiä lauseita.

Puolipisteen unohtaminen on tyypillinen syntaksivirhe.  Ylimääräiset puolipisteet aiheuttavat tyhjiä lauseita, joista tosin ei ole mitään haittaa:  “Tyhjän tekemiseen ei kauan mene” – sanoo tyhjän toimittaja.

1.3.9 Isot ja pienet kirjaimet

Isoilla ja pienillä kirjaimilla on Java–kielessä eri merkitys.  Siis EI VOIDA KIRJOITTAA:

SysTem.Out.printLn("Hello!")              // VÄÄRIN!                   L

 

1.3.10 White spaces, tyhjä

Välilyöntejä, tabulointimerkkejä, rivinvaihtoja ja sivunvaihtoja nimitetään yleisesti yhteisellä nimellä "white space".  Käännettäessä kommentit muutetaan yhdeksi välilyönniksi, joten myös kommenteista voitaisiin käyttää nimitystä "white space".  Jatkossa käytämme nimitystä tyhjä tai tyhjä merkki, kun tarkoitamme "white space".

Java–koodi voi sisältää tyhjiä merkkejä missä tahansa, kunhan niitä ei kirjoiteta keskelle sanaa tai tekstiä määrittelevän ""–parin ollessa auki. ""–parin sisällä tyhjätkin merkit ovat merkityksellisiä.

Siis kääntäjän kannalta malliohjelmamme voitaisiin kirjoittaa myös seuraavillakin tavoilla:

class                                                                  L

Hello4

{

public

static

void

main

(

String[]

args)

{

System

.

out

.

println

(

"Hello world!"

)

;

}

}

 

class Hello5{public static void main                                   L

         (String[]                                          args){

                 System.out.println("Hello world!"               );}}

 

L

class Hello6{public static void main(String[]args){System.out.println("Hello world!");}}

 

Yleinen tyyli on kuitenkin jakaa koodia riveihin ja sisentää lohkoja muutamalla pykälällä.  Kunnes lukija on varma omasta tyylistään, kannattaa matkia tässä monisteessa (ei kuitenkaan edellisiä esimerkkejä) esitettyä kirjoitustapaa ohjelmille.

1.3.11 Vakiomerkkijonot

Voimme määritellä ohjelmaamme vakioita; eli arvoja jotka esiintyvät ohjelmassa täsmälleen yhden kerran.  Näin ohjelmastamme saadaan helpommin muuteltava.  Esimerkiksi seuraava ohjelma tulostaisi myös tekstin "Hello world!": .  Vakioiden nimet on tapana kirjoittaa isoilla kirjaimilla.

java-alk\Hello7.java - tervehdys vakioksi

/**

 * Ohjelma tulostaa Hello World!  Tulostettava teksti on vakiona

 * @author Vesa Lappalainen

 * @version 1.0, 03.01.2003

 */

class Hello7 {

  static final String TERVE   = "Hello";

  static final String MAAILMA = "world!";

 

  public static void main(String[] args) {

    System.out.println(TERVE + " " + MAAILMA);

  }

}

 

Tehtävä 7.2    Terve maailma!

Kirjoita edellisestä ohjelmasta suomenkielellä tulostava versio (= suomenna ohjelma).

Tehtävä 7.3    Nimi ja osoite vakioksi

Kirjoita aikaisemmasta "Matti Meikäläinen asuu Kortepohjassa" –ohjelmasta versio, jossa nimi, osoite ja puhelin on esitelty vakioina.

 

1.3.12 Vakiolukuarvot

Vakiomäärittelyä voitaisiin käyttää esimerkiksi kokonaislukuvakioiden määrittelemiseen:

java-alk\Kuutio.java - monikulmion tiedot vakioksi

/**

 * Ohjelma tulostaa tietoja kuutiosta

 * @author Vesa Lappalainen

 * @version 1.0, 04.01.2003

 */

class Kuutio {

  static final String TAHOKAS    = "Kuutiossa";

  static final int    KARKIA     =  8;

  static final int    SIVUTASOJA =  6;

  static final int    SARMIA     = 12;

 

  public static void main(String[] args) {

    System.out.print  (TAHOKAS + " on " + KARKIA + " kärkeä,");

    System.out.print  (" " + SIVUTASOJA + " sivutasoa ja");

    System.out.println(" " + SARMIA + " särmää.");

  }

}

 

Tehtävä 7.4    Tetraedri

Muuta edellistä ohjelmaa siten, että tulostetaan samat asiat tetraedristä.

1.3.13 Tulostuksen muotoilu ja apumetodit

C:llä olisi edellisen esimerkin tulostus helppo muotoilla kutsulla:

  printf("%17s on %2d kärkeä,\n"     ,TAHOKAS,KARKIA);

 

Javassa joudumme kuitenkin tekemään saman asian eteen aluksi joukon apumetodeja:

java-alk\Kuutio4.java - monikulmion tulostus muotoillusti

/**

 * Ohjelma tulostaa tietoja kuutiosta "siistissä" muodossa

 * @author Vesa Lappalainen

 * @version 1.0, 05.01.2003

 */

class Kuutio4 {

  static final String TAHOKAS    = "Kuutiossa";

  static final int    KARKIA     =  8;

  static final int    SIVUTASOJA =  6;

  static final int    SARMIA     = 12;

 

  /**

   * Palauttaa jonon s muotoiltuna vähintään len-pituiseksi

   * <pre>

   * Esim:  fmt("2",3)  => "  2"

   *        fmt("2",-3) => "2  "

   * </pre>

   * @param s     muotoiltava jono

   * @param len   pituus, negatiivisella vasempaan laitaan, pos. oikeaan

   * @return      muotoiltu jono

   */

  static String fmt(String s,int len) {

    int needs = Math.abs(len) - s.length();

    if ( needs <= 0 ) return s;

    StringBuffer fill = new StringBuffer("                                   ");

    while ( fill.length() < needs ) fill.append("                            ");

    fill.delete(needs,1000);

    if ( len < 0 ) return s + fill;

    return fill + s;

  }

 

  /**

   * Tulostaa 2 merkkijonoa ja yhden kokonaisluvun siististi

   * @param s1 Ensimmäinen tulostettava jono

   * @param i  tulostettava kokonaisluku

   * @param s2 toinen tulostettava jono

   */

  static void tulosta(String s1, int i, String s2) {

    System.out.println(fmt(s1,20) + " " + fmt(String.valueOf(i),2) + " " + s2);

  }

 

  public static void main(String[] args) {

    tulosta(TAHOKAS + " on", KARKIA    , "kärkeä,");

    tulosta(""             , SIVUTASOJA, "sivutasoa ja");

    tulosta(""             , SARMIA    , "särmää.");

  }

}

Tehtävä 7.5    Apumetodit

Mieti miksi edellinen Java-ohjelma tulostaa tiedot seuraavassa muodossa:

 

0        1         2         3         4

1234567890123456789012345678901234567890

––––––––––––––––––––––––––––––––––––––––––––

        Kuutiossa on  8 kärkeä,

                      6 sivutasoa ja

                     12 särmää.