Java

Ohjelmistotekniikan seminaari 28.11.1996
Otto Kopra


Sisällysluettelo


1. JOHDANTO

Viime aikoina on käyty paljon keskustelua tietotekniikan tulevaisuudesta, tietoverkoista, verkkotietokoneista, WWW:stä jne. Tavalla tai toisella keskusteluun on aina liittynyt Java-kieli. Sitä on kaavailty osaksi WWW:n suurta tulevaisuutta, tulevien käyttöjärjestelmien kulmakiveksi tai sulautettujen järjestelmien ohjelmointiympäristöksi. Jopa kilpailevia järjestelmiä kehittävät yritykset ovat ilmoittaneet joka tapauksessa tukevansa Javaa. Tulevaisuus näyttää siis varmalta, mutta pystyykö Java täyttämään kaikki sille asetetut odotukset?

Tässä esitelmässä perehdytään pintapuolisesti Java-kieleen, sen perusrakenteisiin, mukana tuleviin kirjastoihin ja Javan käyttöön WWW-dokumenttien osana. Lukijalla oletetaan olevan perustiedot sekä oliopohjaisesta ohjelmoinnista että C- tai C++-kielestä.

2. Java-kielen historia

Javan kehitystyö alkoi vuonna 1990 Sun Microsystems:in käynnistäessä Patrick Naughtonin johdolla projektin, joka tunnettiin yksinkertaisesti nimellä "Green". Projektin alkuperäinen tavoite oli kehittää ohjelmointijärjestelmä sulautettuja systeemejä varten.

Kehitystyö alkoi laajentamalla C++-kääntäjää, mutta pian kävi ilmi ettei tämä strategia toimisi kovin pitkälle. C++ oli yksinkertaisesti sopimaton tehtävään. Projektissa työskennellyt James Gosling alkoi kehitellä täysin uutta ohjelmointikieltä, jolle hän antoi työnimeksi Oak työhuoneen ulkopuolella seisoneen puun mukaan. Oakin kehittely jatkui, ja tuotemerkkiä etsittäessä sen nimi lopulta muutettiin Javaksi.

Green-projektin ensimmäinen varsinainen tuote oli Star7, joka oli kädessä pidettävän tietokoneen ja kaukosäätimen risteytys. Star7 ei koskaan päässyt myyntiin, mutta se riitti vakuuttamaan Sunin silloisen pääjohtajan, Scott McNealyn, joka muodosti Green-projektista erillisen yhtiön, First Person Incin.

Samaan aikaan First Person siirsi kiinnostuksensa nk. settop:ien käyttöjärjestelmiin. Settopit, kuten sulautetut järjestelmät, vaativat käyttöjärjestelmän lisäksi ohjelmointikielen, jolla olisi mahdollista kirjoittaa kompaktia, virheetöntä, turvallista ja ennenkaikkea laitteistosta riippumatonta koodia.

Settop-laitteiden markkinat osoittautuivat lähes olemattomiksi, joten vuonna 1994 First Person Inc sulautetttiin takaisin emoyhtiöön Sun:iin. Suuri osa First Person In:cin työntekijöistä siirtyi muihin tehtäviin, mutta osa jäi jatkamaan Javan kehitystyötä ja miettimään sille uusia käyttökohteita. Saman vuonnna World Wide Web oli lyömässä itseään voimalla läpi, ja Naughton näki siinä Javalle sopivan käyttökohteen.

Viikonlopun mittaisen koodaussession aikana syntyi prototyyppi uudenlaisesta selailimesta, WebRunnerista, joka pystyi ajamaan HTML-koodin lomaan istutettuja Java-ohjelmia. WebRunner onnistui vakuuttamaan Sunin johtajat Java-kielen hyödyllisyydestä, ja Javan voittokulku saattoi lopulta alkaa.

3. Java-kielen perusteet

3.1 Yleistä

Javan suunnittelun lähtökohtia ovat olleet laitteistoriippumattomuus, turvallisuus ja ohjelmoinnin helppous. Java-kieli ei sisällä mitään uusia tai kokeellisia piirteitä, vaan siihen on koottu useissa kielissä hyviksi havaittuja piirteitä.

Java on oliopohjainen, vahvaa tyypitystä tukeva kieli josta löytyvät automaattinen roskien keruu, abstraktit olioluokat, säikeet ja poikkeutukset.

Java on sekä kääntävä että tulkkaava kieli. Java-kieliset ohjelmat käännetään ensin nk. bytecode-muotoon, joka sitten ajetaan Java virtuaalikoneella.

3.2 Javan ja C++:n eroavaisuudet

Java muistuttaa paljon C++:aa, eikä ihme, sillä kielen kehitys lähti alunperin liikkeelle C++:n ominaisuuksien laajentamisesta. Myöhemmin Javasta kehittyi oma, erillinen kieli, joka eroaa huomattavasti C++:sta. Muutamia tärkeimpiä Javan ja C++:n välisiä eroja ovat:

3.3 Javan syntaksi

