Utak og feilsituasjoer i Java (samt litt ekte Java I/O) Stei Gjessig, Istitutt for iformatikk, Uiversitetet i Oslo Oversikt Hva er e feil (er det ikke mulig å ugå feil?) Hva skjer år et program feiler Mål 1: Å ikke få feilmeldiger fra kjøretidsystemet, me istede la programmet få kotrolle tilbake etter e feilsituasjoe: Der programmet ormalt ville ha avsluttet med e feilmeldig Eks: Divisjo med ull, greier ikke åpe e fil, file fies ikke, kytte kotakt over ettet mislykkes, utefor arraygrese Mål 2: Eklere, mer vedlikeholdbar og mer forstålig kode
Feil i programmet hva skjer? import easyio.*; class Feil1 { public static void mai(strig[] args) { I tast = ew I(); it i = 1, j = 1; while ( i >= 0) { System.out.prit("\ Divisjo: 100 delt på: (gi tall):"); i = tast. iit(); j = 100/ i; System.out.pritl("Svaret på 100/" + i + " er:" +j); Array ideks utefor sie greser it [ ] tallvektor; tallvektor = ew it [100]; tallvektor[101] = 17;
Dages tema: Utak / feil Mye kode ka feile og feilaktige situasjoer (utak) ka oppstå. De kode som ka feile ka. og som oftest må vi legge følgede rudt kode:... Kode som ka feile...; catch (Exceptio e) {... Gjør oe med feile, prøv å rett opp... Dages tema: Utaksbehadlig <USIKKER KODE> <Hvis det skjer oe galt:> throw ew Utaksklasse( ); Ekleste form for utaksbehadlig. catch (Utaksklasse ut) { < Utaksbehadlig. Dette hoppes over år itet uormalt/galt har hedt > < her fortsetter valigvis programmet både etter ormal utførig og etter behadlig av evetuelle utak > På forhåd har vi deklarert: class Utaksklasse exteds Exceptio {...
Fire ye Java ord throw - Starter å kaste et utak throw <e peker til et utaksobjekt> f.eks throw ew Utak(); try - Står fora e blokk som er usikker dvs. der det ka oppstå et utak catch - Står fora e blokk som behadler et utak. Har e peker til et utaksobjekt som parameter throws - Kaster et utak videre Brukes i overskrifte på e metode som ikke selv vil behadle et utak <usikker kode> catch (Utaksklasse u) { <behadle utaket, u peker på et objekt som beskriver utaket Når utak oppstår i e metode A A x = B ( ); catch (Utaksklasse ut) { < Utaksbehadlig. Dette hoppes over år itet uormalt har hedt > < her fortsetter programmet både etter ormal utførig og etter behadlig av evetuelle utak > it B( ) throws Utaksklasse { A kaller B B oppdager e feil: throw ew Utaksklasse ( ) ; Normal retur fra B til A: retur 17; Utaksklasse er e klasse som vi på forhåd har deklarert som e subklasse av klasse Exceptio.
Utak - oversikt Brukes til å fage feil - eller uvalige situasjoer Når e feilsituasjo oppstår: Lages det et objekt Dette objektet brukes av feilbehadlige som ete skjer I samme metode (try-catch) eller blir sedt tilbake til kallede metode (throws) Vi må ikke (me ka) behadle feil av type: Error RuTimeExceptio Artimetriske feil Array-grese-feil Behadler vi ikke slike feil, avsluttes programmet av rutime-systemet Grusomme systemfeil vi ikke ka gjøre oe med Feil og feil fru Blom Vi behøver ikke gjøre oe med feil/utak (throws) Vi ka bare sede dem videre til de metode som kalte oss: throws (og helt til kjøresystemet: > java hvis det er mai som kaster utak/feilmeldiger videre). Vi må da etter metodes parameter-paretes me før begyede krøll-paretes skrive: throws UttakType1, UtakType2,... { hvor UttakType1, UtakType2,... er de typer (klasseavee) på de utak som oppstår (eller superklasser av disse, f.eks. Exceptio) og ikke selv fager med try-catch. Merk at vi bruker ordet både for utak metode vår selv geererer og de utak/feil metode mottar (fra metoder de selv har kalt) og bare videreseder. Ulempe med videre-kastig av utak: Jo ærmere feilkilde feile blir rettet, jo bedre.
Sede feilee videre ut av mai throws (ulempe programmet bare avslutter) import easyio.*; class MiFeil exteds Exceptio { MiFeil (Strig s) { super(s); class Feil { it i; public static void mai(strig[] args) throws ArrayIdexOutOfBoudsExceptio, NumberFormatExceptio, MiFeil { it j; j = ew Feil().a(args[0]); System.out.pritl("RIKTIG: j = + j); it a (Strig s) throws NumberFormatExceptio, MiFeil { it i = Iteger.parseIt(s); if (i < 10) throw ew MiFeil ("FEIL: Tallet er midre e 10"); retur i;!"# $ %!&"' To (tre) strategier for utakshådterig Fage utaket med try-catch og gjøre oe i catch-dele Ikke bruke try-catch, me bare sede (kaste) utaket videre med throws Fage utaket og ha e tom krøll-paretes i catch-dele (Ikke abefalt)
Utak strategier, mer detaljert oversikt (( %) %* 1. Løs problemet og kall metode som ga utak om igje 2. Lapper samme tig ute å kalle metode som ga utak, eller bereg et alterativt ( beste ) resultat istedefor det utaksmetode skulle ha bereget 3. Avslutt programmet: System.exit(0); 4. Igorere dem hvis de er av type RuTimeExceptio eller Error hvis de oppstår termierer programmet Utak - oversikt, forts. $ $$! (!" +,, $ - ).,/,,* + 0 $$$$,$1 2 33 # 453 ' 0 $$$, %,, 2 $ - 6,),(# ' * + 0 $$$$,$1 2 33 # 453 ' 0 $$$, %,6 $$, ( & 7 2
Strig-ideks utefor strige class Utak0x { public static void mai(strig[ ] args) { ew Utak0x ( ); Utak0x ( ) { Strig s = "Dette er e tekst med 29 teg", s1; s1 = s.substrig(30,32); // strig-ideks utefor "ede" Behadler Strigideks-feil class Utak1x { public static void mai(strig[ ] args) { ew Utak1x ( ); Utak1x ( ) { Strig s = "Dette er e tekst med 29 teg", s1; s1 = s.substrig(30,32); // strig-ideks utefor "ede" catch (StrigIdexOutOfBoudsExceptio e) { System.out.pritl("Her er det oe galt med strig-idekse ); //ed try >java Utak1x Her er det oe galt med strig-idekse
Eksempel på bruk av utaksobjektet class Utak2x { public static void mai(strig[ ] args) { ew Utak2x ( ); Utak2x ( ) { Strig s = "Dette er e tekst med 29 teg", s1; s1 = s.substrig(30,32); // strig-ideks utefor "ede" catch (StrigIdexOutOfBoudsExceptio e) { System.out.pritl("Her er det oe galt med strig-idekse " + e.getmessage( )); //ed try >java Utak2x Her er det oe galt med strig-idekse Strig idex out of rage: 32 Fage divisjo med 0 public class TryTest { public static void mai ( Strig [ ] args) Her tar programmet { it i=1; seg av hele feile for (it j=0; j < 5; j++) try{ i = 10/j; System.out.pritl("Det gikk OK, i:" + i + ", j:" + j); catch (Exceptio e) { System.out.pritl("Feil i uttrykk: "+ e.getmessage( )); // ed TryTest sidil> java TryTest Feil i uttrykk: / by zero Det gikk OK, i:10, j:1 Det gikk OK, i:5, j:2 Det gikk OK, i:3, j:3 Det gikk OK, i:2, j:4 sidil>
Starte å sede feil/utak selv - eks. class Feil1 { it i; public static void mai(strig[] args) { ew Feil1().a(ull); void a( Feil1 pek) { if (pek == ull ) throw ew NullPoiterExceptio( pek må være!= ull"); pek.i = 14; Merk at her kastes et objekt av e klasse som er subklasse av RuTimeExceptio, så da treger vi ikke try-catch rudt kallet på metode a Egedefierte utak class Mittutak exteds Exceptio { public Mittutak ( ) { public Mittutak (Strig s) { super(s); // ed kostruktører // ed class Mittutak try{... catch (Mittutak e) {.. e.getmessage( ).. throw ew Mittutak("feilmeldig"); De ye klasse Mittutak utvider (exteds) de ferdiglaget Java-klasse med av Exceptio. throw ew Mittutak( );
4* class Mittutak exteds Exceptio { public Mittutak ( ) { Fullstedig eks. public Mittutak (Strig s) { super(s); import java.io.*; class UtakEge { public static void mai(strig[ ] args) throws IOExceptio { ew UtakEge ( ); UtakEge ( ) throws IOExceptio { BufferedReader mii = ew BufferedReader (ew IputStreamReader(System.i)); System.out.pritl("Skriv et positivt tall?"); Strig lije = mii.readlie ( ); it tall = Iteger.parseIt(lije); if (tall < 0) throw ew Mittutak(lije); System.out.pritl("Rote av tallet er: " + Math.sqrt(tall)); catch (Mittutak u) { System.out.pritl(" Ka ikke fie rote av " + u.getmessage()); // slutt class UtakEge 4* Koto med OvertrekkUtak - VIKTIG class Koto { private double saldo = 0, miimumsaldo = 0; private it kotor; Koto (it r) { kotor = r; public void taut (double belop) throws OvertrekkUtak { if (saldo - belop < miimumsaldo) { throw ew OvertrekkUtak(Iteger.toStrig(kotor)); else saldo = saldo - belop; // slutt taut... class OvertrekkUtak exteds Exceptio { public OvertrekkUtak (Strig s) { // slutt Koto super(s); // ed class OvertrekkUtak
Bruk av Koto med OvertrekkUtak class Bak{ static void mai (Strig [] args) { Koto pek = ew Koto(234); pek.taut(-10); catch (OvertrekkUtak e) { System.out.prit(" Overtrekk på koto "); System.out.pritl( e.getmessage()); // slutt catch // slutt mai slutt Bak Flere opplysiger ut av parametere til catch import easyio.*; class Feil3 { public static void mai(strig[] args) { ew Feil3().a(); void a() { b(); void b(){ I tast = ew I(); it i = 1, j = 0; Divisjo: 100 delt p : (gi tall):0 FY - delig med ull er tull java.lag.arithmeticexceptio: / by zero at Feil3.b(Feil3.java:19) at Feil3.a(Feil3.java:9) at Feil3.mai(Feil3.java:6) Divisjo: 100 delt p : (gi tall): while ( i >= 0) { System.out.prit("\Divisjo: 100 delt på: (gi tall):"); i = tast. iit(); try{ j = 100/ i; System.out.pritl("Svaret på 100/" + i + " er:" +j); catch (Exceptio e){ System.out.pritl("\ FY - delig med ull er tull"); e.pritstacktrace();
Hvilke klasser av feil og utak har vi i Java Exceptio utak (med alle subklassee) Disse utakee ka og må vi fage (Utatt RuTimeExceptio) F.eks. IOExceptio (kommer vi tilbake til) RuTimeExceptio (e subklasse av Exceptio) igje med sie subklasser som : ArrayIdexOutOfBoudsExceptio, NumberFormatExceptio, ArithmeticExceptio,... Disse ka, me må vi ikke fage Vi ka, me må ikke skrive try-catch for disse feilsituasjoee Vi ka kort sagt igorere disse (me da termierer programmet ) Det ville ellers bli alt for mye..catch (..){... i kode Eks: Divisjo med 0, e peker er ull, gal ideks i e array,.. Error (med alle subklassee) Noe galt skjer, vi ka som oftest ikke gjøre oe med det Eks:.IteralError.OutOfMemoryError, NoClassDefFoudError Error og Exceptio er subklasser av Throwable Fage flere utak class Utak3x { public static void mai(strig[ ] args) { ew Utak3x ( ) ; Utak3x ( ) { it divided=7, divisor = 0; it kvotiet=0; Strig s="dette er e tekst med 29 teg"; Strig s1="*********"; s1 = s.substrig(15,17); // OK strig-ideks kvotiet = divided/divisor; // Feil: divisjo med 0 catch (StrigIdexOutOfBoudsExceptio e) { System.out.pritl("Her er det oe galt med strig-idekse"); catch (ArithmeticExceptio e1) { System.out.pritl("Divisjo med 0: " + e1.getmessage( ) ); //ed try-catch System.out.pritl(s1); System.out.pritl(kvotiet); >java Utak3x Divisjo med 0: / by zero st 0
Nytt Java ord: fially Vi ka ha flere catch etter hveradre: try{... Kode som ka gi utak / feile... catch (Type1 t1 ) { catch (Type2 t2 ) {... catch (Type3 t3 ) {... fially { // Dette gjøres alltid - selv om vi ikke får oe utak Da testes det (omlag som e switch), og bare de første som får tilslag, blir utført Husk: At hvis e av klasseavee (Type1, Type2,..) er superklasse til det ikome utaket, vil de blir utført. Fially vil alltid bli utført ete det ble utak eller ikke og ete oe av catchee fikk tilslag eller ikke. Motta mage feiltyper - eksempel import easyio.*; class MiFeil exteds Exceptio { MiFeil (Strig s) { super(s); class Feil7 { it i; it a( Strig s) throws NumberFormatExceptio, MiFeil{ it i = Iteger.parseIt(s); if (i < 10) throw ew MiFeil ("FEIL: Tallet er midre e 10"); retur i; public static void mai(strig[] args) { it j; j= ew Feil7().a(args[0]); System.out.pritl("RIKTIG: j="+j); catch (ArrayIdexOutOfBoudsExceptio e) { System.out.pritl("Galt kall på Feil7, bruk:>java Feil7 tall "); catch (NumberFormatExceptio e) { System.out.pritl("Skriv tall"); catch (MiFeil m) { System.out.pritl(m.getMessage()); m.pritstacktrace(); fially { // Dette gjøres alltid - selv om vi ikke får oe utak System.out.pritl("Alltid fially");
IO feil E metode som ka komme til å gjøre e IO-feil må ete behadle dette selv, eller kaste feile videre: public void mifilleser() throws IOExceptio { < kode som gjør fil-behadlig> I fra tastatur i Java mai mii Hilse klassedatastruktur import java.io.*; class Hilse { public static void mai (Strig [] args) throws IOExceptio { BufferedReader mii = ew BufferedReader (ew IputStreamReader(System.i)); av Strig readlie() Objekt av klasse BufferedReader System.out.pritl( Hva heter du?"); Strig av = mii.readlie ( ); System.out.pritl( God dag " + av ); sidil:>javac Hilse.java sidil:>java Hilse Hav heter du? Stei Gjessig God dag Stei Gjessig sidil:> " # $ # 11 kostruktører 47 metoder pluss plass til å lagre e streg (e tekst) Stei Gjessig Et objekt av klasse Strig
Om å lese desimaltall (Utdrag av et program) import java.io.*; BufferedReader mii = ew BufferedReader (ew IputStreamreader (System.i)); double tall; Strig lije; mai mii lije = mii.readlie(); Strig readlie() tall = Double.parseDouble(lije); // eller: tall = Double.valueOf(lije.trim()).doubleValue(); Vi husker: Double er e klasse som ieholder mye verktøy som behadler kommatall av type double. ( Dette har ige tig med ilesig å gjøre. ) Adre klasser som bl.a. heter Character, Iteger, Log og Boolea ieholder metoder for å ta seg av hhv. teg, heltall (it og log) og logiske verdier. Se i pakke java.lag Dette objektet leser fra tastaturet Double Double valueof ( ) double parsedouble ( ) double doublevalue( ) E ekel måte å lese heltall på import java.io.*; BufferedReader mii = ew BufferedReader (ew IputStreamReader (System.i)); it tall; Strig lije; lije = mii.readlie(); tall = Iteger.parseIt(lije); DETTE GÅR BRA HVIS LINJEN BARE INNE- HOLDER ET TALL!! 137 tall lije Iteger it parseit ( ) Strig klassedatastruktur 137 Et objekt av klasse Strig
Ilesig fra fil Java origial Først må vi lage e forbidelse med file: fili BufferedReader fili = ew BufferedReader (ew FileReader ( mifil.txt )); Nå ka vi bruke file på samme måte som vi leste data fra tastaturet: double dtall; Strig tekst; Dette objektet leser fra file mifil.txt mifil.txt 123.54 Forelesigee dtall = Double.parseDouble(filI.readLie()); tekst = fili.readlie( ); tekst dtall 123.54 Forelesigee Et objekt av klasse Strig Utskrift til fil - Java origial mai filut PritWriter filut = ew PritWriter (ew FileWriter ( miutfil.txt )); // Utskrift skjer som til skjerm: filut.pritl( utskrift + 17 ): For at iholdet på de ye file skal bevares må vi til slutt si: Dette objektet skriver på file miutfil.txt void pritl() miutfil.txt filut.close( );
I/O utak som ikke behadles av programmet Når det oppstår et I/O-utak ka programmet velge å selv ikke behadler det, me kaste det videre til kjøretidsystemet. public static void mai(strig[] args) throws IOExceptio { BufferedReader fili = ew BufferedReader (ew FileReader ("difil.txt"));... For eksempel hvis file ikke fies: Summe av tallee på e fil (estet try-catch) import java.io.*; class Sum { public static void mai(strig[] args) throws IOExceptio { BufferedReader i = ew BufferedReader (ew IputStreamReader (System.i)); BufferedReader fili = ull; Strig filav = ull, lije = ull; it tall, sum= 0; boolea filskalfies = true; while ( filskalfies ) { System.out.prit("Filav: "); filav = i.readlie(); fili = ew BufferedReader (ew FileReader (filav)); // Ikke gjeta fil-åpig mer: filskalfies = false; while ( true ) { lije = fili.readlie(); tall = Iteger.parseIt(lije); sum += tall; catch (NumberFormatExceptio e) { System.out.pritl("Summe er: "+sum); catch ( FileNotFoudExceptio e) { System.out.pritl(filav+ " uket ); System.out.pritl("Prøv igje"); // slutt åpe fil løkke // slutt mai // slutt klasse Sum
To alterative EOF -metoder (programmøstre) while ( true ) { lije = fili.readlie(); if (lije == ull) throw ew EOFExceptio(); tall = Iteger.parseIt(lije); sum += tall; catch (EOFExceptio e) { System.out.pritl ("Summe er: "+sum); lije = fili.readlie(); while ( lije!= ull ) { tall = Iteger.parseIt(lije); sum += tall; lije = fili.readlie(); System.out.pritl ("Summe er: "+sum); Eksempel: class I og IExp i easyio public class IExp { BufferedReader i;... public it iit(strig sep) throws NumberFormatExceptio, IOExceptio { retur Iteger.parseIt(iWord(sep)); public Strig iword(strig sep) throws IOExceptio { lieno++; retur i.readlie(); public class I exteds IExp { public it iit() { retur iit(ull); public it iit(strig sep) { for (it i = 0; i < umtry; i++) { retur super.iit(sep);... catch (IOExceptio ioe) { feil("iit: " + ioe.getmessage()); retur 0; // kompilatormat catch (NumberFormatExceptio fe) { System.out.prit("Forveter et heltall. Prøv igje: "); // ed try-catch
A%, 8% @ 8 9 ( %,,6 %* & & :#'7 8; % #'', % +)33$ <, +)33=* 0 $ $ $ + 0 $ $ $ %$ $ $ 2 33#453> ' 0 $ $ $ 2 + 0 $ $ $ 2 2 8:,$ ; % 6 ( &* #$$$' & 453> 8; %?%453=6, ( $ 8 4 %, % 6 %, +@ 6 % %, %,$ Java og C# Vi har tidligere sakket litt om forskjellee mellom Java og C# Java er laget av Su, C# av Microsoft Det meste er likt Tidligere har vi sakt at hedelser hådteres forskjellig Utak hådteres rimelig likt, me i C# er du ikke tvuget til å deklarere de utak som kastets videre (alle utak I C# fugerer altså slik som rutime-feil i Java) Alle Microsofts språk kompileres til C# og bruker C#s objektorieterte kjøretidsystem Java compileres til byte-kode, C# kompileres Just-I-Time (JIT) til maskikode