750 likes | 896 Views
SWING. JAVADOC. UML-KAAVIOT. SÄIKEET JA SWING. 2D-GRAFIIKKA. SOVELMAT. TIETOVIRRAT. JAVA-API. PAKKAUKSET. POLYMORFISMI. SILMUKAT. MERKKIJONOT. TAULUKOT. MUUTTUJAT. SUUNNITTELUSTA. POIKKEUKSET. Informaatioverkostot: Studio 1 Luentomateriaali. 5 11 17 23. 40 45 50 60.
E N D
SWING JAVADOC UML-KAAVIOT SÄIKEET JA SWING 2D-GRAFIIKKA SOVELMAT TIETOVIRRAT JAVA-API PAKKAUKSET POLYMORFISMI SILMUKAT MERKKIJONOT TAULUKOT MUUTTUJAT SUUNNITTELUSTA POIKKEUKSET Informaatioverkostot: Studio 1Luentomateriaali 5 11 17 23 40 45 50 60 Janne Käki 2006 28 33 35 37 63 64 66 70
Muutama perusasia • Tietokone tekee juuri (ja vain) sen, mitä käsketään. • Tietokone ymmärtää vain syntaksia (sanojen kirjoitusasua), ei semantiikkaa (sanojen merkitystä). • Muuttujat ja metodit voi tietokoneen puolesta nimetä (melkein) ”ihan miten vaan”, olennaista on vain, että samasta muuttujasta tai metodista käytetään johdonmukaisesti samaa nimeä. • Java-kielessä on kuitenkin joitakin kymmeniä avainsanoja (public, private, int, void, true, null, return, . . .), jotka on varattu tiettyyn käyttöön. Näitä ei siis voi valita muuttujien nimiksi. • Se, että muuttujat ja metodit nimetään fiksusti ja käyttötarkoitusta kuvaavasti, on tärkeää nimenomaan (ja vain) koodia lukevan ihmisen kannalta. • Ohjelman suoritus on normaalisti (virheettömänä) täysin näkymätöntä. • Siksi tarvitaan tulostuksia, jotta saisimme käsityksen siitä, mitä ohjelmassa tapahtuu – mitä paremmat tulostukset, sitä parempi käsitys.
Sijoituslause sijoitusoperaattori (ei yhtäsuuruusmerkki!) int luku = (5 + 4) * 8 - 7; laskuri = laskuri + 1; 1. Selvitetään oikeanpuoleisen lausekkeen arvo. 2. Määritellään uusi kokonaislukutyyppinen muuttuja nimeltä luku. 3. Sijoitetaan kohdassa 1 laskettu arvo kohdassa 2 määriteltyyn muuttujaan. 1. Lasketaan yhteen laskurin nykyinen arvo ja yksi. 2. Sijoitetaan tämä arvo laskurin uudeksi arvoksi. (Koska laskurimuuttuja on jo entuudestaan olemassa, sitä ei siis ole syytä määritellä uudelleen, joten emme käytä sanaa int.)
Palauttaminen vs. tulostaminen Metodi, joka palauttaa tekstin ”böö”: public String palautaBöö() { return ”böö”; } Metodi, joka tulostaa tekstin ”böö”: public void tulostaBöö() { System.out.println(”böö”); } paluuarvon tyyppi ”ei palauta mitään” antaa palautettavan arvon käyttöön sille, joka metodia kutsui tuottaa tekstin näytölle String bööTeksti = palautaBöö(); System.out.println(bööTeksti); böö
MUUTTUJAT Tiedon abstraktiotasoja kokoelmatnimetty joukko olioita oliotnimetty joukko muuttujia (ja operaatioita) Javan fokus muuttujatnimetty tietyntyyppisen tiedon muistipaikka muistipaikatjoukko bittejä, joilla on yksi osoite bititnollia tai ykkösiä
MUUTTUJAT Erilaisia muuttujia public class Mursu { private String nimi; private int nopeus; public Mursu(String nimi, int nopeus) { this.nimi = nimi; this.nopeus = nopeus; } public double liiku(double aika) { double matka = aika * this.nopeus; System.out.println(nimi + ” lyllersi ” + matka + ” km.”); return matka; } }
MUUTTUJAT Muuttujista • Muuttujan määrittely (eli esittely): nimetään tietolokero ja kerrotaan, minkä tyyppistä tietoa se voi sisältää. • String brutaaliSolvaus; • int vihreidenPingviinienLukumaara; • Muuttujan alustus: sijoitetaan muuttujaan (sen historian ensimmäinen) arvo. • brutaaliSolvaus = ”hähä mogari”; • Voidaan tehdä myös suoraan määrittelyn yhteydessä:String brutaalimpiSolvaus = ”luetaan sitä API:a”; • Muuttujan arvon lukeminen: käytetään muuttujaa missä tahansa muualla kuin sijoituslauseen vasemmalla puolella. • System.out.println(brutaalimpiSolvaus); • if (vihreidenPingviinienLukumaara > 1) { • Ei saa tehdä alustamattomalle muuttujalle, muuten kääntäjää alkaa pelottaa. (”Variable might not have been initialized.”) • Attribuuteilla on aina tietty alkuarvo automaattisesti (numeromuuttujilla nolla, booleaneilla false, oliomuuttujilla null), joten niiden alustaminen ei ole välttämätöntä ennen muuttujan käyttämistä – yleensä toki suositeltavaa.
MUUTTUJAT Tietotyypeistä olioita
MUUTTUJAT Viittaustyyppiset muuttujat • Olio on kuin ilmapallo. • Oliomuuttujat ovat viittauksia – kuin naruja, joiden päässä se ilmapallo on. • Sama olioilmapallo voi olla useamman narun päässä. Siihen voidaan vaikuttaa (eli sen metodeita kutsua) kaikkia naruja pitkin, ja kaikki kutsut muokkaavat yhtä ja samaa oliota. • Kun oliomuuttuja lakkaa olemasta tai saa uuden arvon, yksi naru katkeaa. • Kun olio ei ole enää yhdenkään narun päässä kiinni, se karkaa stratosfääriin (eli Javan automaattinen roskienkerääjä tulee ja syö sen).
SILMUKAT Klassinen for-lause for (int i = 0; i < 3; i++) { ... } ei onkoehtotosi? for-lauseen jälkeinen elämä alustus-lause suoritettavatlauseet kyllä kasvatus-lause
SILMUKAT Tällainen for-lause... for (int i = 0; i < 3; i++) { ... } ...vastaa while-lauseella toteutettua rakennetta { int i = 0; while (i < 3) { ... i++; } } Mikä merkityson ulommillaaaltosuluilla?
SILMUKAT Iteroiva for-lause public void tulostaNimet(Set<Olento> olennot) { for (Olento o : olennot) { System.out.println(o.annaNimi()); } } • Käy läpi kaikki tiettyyn kokoelmaan sisältyvät oliot. • Kukin kokoelman olio sijoitetaan siis vuorollaan for-lauseen määrittelemään muuttujaan ja siihen sovelletaan aaltosulkujen sisällä olevia lauseita. • Läpikäyntijärjestys riippuu kokoelmasta. Listoilla se on määrätty, joukoilla (Set) yleensä määrittelemätön, mutta ei kuitenkaan aidosti satunnainen. • Kokoelman sisältöä ei saa muuttaa (lisätä tai poistaa olioita) kesken iteroinnin, muuten seuraa virhe nimeltä ConcurrentModificationException.
SILMUKAT public void tulostaNimet(Set<Olento> olennot) { String nimet = ””; for (Olento o : olennot) { nimet += o.annaNimi() + ”, ”; } System.out.println(nimet); } Miten pääsemme eroon ylimääräisestä pilkusta? Arska, Pena, Mats, Rauski, Tulostaa: public void tulostaNimet(Set<Olento> olennot) { String nimet = ””; int otuslaskuri = 0; for (Olento o : olennot) { nimet += o.annaNimi(); if (otuslaskuri < olennot.size()-1) { nimet += ”, ”; } otuslaskuri++; } System.out.println(nimet); }
SILMUKAT Iteraattori Vanha tuttu iteroiva for-looppi... Kokoelman on toteutettava rajapintaIterable<T>, joka määrittelee metodin public Iterator<T> iterator(). for (Olio o : kokoelma) { System.out.println(o); } ...toimii pinnan alla itse asiassa iteraattoriolion avulla.Sama looppi hieman toisin kirjoitettuna: Iterator<Olio> iter = kokoelma.iterator(); while (iter.hasNext()) { Olio o = iter.next(); System.out.println(o); } Myös Iterator<T> on itse asiassa rajapinta.Iteraattorin metodi next() palauttaa ja poistaa – iteraattorista, ei iteroitavastakokoelmasta – järjestyksessä seuraavanelementin. Metodi hasNext() kertoo,vieläkö elementtejä on jäljellä.
SILMUKAT Iteraattori • Iteroimisessa on vaaransa. Metodi next() voi heittää poikkeuksia... • NoSuchElementException, jos elementtejä ei enää ole. Vältettävissä huolellisella hasNext()-metodin käytöllä. • ConcurrentModificationException, jos iteroitava kokoelma on muuttunut iteraattorin luomisen jälkeen. Uusia elementtejä ei siis voi kesken iteroinnin lisätä, ellei iterointia tämän jälkeen keskeytä.Elementtien poistaminen on luvallista iteroinnin lomassa vain iteraattori-olion metodilla remove(), joka poistaa viimeisimmän next()-metodin palauttaman elementin, myös iteroitavasta kokoelmasta. • Iteraattori siis antaa luvan myös elementtien poistamiseen kokoelmasta (periaatteessa – oma iteraattoriluokka voidaan kuitenkin toteuttaa myös niin, ettei remove()-metodi tee mitään). Aina ulkopuoliselle käyttäjälle ei haluta jättää tällaista mahdollisuutta, jolloin voi olla syytä harkita toisenlaisen rajapinnan tarjoamista kokoelman läpikäyntiin.
TAULUKOT Taulukko Taulukkomuuttujan määrittely ja alustaminen ns. taulukon alustajalla: int[] taulu = { 9, 14, 2, 7, 2, 0, 22 }; Taulukon indeksointi ja sen alkioiden arvojen asettaminen: taulu[0] = 1;taulu[2] = 100;taulu[taulu.length-1] = 8; Uuden, tyhjän taulukon luonti new-operaattorilla: taulu = new int[5]; Taulukotkin ovat olioita. Huomaa, että taulukon koko on taulukko-olion, ei taulukkomuuttujan ominaisuus. (Samaan muuttujaan voi sijoittaa minkä kokoisen taulukon tahansa.) Taulukon tietotyyppi on sen sijaan myös taulukkomuuttujan ominaisuus.
TAULUKOT Laskurilla varustettu for-silmukka on kuin luotu taulukon läpikäymiseen, esimerkiksi seuraavassa fiktiivisessä Olento-luokan metodissa: public void kauhistuHirviolaumaa(Olento[] hirviot) { for (int i = 0; i < hirviot.length; i++) { hirviot[i].pelottele(this); } } this viittaaaina siihen olioon, jonkametodista on kyse.Sitä voi käyttää myössellaisenaan, esimerkiksiparametrina jollekintoiselle metodille. Muista, ettätaulukon indeksitalkavat nollasta japäättyvät yhtäpienempään kuintaulukon koko. hirviot[i] viittaavuorollaan aina yhteentaulukon alkioon,siis Olento-tyyppiseenolioon (ellei kyseinenalkio ole null).
TAULUKOT Variable tauluA might not have been initialized. java.lang.NullPointerException java.lang.ArrayIndexOutOfBoundsException Possible loss of precision. Found: double. Required: int. Incompatible types. Found: double[ ]. Required: int[ ]. Variable tauluA might not have been initialized. java.lang.NullPointerException Jos määrittelemme seuraavasti int[] tauluA; int[] tauluB = null; int[] tauluC = new int[5]; Pelotteluesine[] tauluD = new Pelotteluesine[1000]; ja sen jälkeen yritämme seuraavia asioita, mikään niistä ei onnistu. Miksi? tauluA[0] = 49; tauluB[0] = 88; tauluC[5] = 31; tauluC[2] = 4.86; tauluA = new double[10]; tauluB = tauluA; tauluD[666].annaPelottavuus(); Inspired by: http://www.cs.helsinki.fi/u/wikla/Ohjelmointi/Sisalto/3/Taulukot.html#2
TAULUKOT Kaksiulotteinen taulukkoeli taulukoita taulukossa Luodaan 2D-taulukko eli matriisi, jossa on neljä riviä ja viisi saraketta: Olento[][] otusruudukko = new Olento[4][5]; otusruudukko[2][1] = new Olento(”Rauski”, 100); Itse asiassa loimme yhden nelipaikkaisen taulukon, jonka alkioiden tietotyyppi on Olento[]. Se sisältää siis neljä yksiulotteista, viisipaikkaista olentotaulukkoa. Nämä taulukot ovat aluksi tyhjiä, eli niiden jokainen alkio on null. Voimme sijoittaa ruudukkoon uusia arvoja kertomalla, mihin alitaulukkoon ja mihin lokeroon siellä kyseinen arvo sijoitetaan:
TAULUKOT 2D-taulukon rivien ei välttämättä tarvitse olla samanpituisia – jokainen alitaulukkohan on yksilöllinen olio, jonka pituus voi olla mitä vain: Olento[][] otusruudukko = new Olento[4][]; Huomaa tyhjät jälkimmäiset hakasulut. Tässä luotiin tyhjä nelipaikkainen taulukko, johon voi sijoittaaOlento[]-taulukoita. Näitä alitaulukkoja ei kuitenkaan vielä ole olemassa, ne on luotava nyt erikseen. otusruudukko[0] = new Olento[5]; otusruudukko[1] = new Olento[3]; otusruudukko[2] = new Olento[1]; otusruudukko[3] = new Olento[4]; otusruudukko[3][3] = new Olento(”Rauski”, 100);
TAULUKOT for-lauseita voi käyttää myös sisäkkäin. Kaksiulotteisen taulukon läpikäynnissä tämä on usein tarpeen: String[][] ruudut = new String[5][5]; for (int i = 0; i < ruudut.length; i++) { for (int j = 0; j < ruudut[i].length; j++) { ruudut[i][j] = i + ”, ” + j; } }
MERKKIJONOT Merkkijonojen vertailu String a = "kaikki on mahdollista"; String b = "kaikki on mahdollista"; System.out.println(a == b); b = new String("kaikki on mahdollista"); System.out.println(a == b); System.out.println(a.equals(b)); System.out.println(a == b.intern()); true false true true Esimerkit: Ville Sundberg
MERKKIJONOT EI NÄIN if (nimi == ”Rauski”) { VAAN NÄIN if (nimi.equals(”Rauski”)) { TAI JOS KIRJAIN-KOOLLA EI OLE MERKITYSTÄ if (nimi.equalsIgnoreCase(”RAUSKI”)) {
MERKKIJONOT Merkkijonon paloittelu String lause = ”Kivet on tosi jänniä.”; String[] sanat = lause.split(” ”);
MERKKIJONOT Merkkijonon tulkinta luvuksi Integer.parseInt(String merkkijono) • Integer-luokan staattinen metodi • yrittää tulkita merkkijonon kokonaisluvuksi • heittää poikkeuksen NumberFormatException, jos merkkijono ei esitä puhdasta kokonaislukua (varauduttava aina tähän mahdollisuuteen) Double.parseDouble(String merkkijono) • Double-luokan staattinen metodi, muuten sama kuin yllä mutta tulkitsee merkkijonoja desimaaliluvuiksi (desimaali-erottimena oletusarvoisesti piste)
MERKKIJONOT String-luokassa lisäksi mm. metodit: • String substring(int alku, int loppu) • palauttaa osamerkkijonon väliltä alku … loppu-1 • int indexOf(String osamerkkijono) • palauttaa indeksin, josta etsittävä osamerkkijono (ensimmäinen löytynyt) alkaa • jos osamerkkijonoa ei löydy, palauttaa arvon –1 • String trim() • palauttaa merkkijonon kopion, jonka alusta ja lopusta on poistettu mahdolliset välilyönnit • String toLowerCase() • palauttaa merkkijonon kopion, jonka kaikki ISOT KIRJAIMET on muutettu pieniksi kirjaimiksi (toUpperCase() tekee saman toisinpäin) • String toString() • :D Luokka String on arvo-keskeinen: String-olion metodit eivät muuta kysei-sen olion tilaa mitenkään. Jos metodi tekee muutoksia, se palauttaa kopion alku-peräisestä – uuden olion.
POLYMORFISMI Halutaan luoda uusi Pelotteluesine... Kun luodaan uutta Pelotteluesinettä, on sille ensin rakennettava yläluokkien määrittelemä perusta – alustettava ne ominaisuudet, jotka sille kuuluvat 1) Objectina ja 2) Esineenä. public Pelotteluesine(String nimi, double paino, int pelottavuus) { super(nimi, paino); this.pelottavuus = pelottavuus; } public Esine(String nimi, double paino) { super(); this.nimi = nimi; this.paino = paino; } public Object() { ... } ...mutta ennen pelotteluesineen oman pelottavuus-ominaisuuden alustusta on varmistettava, että perustana on oikeaoppinen Esine. Siksi ihan aluksi kutsutaan Esine-luokan luontimetodia... Pelotteluesine private int pelottavuus public Pelotteluesine(String nimi,double paino, int pelottavuus) Esine private String nimiprivate double paino public Esine(String nimi, double paino) ...jonka aluksi puolestaan kutsutaan vielä Object-luokan konstruktoria. (Tässä super();ia ei olisi pakko kirjoittaa, koska nyt yläluokan luontimetodille ei tarvitse antaa parametreja. Esineelle sen sijaan täytyi.) ominaisuuksien määrä Object public Object()
POLYMORFISMI Metodin kuormittaminen(overloading) • Samannimisestä metodista on määritelty samassa luokassa (tai samassa yli- ja aliluokkien jatkumossa) useita versioita, joista valitaan suoritettavaksi yksi sen perusteella, mitä parametreja metodikutsussa on annettu. • Metodikutsu sidotaan suoritettavaan metodiin metodin nimen sekä parametrien tyyppien ja järjestyksen perusteella. (Sen sijaan esimerkiksi parametrimuuttujien nimillä ei ole mitään merkitystä.Ei myöskään sillä, minkä tyyppisiä arvoja metodin eri versiot palauttavat.) • Metodikutsujen on oltava yksiselitteisiä, eli ei saa olla epäselvää, mikä vaihtoehtoisista tietynnimisen metodin versioista nyt suoritetaan: public void metodi(Object o, String s) { ...} public void metodi(String s, Object o) { ...} metodi(”nuuh”, ”nuuh”); metodi(”nuuh”, (Object) ”nuuh”);
POLYMORFISMI Metodin korvaaminen(overriding) • Aliluokka määrittelee yliluokassa määritellyn metodin toteutuksen kokonaan uudelleen. Korvaavan metodin puumerkki on täsmälleen sama kuin alkuperäisen, eli metodeilla on sama nimi, samanlainen parametrilista (tyypit ja järjestys) ja sama paluuarvon tyyppi. • Voidaan merkitä aliluokkaan kirjoittamalla metodin yläpuolelle erityinen @Override-tägi. Ei pakollista, mutta parantaa luettavuutta. • Metodin uusi versio EI saa • muuttaa paluuarvon tyyppiä, • rajata näkyvyyttä alkuperäistä suppeammaksi (laajentaa sen sijaan saa), • heittää sellaisia poikkeuksia joita alkuperäinen ei määritellyt heittävänsä (sen sijaan uusi versio voi mainiosti olla heittämättä joitakin poikkeuksia joita alkuperäinen metodi heitti). • Kun luokan A metodi x() on korvattu aliluokassa B metodilla x(), niin alkuperäistä metodia voi kutsua luokan B oliolle vain olio itse notaatiolla super.x(). Muut kutsut johtavat aina luokassa B määritellyn metodin suorittamiseen.
POLYMORFISMI Metodien staattinen ja dynaaminen sidonta Otus eka = new Otus(); Otus toka = new PäheäOtus(); PäheäOtus kolmas = new PäheäOtus(); Olkoon PäheäOtus luokan Otus aliluokka. Otus-luokassa on määritelty tylsä metodi eksistoi(), jonka PäheäOtus on korvannut uudella päheämmällä versiolla. Lisäksi PäheäOtus-luokassa on täysin uusi, ennen näkemätön metodi kelaaSunLaatuas(). PäheälleOtukselle, joka on sijoitettu Otus-tyyppiseen muuttujaan, voidaan kutsua ainoastaan Otus-luokan metodeja. Sanotaan, että kyseisen olion staattinen tyyppi on Otus. Vaikka olio siis osaisi myös kelata laatuaan, sitä ei voi tuon muuttujan kautta käskeä niin tekemään. Sopivalla tyyppimuunnoksella staattinen tyyppi voidaan kuitenkin saattaa sellaiseksi, että tuokin metodi on käytössä. Sen sijaan muuttujan staattinen tyyppi Otus antaa toki meille luvan kutsua oliollemme metodia eksistoi(). Tällöin metodikutsu sidotaan kuitenkin aina olion todelliseen, dynaamiseen tyyppiin, joka tässä tapauksessa on PäheäOtus. Hämmästykseksemme tylsässä Otus-laatikossa piileksinyt olio alkaakin siis eksistoida hyvin päheästi, kun käskytämme sitä tuollaisella metodikutsulla. Mitenkään emme pysty käskemään tuota oliota käyttäytymään siten kuin puhdas Otus käyttäytyisi, ellei se sitten itse päätä suorittaa tuota metodia kutsulla super.eksistoi(). Staattinen tyyppi siis sanelee sen, mitkä metodikutsut muuttujaan sijoitetulle oliolle ovat ylipäänsä luvallisia. Dynaaminen tyyppi (joka ei olion elinaikana muutu) taas määrää, mitä koodia oliolle tehtyjen metodikutsujen seurauksena todella suoritetaan. :) :D eka toka :D kolmas
POLYMORFISMI Rajapinnat Rajapinta eli liittymä (engl. interface) on luokka, joka määrittelee ”olion käyttöliittymän” (tai jonkin osa-alueen siitä). Rajapinta toisin sanoen määrittelee yhden tai useamman metodin, jotka tarjoavat tietyn toiminnallisuuden. Ja tarkemmin sanoen se vain määrittelee nämä metodit, ei toteuta niitä (eikä ota kantaa siihen, millaisten teknisten yksityiskohtien avulla niiden toiminnallisuus toteutetaan). Rajapinta on toisin sanoen kuin abstrakti luokka, joka sisältää vain abstrakteja metodeja (siis metodeja ilman toteutusta, eli tavallaan vaatimuksia aliluokille tietynlaisten metodien toteuttamisesta). Mutta siinä missä Java-luokalla voi olla aina vain yksi suoranainen yläluokka (abstrakti tai ei), voi sama luokka toteuttaa yhden, kaksi, kolme tai miljoona rajapintaa. Toteuttaminen tarkoittaa sitä, että luokkaan on laadittu käytännön toteutus kaikille näissä rajapinnoissa määritellyille metodeille ja lisäksi toteuttami-sesta on kerrottu avainsanan implements avulla. 1. Rajapintaluokka määrittelee tietyn toiminnallisuuden. 2. Konkreettiset luokat toteuttavat rajapinnan, kukin omalla tavallaan. 3. Toinen luokka voi käyttää kaikkia näitä luokkia ”rajapinnan edustajina”, yhteisten ominaisuuksien pohjalta.
POIKKEUKSET Poikkeukset Tähän asti olemme tottuneet siihen, että metodin paluuarvo (true tai false, olio tai null) riittää kertomaan, onnistuiko metodi tehtävässään vai ei. Mutta millainen paluuarvo pystyisi ilmaisemaan, että jäimme kiinni varastaessamme päärynää? Javan poikkeukset (engl. exceptions) ovat ikään kuin vaihtoehtoja metodien normaaleille paluuarvoille. Tyypillisesti ne kertovat, että metodissa tapahtui odottamaton virhe. Poikkeusten yhteydessä ei puhuta palauttamisesta, vaan ”heittämisestä”. public Paaryna varastaPaaryna() throws KaameaPoikkeus { if (vartija.onVahdissa() && !vartija.nukkuu()) { KaameaPoikkeus poikkeus = new KaameaPoikkeus("Kiinni jäit, hähä!"); throw poikkeus; } else { return paarynapuu.annaPaaryna(); } } public void eleleVaarallistaElamaa() { try { // VOI HEITTÄÄ POIKKEUKSEN: Paaryna saalis = this.varastaPaaryna(); this.syo(saalis); } catch (KaameaPoikkeus poikkeus) { System.out.println(poikkeus); this.karsiRangaistus(); } finally { this.jatkaElamaaEntiseenTapaan(); } } Monet Javan valmiit poikkeukset (ja tyypillisesti kaikki itse laaditut) täytyy käsitellä. Toisin sanoen jos on olemassa vaara (todellinen tai edes teoreettinen), että tietyn metodin kutsusta aiheutuu poikkeus, tämän poikkeuksen mahdollisuuteen tulee varautua ns. try-catch-rakenteen avulla. Try-osioon sijoitetaan se metodikutsu, josta potentiaalisesti voi aiheutua poikkeus, sekä kaikki se mitä onnistuneesta yrityksestä suoraan seuraa. Catch-osiossa puolestaan yleensä reagoidaan jollain tapaa yrityksen epäonnistumiseen. Finally-osio ei ole pakollinen. Se suoritetaan sekä onnistuneen että epäonnistuneen kokeilun lopuksi.
POIKKEUKSET Exception Error Erilaisia poikkeusluokkia RuntimeException ...näitä ei tarvitse käsitellä. Tarvitsee käsitellä, paitsi... Throwable Kaikkien poikkeus-luokkien yläluokka. (Nimestään huolimatta ei siis rajapinta.) Ei tarvitse käsitellä.
java.lang pari aivan keskeistä luokkaa, kuten Object, String ja Math alkeistyyppien kääreluokat (Integer, Double, Boolean, Character, ...) useimmat poikkeus- (Exception) ja virheluokat (Error) aina käytössä, ei tarvitse importoida! java.util kokoelmarajapinnat (Collection, Set, List, Map) ja niiden toteutukset (HashSet, Vector, ArrayList, HashMap, ...) kirjastoluokat Arrays ja Collections välineitä päiväysten ja kellonaikojen käsittelyyn: Date, Calendar, TimeZone pari muuta hyödyllistä: Random, Timer, Scanner java.io välineet näppäimistön ja tiedostojen lukemiseen (erilaiset InputStream- ja Reader-luokat) sekä näytölle ja tiedostoon kirjoittamiseen (OutputStream- ja Writer-luokat) java.net välineet verkkoyhteyksien muodostamiseen java.awt AWT-luokkakirjasto (Abstract Windowing Toolkit), Javan vanhempi kalusto graafisten käyttöliittymien toteutukseen javax.swing Swing-luokkakirjasto, uudemmat välineet graafisten käyttöliittymien tekemiseen JAVA-API Keskeisimmät Java-API:n pakkaukset API = Application Programming Interface eli sovellusohjelmointirajapinta (!) pakkaus (engl. package) = tapa koota samaan asiaan liittyviä luokkia yhteen
JAVA-API Luetaan sitä API:a!Mutta miten? Java-ohjelmoinnissa monien ongelmien ratkaisu käy seuraavaan tapaan: • Etsi API:sta oikea luokka haluamasi asian tekemiseen. • Etsi luokasta metodi, jolla sen saa tekemään tuon asian. • Selvitä, miten kyseistä metodia käytetään. API:n lukemisessa on kuitenkin muutama sudenkuoppa, joita kannattaa varoa: • Varmista, että olet tekemisissä oikean luokan kanssa (tsekkaa myös, missä pakkauksessa se on). Esimerkiksi java.util.List ja java.awt.List ovat kaksi täysin erilaista luokkaa, jotka menevät helposti sekaisin. • Katso, mistä tutkimasi luokka periytyy. Yläluokista voi päätellä paljon siitä, mitä luokka osaa omien metodiensa lisäksi tehdä. Luokan omassa Method Summary -listassa ei mainita yläluokilta perittyjä metodeja, mutta luokalla on luonnollisesti myös ne käytettävissään. (Ne luetellaan lyhyesti tuon listan alapuolella.) • Joistakin metodeista on tarjolla useampi kuormitettu (engl. overloaded) versio, eli samanniminen metodi erilaisilla parametrivaihtoehdoilla. Osa näistä on suora-viivaisempia käyttää, toiset tarjoavat mahdollisuuden hyvinkin monimutkaisiin säätöihin. Valitse oikea metodi tarpeesi mukaan, säästyt turhalta säätämiseltä. :)
TIETOVIRRAT Tietovirrat
TIETOVIRRAT InputStream (System.in) näppäimistö BufferedReader InputStreamReader Näppäimistön lukeminen tavut 11101011 merkit 01001110 b r merkkijonot ö m mene avantoon katso olentoa 4
TIETOVIRRAT BufferedReader lukija = new BufferedReader( new InputStreamReader(System.in)); BufferedReader InputStreamReader InputStream (System.in) IOException (tietovirtahepo) vaanii kaikissa tietovirroissa
SWING Graafisen Java-ohjelman osat top level
SWING käyttäjä tekee jotain… Tapahtuma Tapahtuman-käsittelysäie(event dispatching thread) tapahtumaanreagointi(”ohjelmatekee jotain”) Työläissäie(worker thread) ohjelman sulkeminen Tapahtumapohjainen ohjelmointi ohjelman käynnistys käyttöliittymän alustus Tapahtuman kuuntelija(t) tapahtuman odottelu…
SWING GridBagConstraints anchor:komponentin sijainti solunsisällä (CENTER, NORTH,EAST, SOUTHWEST, jne.) GridBagConstraints c = new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 2, 5, 2), 0, 0); gridx ja gridy:komponentin sijainti-koordinaatit ”gridissä”(vasemmalta ylhäältä luettuna) fill:kuinka komponentti täyttääsolunsa (HORIZONTAL,VERTICAL, BOTH tai NONE) gridwidth ja gridheight:komponentin leveys ja korkeus(riveissä ja sarakkeissa) insets:montako pikseliätyhjää tilaakomponentinympärille jätetään(ylös, vasemmalle,alas, oikealle) ipadx ja ipady:paljonko tyhjää reunusta(”paddingia”) kompo-nentin sisään jätetäänsen minimikoossa weightx ja weighty:komponentin suhteellinenpainoarvo (0.0–1.0)säiliötä täytettäessä
SWING GridBagLayout JPanel paneeli = new JPanel( new GridBagLayout()); JTextField kenttä = new JTextField(); GridBagConstraints c = new GridBagConstraints( 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(5, 2, 5, 2), 0, 0); paneeli.add(kenttä, c); • Luodaan paneeli. • Asetetaan paneelin asettelijaksi uusi GridBagLayout. • Luodaan käyttöliittymä-komponentti. • Luodaan GridBagConstraints-olio, jolle asetetaan sopivat attribuuttien arvot. • Lisätään komponentti paneeliin GridBagConstraints:ia käyttäen. • Palataan tarvittaessa kohtaan 3.
SWING GridBagLayout, toinen tapa JPanel paneeli = new JPanel( new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); JTextField kenttä = new JTextField(); c.gridx = 0;c.gridy = 0;c.anchor = GridBagConstraints.SOUTH;c.insets = new Insets(5, 2, 5, 2); paneeli.add(kenttä, c); JButton namiska = new JButton(”pl”); c.gridy = 1; paneeli.add(namiska, c); • Luodaan paneeli. • Asetetaan paneelin asettelijaksi uusi GridBagLayout. • Luodaan GridBagConstraints-olio oletusarvoisilla attribuuteilla. • Luodaan käyttöliittymä-komponentti. • Muutetaan GridBag-Constraints:in attribuuttien arvoja, mikäli tarpeen. • Lisätään komponentti paneeliin GridBagConstraints:ia käyttäen. • Palataan tarvittaessa kohtaan 4.
SOVELMAT Sovelman ajaminen <html> <head> <title>Kolee appletti</title></head> <body> <table width=”100%” height=”100%” border=”0”> <tr> <td align=”center” valign=”middle”> <applet code=”KoleeAppletti.class” width=”400” height=”300”> </applet> </td> </tr> </table></body> </html>
SOVELMAT Appletviewer
SOVELMAT Java-konsoli(Windowsissa)
SOVELMAT Sovelma vs. sovellus • Sovelmalla kiinteä ikkunan koko, sovelluksella joustava • Sovelma ei saa kirjoittaa mihinkään tiedostoon, sovellus saa • ns. servletit (palvelinsovelmat eli ”palvelmat”) saavat temmeltää jossain määrin vapaammin • Jotkin asiat on tehtävä sovelmissa hieman monimutkaisemmin, esimerkkinä kuvan lataaminen javax.swing.ImageIcon-olioksi: ImageIcon kuva = new ImageIcon(”mursu.png”); ImageIcon kuva = null; try { kuva = new ImageIcon(this.getImage( new java.net.URL(this.getCodeBase(), ”mursu.png”))); } catch (java.net.MalformedURLException e) { e.printStackTrace(); } sovellus sovelma
2D-GRAFIIKKA komponentti.repaint() kutsu tätä tarvittaessa korvaa tämä tarvittaessa omalla toteutuksella Swing-komponentin piirtäminen • Jokainen komponentti vastaa siitä, miten se piirretään ruudulle • Piirtojärjestelmä vastaa siitä, milloin tämä tapahtuu Piirtojärjestelmä paintComponent(Graphics g) komponentti.paint(Graphics g) paintBorder(Graphics g) paintChildren(Graphics g)