Javan syntaksi on hyvin lähellä C:tä tai C++:aa. Ohjelmalohkot merkitään kaarisuluilla, komennot erotetaan puolipisteellä, ja taulukot ja niiden indeksointi ilmaistaan hakasuluilla. Kommentit merkitään joko kaksois-kenoviivalla (//) tai C-kielestä tutulla /* ... */ -rakenteella. Lähes kaikki Javan ja C++:n yhteiset komennot ovat syntaksiltaan täysin identtisiä. Tällaisia komentoja ovat:

if else switch case
default break for do
while new return try
catch throw continue

Muut Java-kielen avainsanat on lueteltu seuraavassa:

abstract private boolean do
implements protected throws double
import public transient byte
instanceof extends int short
void final interface static
volatile char finally long
super class float native
synchronized package this

Niistä tärkeimmät käydään läpi myöhemmin tässä luvussa.

3.4 Muuttujat ja tietotyypit

Javan tietotyypit jakautuvat kahteen kategoriaan: primitiivi- ja viitetyyppeihin. Primitiivityyppejä ovat looginen tyyppi boolean sekä numeeriset tyypit. Kaikki muut tyypit, kuten taulukot, merkkijonot ja kaikki olioluokat, kuuluvat viitetyyppeihin.

Primitiivityyppinen muuttuja sisältää itsessään muuttujan arvon, viitetyyppinen muuttuja vain joko null-arvon tai viittauksen johonkin olioon.

Molemmat muuttujatyypit on alustettava ennen käyttöä. Primitiivityyppinen muuttuja alustetaan yksinkertaisesti asettamalla sille arvo, viitetyyppinen muuttuja alustetaan new-operaattorilla.

Alla on taulukoitu kaiki Javan primitiivityypit

Taulukko 1. kokonaislukutyypit
Nimi Pituus
(bittejä)
lukualue
byte 8 [-127 , 128]
short 16 [-32 768 , 32 767]
int 32 [-2 147 483 648 , 2 147 483 647]
long 64 [-9 223 372 036 854 775 808 ,
9 223 372 036 854 775 807]

Taulukko 2. liukulukutyypit
Nimi Pituus
(bittejä)
kommentti
float 32 IEEE-754 liukuluku
double 64 IEEE-754 liukuluku

Taulukko 3. muut tyypit
Nimi Pituus
(bittejä)
lukualue
boolean 1 true tai false
char 16 Unicode-merkki

Taulukot määritellään kirjoittamalla halutun tyypin perään hakasulut ja taulukon nimi. Esimerkiksi

   int[]kalat;

määrittää kokonaislukutaulukon. Ylläoleva määritelmä luo vasta viitteen taulukolle. Jotta taulukkoa voitaisiin käyttää, se on luotava ensin new-operaattorilla. Samalla määritetään taulukon haluttu koko.

   kalat = new int[100]; 
   int kalapituus = kalat.length; 

Taulukot indeksoidaan kuten C:ssä, eli ensimmäisen alkion indeksi on nolla ja viimeisen (taulukon koko- 1). Kaikilla taulukoilla on length-jäsen, kokonaisluku, joka sisältää taulukon koon ohjelman suorituksen aikana.

3.5 Operaattorit

Alla on taulukoitu kaikki Javan operaattorit..

Taulukko 4. Aritmeettiset operaattorit
Operaattori Operaattorin
käyttö
Toiminta
+ op1 + op2 Yhteenlasku
- op1 - op2 Vähennyslasku
* op1 * op2 Kertolasku
/ op1 / op2 Jakolasku
% op1 % op2 Jakojäännös, kun op1 jaetaan op2:lla

Taulukko 5. Etumerkkioperaattorit
Operaattori Operaattorin
käyttö
Toiminta
+ + op Positiivinen etumerkki
- - op Aritmeettinen negaatio

Taulukko 6. ++ ja---operaattorit
Operaattori Operaattorin
käyttö
Toiminta
++ op++ op:n arvoa lisätään yhdellä. Lausekkeen
arvo on op.
++ ++op Kuten edellä, mutta lausekkeen arvo on
op+1.
-- op-- op:n arvoa vähennetään yhdellä. Lausekkeen
arvo on op.
-- --op Kuten edellä, mutta lausekkeen arvo on
op-1.

Taulukko 7. Vertailuoperaattorit
Operaattori Operaattorin
käyttö
Palauttaa tosi-arvon, jos
> op1 > op2 op1 on suurempi kuin op2
< op1 < op2 op1 on pienempi kuin op2
>= op1 >= op2 op1 on yhtäsuuri tai suurempi kuin op2
<= op1 <= op2 op1 on yhtäsuuri tai pienempi kuin op2
== op1 == op2 op1 on yhtäsuuri kuin op2
!= op1 != op2 op1 on erisuuri tai suurempi kuin op2

Taulukko 8. Loogiset operaattorit
Operaattori Operaattorin
käyttö
Kommentti
&& op1 && op2 Looginen AND
|| op1 || op2 Looginen OR
! !op Looginen negaatio

Taulukko 9. Bittioperaattorit
Operaattori Operaattorin
käyttö
Kommentti
>> op1 >> op2 op1:n bittejä siirretään oikealle
op2:n verran
<< op1 << op2 op1:n bittejä siirretään vasemmalle
op2:n verran
>>> op1 >>> op2 Bitinsiirto oikealle ilman etumerkkiä.
& op1 & op2 AND
| op1 | op2 OR
^ op1 ^ op2 XOR
~ ~op komplementti

Lisäksi Javassa voi käyttää C:stä ja C++:ta tuttuja lyhenteitä +=,-=, *=,/=, jne.

3.6 Oliot ja luokat

Oliot ja luokat muodostavat Java-kielisen koodin koko rakenteen. Kaiken ohjelmakoodin on kuuluttava osana luokanmääritykseen.

Luokka määritellään class-avainsanalla:

   class Complex { ... } 

Kun luokkaa käytetään muuttujanmäärityksessä, se ei voi olla muu kuin viitemuuttuja, joka täytyy alustaa. Esimerkiksi seuraava rivi luo Complex-tyyppisen olion ja asettaa muuttujan a viittaamaan siihen.

   Complex a = new Complex();

Luokka voidaan määritellä abstraktiksi luokaksi, jolloin luokasta itsestään ei voi luoda instanssia, mutta luokan voi periä. Abstraktiksi luokaksi määrittely tapahtuu abstract-avainsanalla:

public abstract class Number { ... } 

Normaalisti luokkaa voi käyttää vain saman paketin (ks. luku 3.7) luokat. Lisäämällä public-muokkaaja luokanmäärityksen eteen voidaan käyttöoikeus luokkaan antaa myös paketin ulkopuolisille luokille. Luokanmäärityksessä ei voi käyttää muita turvallisuusmuokkaajia.

Luokan perinnän voi estää final-avainsanalla. Luokkaa voi käyttää normaalisti, mutta siitä ei voi muodostaa aliluokkia.

   public final class String {
      ... 
   }

3.6.1 Luokkien attribuutit

Luokan attribuutti voi olla joko tieto- tai metodiattribuutti. Attribuutit määritellään kokonaisuudessaan luokanmäärittelyn sisällä. Niille voi antaa erilaisia muokkaajia, jotka sijoitetaan ennen varsinaista attribuutin määrittelyä.

Toisten luokkien käyttöoikeuksia luokan attribuutteihin voidaan rajoittaa sopivalla turvallisuusmuokkaajalla. Alla on lista ja lyhyt kuvaus kaikista attribuuttien käyttöoikeudet määrittelevistä muokkaajista.

public           Kaikilla on käyttöoikeus attribuuttiin.                 

protected        Vain luokalla itsellään, siitä perittyillä aliluokilla  
                 ja saman paketin jäsenillä on käyttöoikeus              
                 attribuuttiin.                                          

private          Vain luokalla itsellään on käyttöoikeus attribuuttiin.  

Oletusarvona vain luokalla itsellään ja saman paketin (ks. luku 3.7) muilla luokilla on käyttöoikeudet attribuutteihin.

Tietoattribuutit määritellään kuten muuttujat. Tietoattribuutin voi alustaa joko suoraan määrittelyn yhteydessä, tai myöhemmin jossain metodissa. Tietoattribuuteille voidaan antaa käyttöoikeuden lisäksi myös muita muokkaajia. Alla on lyhyt luettelo kaikista tietoattribuuttien muokkaajista.

final            attribuutti on vakio. final-attribuutti täytyy alustaa  
                 määrittelyn yhteydessä                                  

static           luokkaattribuutti. Sille varataan muistia vaikka        
                 ohjelma ei missään vaiheessa loisi oliota luokasta.     

volatile         attribuuttia päivitetään asynkronisesti (tämä           
                 muokkaaja ei ole käytössä nykyisessä Javan versiossa)   

transient        attribuuttia ei tallenneta mahdollisten                 
                 arkistointioperaatoiden yhteydessä. (ei käytössä        
                 nykyisessä Javan versiossa)                             


Metodit määritellään kuten C++:ssa. Myös metodeille voidaan antaa muita muokkaajia kuin käyttöoikeudet. Alla on lista metodien muokkaajia.

static           Metodi on luokkametodi; sitä voidaan kutsua vaikka      
                 ohjelma ei loisikaan yhtään instanssia luokasta.        

abstract         Metodi on abstrakti, ts. sitä ei toteuteta sen          
                 esitelleessä luokassa, vaan aliluokkien on              
                 toteutettava se aina erikseen.                          

final            Metodia ei voida uudelleenmääritellä aliluokissa.       

native           Metodi on toteutettu ohjelman ulkopuolella jollain      
                 muulla ohjelmointikielellä                              

synchronized     Metodi lukitsee olion käyttämän muistialueen, jotta     
                 toiset säikeet eivät voisi kutusua olion metodeja.      

Seuraavassa esimerkki attribuuttien määrittelystä:

   /** The representation of a 3D model */ 
   class Model3D { 
      float vert[]; 
      int tvert[]; 
      int nvert, maxvert; 
      int con[];
      int ncon, maxcon; 
      boolean transformed; 
      Matrix3D mat;
      float xmin, xmax, ymin, ymax, zmin, zmax; 

      Model3D () {
         ... 
      } 

      /** Add a vertex to this model */ 
      int addVert(float x, float y, floatz) {
         ... 
      }
 
      /** Transform all the points in this model */ 
      void transform() {
         ... 
      } 

      /* Quick Sort implementation */ 
      private void quickSort(int a[], intleft, int right) {
         ... 
      } 

      static Color gr[];

      /** Paint this model to a graphics context */ 
      void paint(Graphics g) {
         ... 
      } 
   }

3.6.2 Ohjelman aloituskohta

Java-kielisen ohjelman suoritus alkaa aina main-metodista, joka on määriteltävä seuraavasti:

   public static void main(String[] args) { ... } 

Vain yksi luokka voi määrittää main-metodin. Sen ainoa parametri, merkkijonotaulukko sisältää ohjelmalle annetut parametrit.

3.6.3 Rakentajat ja hävittäjät

Luokan rakentaja on metodi jolla sama nimi kuin itse luokalla. Ne eivät palauta mitään arvoa, eikä niille siis määritetä palautusarvon tyyppiä. Luokalle ei ole pakko määritellä rakentajaa, sillä Java määrittää automaattisesti oletusrakentajan jokaiselle luokalle. Rakentajalle voi antaa minkä tahansa turvallisuusmuokkaajan, mutta ei muita muokkaajia. Alla esimerkki rakentajan määrittelystä:

   class Model3D { 
      Model3D () {
         ... 
      } 
   } 

Varsinaisia hävittäjiä ei Javassa ole, vaan niiden virkaa toimittaa Object-luokan (ks. luku 3.5.4) finalize-metodi, jonka muut luokat voivat vapaasti määritellä uudelleen. finalize-metodia kutsutaan aina ennen kuin olio poistetaan muistista. Oletustoteutuksena se ei tee mitään.

3.6.4 Perintä

Vain yksinkertainen perintä on mahdollista Javassa. Perintää ilmaistaan extends-avainsanalla:

   class Complex extends Number {
      ... 
   } 

Kaikki Javan luokkahierarkiaan kuuluvat luokat, käyttäjän luomat mukaan luettuna, perivät Object-luokan. Object-luokka määrittelee joukon yleishyödyllisiä metodeja, jotka alempana hierarkiassa sijaitsevat luokat voivat määritellä uudelleen tarpeen mukaan. Tällaisia ovat esimerkiksi ToString, joka antaa tekstuaalisen esityksen oliosta ja equals, joka testaa kahden olion samanarvoisuutta.

Aliluokat voivat käyttää välittömän edeltäjänsä metodeja tai jäsenmuuttujia super-komennon avulla. super-komentoa käytetään aivan kuin se olisi tavallinen viitemuuttuja. Luokka voi kutsua edeltäjäluokan konstruktoria super:in avulla laittamalla konstruktorin argumentit sulkuihin sen jälkeen. Seuraavassa esimerkki super-komennon käytöstä.

   class ParseException extends Exception {
      ParseException(String s) {
         super(s);
      } 
   }

3.6.5 Rajapinnat

Java luokat voivat kiertää yksinkertaisen perinnän rajoituksia määrittelemällä yhteisen rajapinnan. Niiden avulla voidaan käyttää yhdessä luokkia jotka sijaitsevat erillään luokkahierarkiassa.

Rajapinta määritellään interface-avainsanan avulla samaan tapaan kuin luokka. Erona luokanmäärittelyyn rajapinnan kaikki attribuutit ovat vakioita, ja metodeita ei implementoida. Rajapinta voi periä yhden tai useampia rajapintoja extends-avainsanalla. Seuraavassa on esimerkki rajapinnan määrittelystä.

   interface DoubleLinkedList extends Collection, List { 
      int MAXNUMOFELEMENTS = 500; 
      void add(Object obj); 
      void delete(Object obj); 
      Object find(Object obj); 
      int currentCount(); 
   }

Jokainen metodin määritys lopetetaan puolipisteellä, koska rajapinta ei itse toteuta metodeja, vaan jättää sen luokkien tehtäväksi.

Luokanmäärityksessä luokan toteuttamat rajapinnat ilmoitetaan implements-avainsanalla. Luokka voi toteuttaa useampia rajapintoja kerrallaan. Esimerkiksi:

   class Model3DList implements DoubleLinkedList {
      ... 
   } 

Rajapintoja käytetään kuten luokkien nimiä. Esimerkiksi viite:

   Collection box; 

voi viitata mihin tahansa olioon jonka luokka toteuttaa Collection-rajapinnan.

3.7 Paketit

Javan luokat on mahdollista koota yhteen paketeiksi. Paketti määritellään laittamalla tiedoston alkuun avainsana package ja sen perään paketin nimi. Kaikki samassa tiedostossa olevat luokat ja käyttöliittymät kuuluvat samaan pakettiin.

Seuraava esimerkki luo graphics-nimisen paketin, joka sisältää yhden luokan ja yhden rajapinnan:

   package graphics; 
   interface GraphicObject {
      ... 
   } 
   class BitMap implements GraphicObject {
      ... 
   } 

Ulkopuolisen paketin luokat tuodaan mukaan ohjelmaan import-komennolla:

   import graphics.*; 
   import graphics.BitMap; 

import-komennon avulla voidaan ottaa paketista joko yksittäinen paketin jäsen, tai käyttämällä jokerimerkkiä * kaikki paketin jäsenet. Paketin jäseniä voidaan importin jälkeen käyttää kuten mitä tahansa ohjelmassa määritettyä luokkaa tai rajapintaa. Jos ohjelmassa määriteltyjen luokkien tai rajapintojen ja mukaantuotujen pakettien jäsenten nimien välillä on sekaannuksen vaara, voidaan paketin jäsenet määritellä tarkasti laittamalla paketin nimi pisteellä erotettuna ennen jäsenen nimeä:

   graphics.Circle FirstCircle; 

   class Triangle implements
   graphics.GraphicObject {
      ... 
   } 

Paketin binääritiedostojen täytyy sijaita hakemistossa, jolla on sama nimi kuin paketilla, ja joka löytyy classpath-järjestelmämuuttujasta. Pakettien nimet voivat sisältää useampia osia pisteellä erotettuna, jolloin jokainen nimen osa viittaa omaan hakemistoon. Esimerkiksi seuraavalla import-komennolla haettavan paketin pitäisi löytyä hakemistosta ../java/lang/awt/

   import java.lang.awt.*;

Kaikki luokat ja rajapinnat kuuluvat automaattisesti johonkin pakettiin. Jos pakettia ei määritellä erikseen, kuuluvat tiedoston luokat ja rajapinnat oletuspakettiin, jolla ei ole nimeä ja joka otetaan aina mukaan ohjelmaan.

4. Luokkakirjasto

Java-kielen mukana tulee laaja luokkakirjasto, jonka paketeista löytyy kaikki tarvittava applettien ohjelmoimiseen, graafisten käyttöliittymien luomiseen, syöttöön, tulostukseen ja moneen muuhun tarkoitukseen. Seuraavassa lyhyt luettelo Javan mukana tulevista paketeista:

Applet- ja AWT-paketit käydään läpi omissa luvuissaan. Muista paketeista, erityisesti j

java.lang:ista, annetaan jäljempänä lyhyt kuvaus.

4.1 Java.lang

Java.lang on ehkä tärkein Javan mukana tulevista paketeista. Alla on lyhyt lista sen sisällöstä. Tärkeimmät luokat käsitellään vielä erikseen.

4.1.1 System-luokka

System-luokka sisältää informaatiota laitteistosta ja käyttöjärjestelmästä. Kaikki sen metodit ja tetoattribuutit ovat luokkakohtaisia; siitä ei siis tarvitse luoda instanssia jotta sen attribuutteihin pääsisi käsiksi. System-luokan tarjoamat palvelut on lueteltu alla lyhyesti.

4.1.2 String ja StringBuffer

String ja StringBuffer ovat Javan merkkijonojen käsittelyyn tarkoitetut luokat. String on sopivin muuttumattomien merkkijonojen käsittelyyn. StringBuffer on tarkoituksenmukaisin kun on tarpeen muuttaa merkkijonon sisältöä ajon aikana.

String-luokka sisältää useita merkkijonon sisällön lukemiseen tarkoitettuja metodeja. Näitä ovat mm. charAt, length, substring, indexOf ja lastIndexOf.

StringBuffer sisältää edellisten lisäksi paljon merkkijonojen muuttamiseen tarkoitettuja metodeja kuten setCharAt, reverseIt ja append. Lisäksi, koska StringBuffer on itse asiassa merkkijonojen tallettamiseen varattu muistialue, se sisältää capacity-metodin, joka kertoo varatun muistin määrän.

4.1.3 Säikeet

Java-kieli sisältää sisäänrakennetun tuen säikeille. Koska Java on tarkoitettu toimimaan useissa eri laiteympäristöissä ja käyttöjärjestelmissä, se ei voi luottaa järjestelmän moniajoon. Javan säikeet on suunniteltu mahdollisimman ympäristöriippumattomiksi, joskin järjestelmän oma moniajotuki vaikuttaa jonkin verran niiden toimintaan.

Säikeen voi luoda kahdella tavalla: luomalla sille oman luokan, joka perii java.lang -paketin Thread-luokan, tai luomalla luokan joka toteuttaa Runnable-rajapinnan. Jälkimmäinen tapa on parempi jos luokan on perittävä jokin muu luokka (esimerkiksi Applet).

Säikeen on määriteltävä joukko metodeita, jotka ohjaavat sen toimintaa. start-metodi käynnistää säikeen ja varaa sen tarvitsemat resurssit, run sisältää säikeen varsinaisen ohjelmakoodin, ja stop pysäyttää säikeen ja vapauttaa sen varaamat resurssit.

4.1.4 Poikkeutukset

Poikkeutukset ovat tehokas tapa käsitellä ohjelman sisällä tapahtuvia virheitä. Tyypillisesti virhetilanteessa virheen aiheuttanut metodi lähettää poikkeutuksen metodia kutsuneelle metodille. Jos kutsunut metodi ei käsittele poikkeutusta, se välitetään kutsupinossa (call stack) eteenpäin, kunnes jokin metodi lopultaa käsittelee lähetetyn poikkeutuksen. Jos mikään metodi ei käsittele poikkeutusta, ohjelman suoritus loppuu.

Java-kielen poikkeutukset välitetään Throwable-luokan, tai jonkin sen aliluokan avulla. Käyttäjä voi määritellä omia poikkeutuksiaan perimällä jonkun Throwable-luokkahierarkian luokan.


Kuva 1: Java-kielen poikkeutusten luokkahierarkia

Metodin täytyy joko käsitellä tai esitellä kaikki poikkeutukset, mitä metodin sisällä voi tapahtua. Poikkeutuksen määrittely esittely throws-avainsanalla, joka lisätään metodin argumenttilistan perään ennen varsinaista ohjelmalohkoa. Sen jälkeen luetellaan kaikki ne poikkeutukset mitä metodi saattaa aiheuttaa. Poikkeutuksen lähettäminen tapahtuu throw-komennolla:

   class ParseException extends Exception {
      ... 
   } 
   String Parse(String sentence) throws ParseException {
      if (!sentence.endsWith(".") { 
         throw new ParseException("Not a full sentence"); 
   }
      ...
} 

Poikkeutusten käsittely tapahtuu try-catch-finally-lohkolla. try-lohkon sisään sijoitetaan mahdollisen poikkeutuksen lähettävä ohjelmakoodi, catch-lohkot yrittävät tunnistaa ja käsitellä lähetetyn poikkeutuksen ja finally-lohko suoritetaan aina lopuksi, lähettipä ohjelma poikkeutuksen tai ei. Alla on esimerkki try-catch-finally-lohkosta:

   String Translate(String s) {
      ... 
      String t; 
      try {
         t = Parse(s); 
      } catch (ParseException p) {
         ... 
      } catch (Exception e) {
         ...
      } finally {
         ... 
      }
   ... 
   }

catch-lohkoja läpikäydessään ohjelma suorittaa ensimmäisen sopivan catch-lauseen, ja hyppää loppujen yli. Yleisluontoiset virhetilanteet käsittelevät lauseet kannattaa sijoittaa lohkon loppupäähän.

4.2 Java.io

Java.io-paketti sisältää syöttö- ja tulostusvirtojen luokkamäärittelyt, tiedostojen käsittelyyn tarvittavat luokat, sekä käyttöliittymät Javan primitiivityyppisen tiedon syöttöön ja tulostukseen.

InputStream ja OutputStream ovat syöttö- ja tulostusvirtojen perusluokat. Ne sisältävät vain yksinkertaisen käyttöliittymän, ja pystyvät rajoitettuun tiedonkäsittelyyn. Kaikki monimutkaisemmat tominnot on toteutettu näiden luokkien aliluokissa. Alla on lista InputStream:in ja OutputStream:in tärkeimmistä aliluokista ja niiden käyttötarkoituksista.

Edellämainittujen luokkien lisäksi java.io sisältää kirjaston erilaisia syöttö- ja tulostusvirtaluokkia, jotka käsittelevät tietoa lukemisen ja tulostamisen ohella. Näitä luokkia ei käsitellä tässä esitelmässä.

Syöttö- tai tulostusvirta avataan automaattisesti luotaessa, ja se suljetaan joko close-metodilla, tai automaattisesti kun systeemi poistaa virtaa vastaavan olion muistista. Avatun virran lukeminen ja kirjoittaminen tapahtuu luokan metodeilla. Alla on lyhyt esimerkki tiedostojen lukemisesta ja kirjoittamisesta FileInputStream:in ja FileOutputStream:in avulla:

class FileStreamsTest { 
   public static void main(String[] args) { 
      try{
         File inputFile = new File("farrago.txt"); 
         File outputFile = new File("outagain.txt"); 
         FileInputStream fis = new FileInputStream(inputFile); 
         FileOutputStream fos = new FileOutputStream(outputFile);
         int c; 
         while ((c = fis.read()) !=-1) { 
            fos.write(c); 
         } 
      } catch (FileNotFoundException e) { 
         System.err.println("FileStreamsTest:" + e); 
      } catch (IOException e) { 
         System.err.println("FileStreamsTest:" + e); 
      } finally {
         fis.close(); 
         fos.close(); 
      } 
   } 
} 

5. Graafisen käyttöliittymän ohjelmointi

Javan AWT (Abstract Window Toolkit) sisältää laajan kokoelman graafisen käyttöliittymän ohjelmointiin tarvittavia luokkia. Tavallisten ikkunointijärjestelmän komponenttien kuten painikkeiden, valikkojen, jne. lisäksi AWT sisältää luokkia, joiden avulla voidaan käsitellä ja jossain määrin muokata bittikarttamuodossa olevia kuvia.

5.1 Komponentit

Java-ohjelman käyttöliittymä koostuu kahdenlaisista komponenteista: peruskomponenteista ja säiliökomponenteista. Peruskomponentteihin kuuluvat kaikki ikkunointijärjestelmän tärkeimmät osat: nappulat, listat, valintalistat, valikot, vierityspalkit, otsikot, checkboxit, radiopainikkeet, valintalistat ja tekstilaatikot. Säiliökomponentteja, kuten ikkunoita, dialogeja ja paneleita, käytetään peruskomponenttien sommitteluun. Kuvassa 2 näkyvät kaikki AWT:n komponentit sellaisina kuin ne näkyvät Windows NT 3.51-järjestelmässä.



Kuva 2: Kaikki AWT:n komponentit.

Valikkoa lukuunottamatta kaikki AWT:n komponenttiluokat ovat Component-luokan alaluokkia. Kuvissa 3 ja 4 esitetään AWT:n komponenttien luokkahierarkia.


Kuva 3: Komponenttien luokkahierarkia


Kuva 4: Valikkokomponenttien luokkahierarkia

5.1.1 Komponentit ja säiliökomponentit

Ennenkuin komponentti voi tulla näkyviin, sen on kuuluttava johonkin säiliökomponenttiin. Ainoa poikkeus tästä säännöstä ovat säiliökomponentit itse. Kaikki säiliökomponentit ovat Container-luokan aliluokkia. Frame on tavallinen ikkuna, Dialog on joko modaalinen tai ei-modaalinen dialogi, FileDialog on AWT:n mukana tuleva tiedostojen käsittelyyn tarkoitettu dialogi ja Panel yleiskäyttöinen komponenttien ryhmittelyyn tarkoitettu komponentti.

Komponentti lisätään säiliöön Container-luokan add-metodilla. Tämän jälkeen komponentti tulee näkyviin automaattisesti, kun säiliö piirretään ensimmäisen kerran näytölle. add-metodin parametrit riippuvat käytössä olevasta layoutmanagerista (ks. luku 5.3), viimeinen argumentti on kuitenkin aina säiliöön lisättävä komponentti.

5.1.2 Komponenttien piirto

Komponenttien piirto näytölle tapahtuu aina alimmasta komponentista ylimpään. Kukin komponentti siis piirtää itsensä ennen sen mahdollisesti sisältämiä komponentteja.

Komponentin piirtäminen tapahtuu vain, kun AWT antaa siihen luvan. Tämä siksi, että piirtäminen voisi tapahtua keskeytymättä. AWT pyytää komponenttia piirtämään itsensä kutsumalla sen update-metodia. Oletuksena (Component-luokan toteutuksessa) update tyhjentää komponentin alueen piirtämällä taustanvärisen suorakulmion koko komponentin alueelle, ja kutsuu komponentin paint-metodia.

Sekä update että paint-metodille välitetään vain yksi argumentti. Tämä Graphics-luokan olio, joka edustaa graafista kontekstia johon komponentti voi piirtää. Graphics-luokka sisältää metodit kuvioiden (viiva, kaari, ympyrä, soikio, suorakulmio, monikulmio), tekstin ja bittikarttojen piirtämiseen sekä värien ja piirtomoodin asetukseen.

Yksinkertaisin tapa toteuttaa oman komponentin piirto on määrittää uudestaan paint-metodi, ja antaa AWT :n päättää milloin piirtäminen tapahtuu. Koska update puhdistaa koko komponentin alueen ennen paint-metodin kutsua, se saattaa aiheuttaa vilkkumista erityisesti animaatioissa. Tällaisissa tapauksissa on parasta tehdä oma toteutus update-metodista turhan piirtämisen eliminoimiseksi.

5.1.3 Komponenttien rakenne

AWT on suunniteltu siten, että se on riippumaton alla olevasta käyttöjärjestelmästä, mutta säilyttää silti kunkin järjestelmän oman graafisen tyylin. Jotta tämä olisi mahdollista, on AWT:n rakenne jaettu kahteen osaan. Käyttäjälle näkyvän osan muodostavat AWT:n luokkakirjasto, jonka avulla komponentteja voidaan käsitellä. Jokaista luokkaa vastaa vastinkappale (engl. peer), joka toteuttaa kunkin komponentin järjestelmäkohtaisilla kutsuilla. Vastinkappaleet määräävät viimekädessä kunkin komponentin ulkoasun ja käyttäytymisen, jonka takia Java-käyttöliittymät näyttävät hieman erilaisilta eri järjestelmissä.

Kunkin komponentin vastinkappale luodaan vasta viime hetkellä, juuri ennen kuin vastinkappaletta vastaava komponentti piirretään näytölle. Tästä johtuu muunmuassa se, että komponenttien kokoa ei tiedetä ennen kuin ne piirrettään ensimmäisen kerran. Jos komponentti lisätään säiliöön jota ei ole vielä tuotu näkyviin, kaikki sen sisältämien komponenttien vastinkappaleet luodaan automaattisesti kun säiliö piirretään. Jos komponentti lisätään jo näkyvillä olevaan säiliöön, komponentin vastinkappale on luotava erikseen validate-kutsulla.


Kuva 5: Esimerkki AWT:n komponenttien rakenteesta

5.2 Käyttöliittymän sommittelu

Koska AWT on laiteriippumaton kirjasto, komponenttien tarkka sijoittelu säiliön sisällä on yleensä erittäin hankalaa, mikä johtaa usein järjestelmästä riippuvaan toteutukseen. Ongelmaan voidaan ratkaista layoutmanagereiden avulla.

Layoutmanager huolehtii komponenttien tarkasta sijoittelusta säiliön sisällä. AWT:n mukana tulee 5 valmista layoutmanager:ia, jotka käsitellään kukin erikseen. Myös omien layoutmanagerien teko on mahdollista, mutta siihen ei puututa tässä.

Layoutmanager otetaan käyttöön luomalla instanssi halutun tyyppisestä managerista, ja käyttämällä säiliökomponentin setLayout-metodia. Tämän jälkeen sijoiteltavat komponentit lisätään säiliöön add-metodilla. Jotkut layoutmanagerit vaativat useamman parametrin käyttöä add-metodissa; tästä mainitaan erikseen kunkin managerin kohdalla.

5.2.1 BorderLayout


Kuva 6: Esimerkki BorderLayout:in käytöstä

BorderLayout on AWT:n oletusmanageri kaikille ikkunaluokille, ts. Frame ja Dialog-luokille ja niiden alaluokille. BorderLayout jakaa säiliön viiteen osaan: pohjoiseen, etelään, itään, länteen ja keskustaan. Näihin kuhunkin voi asettaa yhden komponentin.

BorderLayout vaatii kahden argumentin käyttöä add-metodin kutsussa. Ensimmäisenä annettava argumentti on merkkijono, joka sisältää säiliön osan nimen, minne komponentti sijoitetaan ("North", "South", "East", "West" tai "Center"). Jälkimmäinen argumentti on viite sijoitettavaan komponenttiin. Jos yhteen osaan sijoitetaan useampi komponentti, vain viimeisin komponentti tulee näkyviin.

5.2.2 CardLayout


Kuva 7: Esimerkki CardLayout:ista. Painikkeet Button1, Button2, Button3 ja Textfield sijaitsevat omissa Panel-säiliöissään, joita vaihdellaan CardLayout-managerin avulla.

CardLayout mahdollistaa usean vaihtoehtoisen komponentin näyttämisen samassa paikassa. Layoutmanager toimii kuin korttipakka, jossa vain päällimmäinen kortti on kerrallaa näkyvissä.

CardLayout käyttää kahta argumenttia add-metodin kutsussa. Ensimmäinen argumentti on lisättävän komponentin nimi. Komponentti voidaan valita näkyviin joko kutsumalla sitä suoraan nimeltä show-metodilla, käymällä korttipakkaa läpi eteen- tai taaksepäin next ja previous-metodeilla, tai valitsemalla pakan ensimmäinen tai viimeinen kortti first ja last-metodeilla.

5.2.3 FlowLayout


Kuva 8: Esimerkki FlowLayout:in käytöstä

FlowLayout on oletusmanageri kaikille Panel-komponenteille. Se sijoittaa komponentit säiliöön riveittäin vasemmalta oikealle komponenttien lisäysjärjestyksessä.

5.2.4 GridLayout


Kuva 9: Esimerkki GridLayout:in käytöstä

GridLayout jakaa säiliön ristikkoon, jonka kuhunkin soluun voi sijoittaa yhden komponentin. Kaikki solut (ja niiden sisältämät komponentit) ovat saman kokoisia. Ristikon koko täytyy määrittää GridLayout:ia luotaessa. Koon lisäksi voidaan määritellä ristikon solujen väliin jäävä tila. Komponentit lisätään säiliöön vasemmalta oikealle ja ylhäältä alas. Ensimmäinen komponentti sijoitetaan siis vasempaan yläkulmaan.

5.2.5 GridbagLayout


Kuva 10: Esimerkki GridBagLayoutista.

GridBagLayout on monimutkaisin ja monipuolisin kaikista AWT:n mukana tulevista layout managereista. GridBagLayout jakaa säiliön tilan halutun kokoiseen ristikkoon kuten GridLayout., mutta yksittäinen komponentti voi viedä useamman solun tilan joko vaaka- tai pystysuunnassa. Kullekin komponentille voidaan lisäksi antaa painoarvo, joka määrää miten tila jaetaan komponenttien kesken pysty- tai vaakasuunnassa.

GridBagLayout käyttää kahta argumenttia add-metodin kutsussa. Ensimmäinen argumentti on GridBagContext-luokan olio, jonka avulla asetetaan komponentin paikka ja muut siihen liittyvät arvot.

5.2.6 Omien layoutmanagerien ohjelmointi

Myös omien layoutmanagerien ohjelmointi on mahdollista. Tällöin tulee luoda luokka joka toteuttaa LayoutManager-rajapinnan ja kaikki siinä määritellyt metodit. Layoutmanagerien ohjelmointia ei käsitellä tässä tarkemmin.

5.3 Käyttöliittymän toiminta

Javan graafisen käyttöliittymän toiminta perustuu järjestelmän lähettämien viestien sieppaamiseen ja käsittelemiseen. Viestien välitys tapahtuu Event-luokan olioiden avulla. Käyttäjän tehdessä jonkin toiminnan, esimerkiksi painaessa hiiren nappia, Java luo asianmukaisen Event-olion, ja lähettää sen ylös komponenttihierarkiaa. Jokainen komponentti saa mahdollisuuden käsitellä viestin, ennen kuin komponentin vastinkappale (ks. luku 5.1.3) lopulta käsittelee viestin.

5.3.1 Viestit

AWT käyttää viestin välitykseen Event-olioita, jotka sisältävät seuraavat tiedot viestin synnyttäneestä tapahtumasta:

AWT ei saa käsiteltäväkseen jokaista käyttäjän toimintaa, vaan ainoastaan ne mitkä järjestelmä välittää sille. Esimerkiksi Motif ei välitä MOUSE_MOVE-viestiä tekstilaatikoille, joten Java-ohjelma ei pysty reagoimaan siihen.

AWT:n välittämät viestit luetellaan seuraavassa aliluvussa viestinkäsittelymetodien kanssa.

5.3.2 Viestien käsittely

Komponentti voi reagoida viestiin neljällä eri tavalla:

Viestiin reagointi tapahtuu määrittelemällä uudelleen jonkun Component-luokan viestinkäsittelymetodin. Näitä metodeja ovat (viestin tyyppi suluissa):

Kaikki metodit palauttavat boolean-arvon. true ilmaisee metodin käsitelleen viestin kokonaan, eikä sitä enää välitetä eteenpäin. false ilmaisee, että viesti tulisi välittää edelleen.

Erityisen merkillepantavia viestinkäsittelymetodeja ovat action ja handleEvent. HandleEvent on yleinen viestienkäsittelymetodi, jolle välitetään kaikki viestit ja joka (oletusarvona) välittää viestit eteenpäin muille metodeille. handleEvent:in tulisi aina palauttaa super.handleEvent, jotta varmistuisi että viesti tulee käsiteltyä kunnolla.

Vain tietyille komponenteille välitetään action-viesti eli luokkien Button, Checkbox, Choice, List, MenuItem ja TextField olioille. action on korkean tason viesti, joka välitetään komponentille vasta kun järjestelmätason koodi on jo käsitellyt viestin. Sitä käsitellessä ei tarvitse välittää sen synnyttäneistä alemman tason viesteistä, kuten hiiren näppäimen alaspainamisesta, eikä komponentin ulkoasusta. Järjestelmä on hoitanut kaiken tarvittavan siinä vaiheessa kun komponentin action-metodia kutsutaan.

5.4 Kuvien käsittely

Kuvien käsittelyyn tarvittavat luokat on jaettu pakettien java.applet, java.awt ja java.awt.image välillä. Kukin paketti sisältää tuen kuville, niiden lataamiselle muistiin, piirtämiselle ja yksinkertaiselle muokkaukselle. Applettien kuvankäsittelyä tarkastellaan seuraavassa luvussa, tässä luvussa kerrotaan vain AWT:n sisältämästä kuvien käsittelystä

Kuvien käsittelyä varten AWT tarjoaa Image-luokan. Se sisältää viittauksen bittikarttaan, ja se on yleensä aina argumenttina kun kutsutaan jonkin komponentin kuvanpiirto-metodia.

5.4.1 Kuvien lataus

Java tukee suoraan GIF- ja JPEG-kuvaformaattia. Kuvan lataaminen muistiin tapahtuu Toolkit-luokan getImage-metodeilla. Asianmukaisen Toolkit-olion saa joko Toolkit-luokan getDefaulttoolkit-metodilla, tai yksittäisen komponentti-olion getToolkit-metodilla. Kuva voidaan hakea joko tiedostonimen tai URL:n avulla.

	Toolkit toolkit = Toolkit.getDefaultToolkit(); 
	Image image1 = toolkit.getImage("imageFile.gif"); 
	Image image2 = toolkit.getImage(new URL("http://java.sun.com/graphics/people.gif")); 

getImage ei lataa kuvaa heti muistiin, vaan ohjelman suoritus jatkuu välittömästi metodin kutsun jälkeen. Kuvan lataus suoritetaan taustaprosessina. Jos on tarpeen tietää kuvan latauksen vaihe, sitä varten ovat MediaTracker- ja ImageObserver-luokat. Näitä luokkia ei käsitellä tässä yhteydessä tarkemmin.

5.4.2 Kuvan piirto

Kuvan piirto tapahtuu Graphics-olion drawImage-metodilla. drawImage tarvitsee argumenteikseen ainakin Image-olion, joka sisältää piirrettävän kuvan, x ja y-koordinaatit, johon kuva piirretään, sekä olion joka toteuttaa imageObserver-rajapinnan (useimmat komponentit ovat sopivia).

6. Appletit

Appletti tarkoittaa pientä ohjelmaa, joka on istutettu HTML-dokumentin sisään. Tavallisesti Java-kieltä tukeva HTML-selain hakee appletin muistiin samaan aikaan kuin itse HTML-dokumentin, ja suorittaa appletin paikallisessa järjestelmässä.

Applettien toiminta poikkeaa jonkin verran tavallisten Java-ohjelmista. Koska applet ladataan ulkopuolisesta järjestelmästä ja ajetaan paikallisesti, turvallisuus on tärkeä näkökohta. Yleensä WWW-selaimet rajoittavat appletien toimintamahdollisuuksia juuri turvallisuuden takia. Toiseksi, koska appletit ovat osa dokumenttia, niiden koko ja paikka on aina tarkasti määritelty ja niiden täytyy varautua toimimaan rajoitetussa tilassa.

6.1 Appletit ja HTML

Applet lisätään HTML-dokumenttiin applet-koodin avulla. Sen täytyy sisältää ainakin seuraavat parametrit:

Lisäksi applet-koodin sisään voi laittaa codebase-parametrin, joka ilmoittaa missä hakemistossa tai URL:ssä ohjelmakoodi sijaitsee.

Applet-lohkon sisäpuolelle voi laittaa param-koodeja, joiden avulla on mahdollista välittää parametrejä applet:ille. param-koodi sisältää name- ja value-muuttujat, joista ensimmäinen on välitettävän parametrin nimi ja jälkimmäinen sen arvo.

Applet-lohkon sisäpuolelle voi sijoittaa myös vaihtoehtoista HTML-koodia. Appletteja ja Java-kieltä tukeva HTML-selain jättää huomiotta kaiken applet-lohkon sisällä olevan ylimääräisen HTML-koodin (param-koodeja lukuunottamatta), kun taas selain, joka ei tue Java-kieltä jättää applet- ja param-koodit huomiotta, ja näyttää vain vaihtoehtoisen koodin.

Alla esimerkki applet-koodin käytöstä.

<applet code=AppletButton.class codebase=example width=350 height=60 > 
<param name=windowType value=BorderWindow> 
<param name=windowText value="BorderLayout">
<param name=buttonText value="Click here to see a BorderLayout in action">
<blockquote> 
<hr> 
<em> 
	Your browser can't run 1.0 Java applets, so here's a picture of the 
	window the program brings up: 
</em> 
<p> 
<img src=images/BorderEx1.gif width=302 height=138> 
<hr> 
</blockquote> 
</applet> 

6.2 Applettien ohjelmointi

Kaikki appletit luodaan perimällä Applet-luokasta uusia aliluokkia. Applet-luokka on Panel-luokan aliluokka, joten se perii kaikki AWT:n komponenttien ominaisuudet. Kuva 11 näyttää koko Applet-luokan perintähierarkian.


Kuva 11: Applet-luokan perintähierarkia.

Koska Applet-luokka perii Panel-luokan, ei appletin ohjelmointi eroa kovin paljon tavallisen Java-käyttöliittymän ohjelmoinnista. Ainoa ero löytyy appletin toimintaa ohjaavista metodeista. Nämä metodit ovat:

Kaikki appletin vaatimat resurssit on syytä varata init-metodissa, sillä ei ole varmaa että appletin ympäristö olisi täysin toiminnassa konstruktoria kutsuttaessa. Esimerkiksi appletin kuvanlataamismetodit eivät toimi vielä konstruktorin suorituksen aikana.

Muita tärkeitä Applet-luokan metodeja ovat:

6.3 Applettien turvallisuus

Applettien turvallisuus on eräs tärkeimmistä Java-kielen suunnittelun lähtökohdista. Jos tuntemattomalta WWW-sivulta ladattu appletti pystyisi aiheuttamaan minkäänlaista tuhoa, aplettien hyödyllisyys olisi vähintäänkin kyseenalaista. Ongelman välttämiseksi selaimet asettavat appleteille yleensä seuraavat rajoitukset:

Ylläolevat rajoitukset koskevat vain niitä appletteja, jotka luetaan ulkopuoliselta koneelta. Paikallisesta tiedostojärjestelmästä käynnistetyllä appletilla ei ole mitään rajoituksia.

Yläolevasta listasta voi päätellä että virusappletin tekeminen on varsin vaikeaa. Koska rajoitukset eivät koske paikallisia appletteja, troijan hevosen tai loogisen pommin tekeminen on mahdollista. Toisaalta, applet voi avata verkkoyhteyden systeemiin josta se ladattiin muistiin ja kirjoittaa tietoja kyseisen systeemin tiedostoihin. Client-server tyyppinen ohjelma, joka hämää käyttäjän paljastamaan tietoja itsestään ja tallettaa saadut tiedot emosysteemin tiedostoihin, on siten mahdollinen.

Appletien toimintarajoitukset toteutetaan nk. turvallisuusmanagerien avulla. Turvallisuusmanageri on systeemikohtainen olio, joka havaitessaan laittoman operaation pysäyttää sen ja lähettää SecurityException-poikkeutuksen. Yleensä Java-kieltä tukevat HTML-selaimet käyttävät omaa turvallisuusmanageria, joten appletien toiminnoille asetetut rajoitukset saattavat vaihdella eri selaimissa.

7. Lähteet

[GOS]    James Gosling, Bill Joy ja Guy Steele, "The Java Language       
         Specification",                                                 
         http://java.sun.com/doc/language_specification/, Sun            
         Microsystems                                                    

[CAM]    Mary Campione ja Kathy Walrath, "The Java Tutorial",            
         http://java.sun.com/doc/tutorial.html, Sun Microsystems         

[HAR]    Elliotte Rusty Harold, "Comp.lang.java FAQ",                    
         http://sunsite.unc.edu/javafaq/javafaq.html                     

[CON]    Michael O'Connell, "Java: the Inside Story",                    
         http://www.sun.com/sunworldonline/swol-07-1995/swol-07-Java.htm 
         l, Web Publishing Inc                                           

[MEY]    Scott Meyers, "More Effective C++", Addison-Wesley Publishing   
         Company                                                         

[ITK]    Jonne Itkonen, "Inferno ja JavaOS", ohjelmistotekniikan         
         seminaari 1996                                                  

[NUR]    Terhi Nurminen, "Virukset" , ohjelmistotekniikan seminaari      
         1996                                                            

Sun, Sun Microsystems, HotJava, and Java are trademarks or registered trademarks of Sun Microsystems, Inc.

Kiitokset Jukka-Pekka Santaselle, Jonne Itkoselle ja Kai Parviaiselle opastuksesta ja avunannosta.

8. Hyödyllisiä linkkejä ja muita resursseja

9. Pieni esimerkkiappletti

Seuraava appletti laskee kahden kokonaisluvun suurimman yhteisen tekijän arvon.


Kuva 12. Esimerkkiappletti

SytApplet.Java:

import Java.awt.*;
import Java.applet.*;
/**************************************************
*
*  SytCalc
*
*  Kahden luvun suurimman yhteisen tekijän (syt)
*  laskemiseen tarkoitettu luokka. Syt:in laskeminen
*  tapahtuu Euklideen algoritmilla.
*/
class SytCalc { 
   static long syt(long number1, long number2) {
      long r = number1 % number2;  
      if (r==0) return number2;  
      else return syt(number2,r); 
   }
}

/***************************************************
*
*  SytApplet
*
*  Käyttöliittymä syt:in laskemiselle.
*/

public class SytApplet extends Applet {
   Button laske; // Laske-painonappi
   Button reset; // Nollaa-painonappi 
   Label tulos; // Tuloskenttä
   TextField luku1; // luvun syöttökenttä 
   TextField luku2; //   "         " 
   Panel buttonpanel; // paneli jolla ryhmitetään
                      //painonapit ja syöttökentät
   final String T = new String("Suurin yhteinen tekijä on:"); 
   public synchronized void init() {  
      // Otetaan BorderLayout käyttöön  
      setLayout(new BorderLayout());    

      // Luodaan oliot käyttöliittymän  
      // komponenteille
      laske = new Button("Laske");  
      reset = new Button("Nollaa");
      tulos = new Label();  
      tulos.setAlignment(Label.CENTER);  
      luku1 = new TextField(9);  
      luku2 = new TextField(9);  
      buttonpanel = new Panel();  

      // Lisätään komponentit paneliin
      buttonpanel.add(luku1);  
      buttonpanel.add(luku2);  
      buttonpanel.add(laske);
      buttonpanel.add(reset);  

      // Sijoitetaan ryhmittelypaneli alalaitaan
      // ja tuloskenttä keskelle  
      add("South",buttonpanel);
      add("Center",tulos); 
   } 

   public boolean action(Event e, Object arg) {
      if(e.target == reset) {    
         tulos.setText("");
         luku1.setText("");   
         luku2.setText("");
      } else {   
         String S1 = luku1.getText();   
         String S2 = luku2.getText();
         long Num1,Num2;     

         // Seuraava lohko koettaa muuttaa merkkijonon
         // long:iksi. Jos merkkijono sisältää ei-numeerisia
         // merkkejä, napataan lähetetty poikkeutus,   
         // ja annetaan käyttäjälle virheilmoitus   
            try {
               Num1 = Long.valueOf(S1).longValue();    
               Num2 = Long.valueOf(S2).longValue();
            } catch (NumberFormatException T) {    
               tulos.setText("Ole hyvä ja syötä numeerinen arvo");  
               return true;   
            }   

          // Lasketaan suurin yhteinen tekijä 
          // ja näytetään tulos tuloskentässä.
          long L = SytCalc.syt(Num1,Num2);   
          tulos.setText(T+Long.toString(L));
       }  
                
       // palautetaan tosi, eli AWT saa käsitellä   
       // viestin loppuun saakka  
       return true; 
    }
}