Chapter 10
Undtagelseshåndtering

Kurt Nørmark ©
Department of Computer Science, Aalborg University, Denmark


September 2001


Abstract
Previous lecture Next lecture
Index References Contents
Vi har valgt at bruge betegnelsen 'undtagelseshåndtering' som overskrift til denne lektion. En anden, og måske mere ligefrem mulighed havde været 'fejlhåndtering'. Vi starter med at motivere området ved at se på forskellige problemstillinger der trænger sig på. Dernæst afklarer vi terminologi og begreber. Med dette ender vi med at tillægge forskellige betydninger til ordene 'fejl' og 'undtagelse'. Efter denne begrebs- og terminologiafklaring går vi over til at studere Java. Vi bruger naturligvis de begreber vi har lagt fast, men vi skal være opmærksomme på, at Java terminologien ofte kommer lidt tværs af vores. Vi slutter lektionen af med at studere fejlhåndtering i forlængelse af specifikation, kontrakter og ansvarsfordeling, som vi jo har set på i detaljer i en tidligere lektion


Motivation og problemstillinger

Normal- og fejltilfælde behandles under ét
Slide Note Contents Index
References Speak
I denne første afdeling af lektionen tager vi et antal forskellige problemstillinger op til behandling. Vi starter med at se på programmer, hvor normaltilfælde og fejltilfælde behandles samlet. Dette giver ofte uoverskuelige programmer

I ekstreme situationer kan det være svært at identificere det egentlige program i forhold til de fejlbehandlende dele af et program

Program: Et program uden fejlhåndtering som kopierer én fil over på en anden. Vi har tidligere i kurset set på netop dette program. Læg mærke til at programmet kan give anledning til en IOException.
import java.io.*;

public class Copy {
    public static void main(String[] args) throws IOException {

        FileReader in = new FileReader(new File(args[0]));
        FileWriter out = new FileWriter(new File(args[1]));
        int c;

        do{
          c = in.read();
          if(c != -1) out.write(c);
        } while (c != -1);  

        in.close();
        out.close();
    }
}

Program: Et (pseudo)program med fejlhåndtering som kopierer én fil over på en anden. Bemærk at programmet forsøger at holde al fejlhåndteringen inden for rammerne af kopieringsprogrammet. Derfor giver denne udgave af programmet ikke anledning til at main kan kaste et exception. Programmet forsøger side om side med kopieringsaspekterne (normaltilfældet) at håndtere en række fejltilfælde. Vi har farvelagt fejlaspekterne med rødt. De sorte dele af programmet udgør de normale kopieringsdele af programmet. Programmet tager udgangspunkt i ovenstående program, men det er ikke gennemført i 100 procent Java.
import java.io.*;

public class Copy {
    public static void main(String[] args) 

        do{
           File inf = new File(args[0]);
           if (!inf.exists())
            args[0] = some other input file name;
        }
        while (!inf.exists());
        FileReader in = new FileReader(f);

        do{ 
           File ouf = new File(args[1]);
           if (ouf.exists())
            args[1] = some other output file name
        while (ouf.exists());
        FileWriter out = new FileWriter(new uof);

        int c;

        do{   
          c = in.read();
          if(c != 1) out.write(c);
          if (out.full())
            // fix some extra room on the disk
        } while (c != -1);  

        in.close();
        if (!in.isClosed)
          // deal with input file which cannot be closed

        out.close();
        if (!out.isClosed)
          // deal with output file which cannot be closed
    }
}

Sondringen mellem normalprogram og fejlbehandlende program udgør en særligt form for ansvarsfordeling

Vi har tidligere - i anden sammenhæng - set på ansvarsfordeling mellem klient og forsyner (mellem kalder og den kaldte procedure). Her lader vi op til en anden form for ansvarsfordeling, nemlig mellem normaltilfælde og undtagelsestilfælde

References

Fejl søges håndteret tæt på det sted hvor fejlene opstår
Slide Note Contents Index
References Speak
Det er i mange situationer ikke muligt eller hensigtsmæssigt at håndtere en fejl i umiddelbar nærhed af det sted, hvor fejlen opstod. Vi ser her nærmere på denne problematik.

Der er ofte 'stor afstand' mellem det sted fejlen opstår og det sted hvor der er en chance for at fejlen kan håndteres fornuftigt

  • Observationer:

    • En fejl i en metode M i en klasse C

      • Mange mulige reaktioner i forskellig direkte og indirekte klienter af C

    • En fejl i en 'model metode'

      • Afstedkommer håndtering af fejlen i en brugergrænseflade klasse

Unuanceret viden om fejlens natur
Slide Note Contents Index
References Speak
Vi ser her på den problemstilling der består i, at vi ikke har nok information om fejlens natur. Det er forudsætning for fejlhåndtering, at vi kender fejlens egenskaber i rimelig detalje

Hvis man skal håndtere en fejl fornuftigt skal man vide i detaljer, hvad det er for en fejl som er opstået

  • Hvis der opstår en fejl skal detaljerne om fejlen repræsenteres på en sådan form, at fejlhåndteringen har optimale muligheder for at reagere på eller afværge fejlen

    • Hvor i programmet opstod fejlen (klasse, metode, linienummer, køretidsstak)?

    • Hvilken slags fejl er der tale om?

    • En intuitiv og uformel beskrivelse af fejlen

I et objekt-orienteret system er det oplagt at repræsentere en fejl som et objekt

Hvilken slags fejlhåndtering?
Slide Note Contents Index
References Speak
Her ser vi på hvad det egentlig vil sig at håndtere en fejl

  • Ignorering: Konstatering af 'falsk alarm'

  • Rapportering: Udskrift af information om fejlen

  • Terminering: Afslutning af programudførelsen

  • Reparering: Tilstandsændring som bringer programmet tilbage 'på ret kurs' (recovery)

I det typiske fejlhåndteringstilfælde kombineres rapportering med efterfølgende terminering


Terminologi og begreber

Mange forskellige ord
Slide Note Contents Index
References Speak
Når man gennemser litteratur om emnet støder man på en del forskellige ord, som er relateret til fejlbehandling. Her opremser vi en række af disse. På næste side vil vi tillægge nogle af disse en klar og tydelig mening

Der anvendes mange forskellige ord inden for fejl- og undtagelsesområdet, ofte uden en klart defineret mening

Table. En række ord på dansk og engelsk som benyttes når vi interesserer os for fejl
DanskEngelsk
FejlError
UndtagelseException
LusBug
DefektDefect
-Failure
 

Der er behov for en begrebsafklaring således at vi på en nuanceret måde kan tale om fejl og fejlhåndtering

Grundliggende begreber
Slide Note Contents Index
References Speak
Tiden er nu inde til at fastlægge betydningen af tre ord: 'fejl', 'defekt' og 'undtagelse'. Disse tre ord afspejler problemer i hhv. programmeringsprocessen, programbeskrivelsen og programudførelsen. Vi er inspireret af bogen 'Object-oriented Software Construction' af Bertrand Meyer

The concept fejl: En fejl er en forkert beslutning i programudviklingsprocessenEn fejl er noget som sker når man programmerer. En fejl betegner en forkert beslutning i udviklingsarbejdet
The concept defekt: En defekt er en egenskab af et program som kan forårsage, at programmet afviger fra den påtænkte (specificerede) opførselEn defekt er den afledte konsekvens, som en fejl har på kildeprogrammet. En defekt er således en (dårlig) egenskab ved et program
The concept undtagelse: En undtagelse er en hændelse i programudførelsen som kan forårsage afvigende eller fatal opførsel i forhold til intensionen (specifikationen)En defekt kan føre til en undtagelse når programmet køres. En undtagelse er altså køretids manifestationen af en fejl og af en programdefekt. En undtagelse er udtryk for afvigende eller fatal opførsel af programmet i forhold til specifikationen af programmet

En undtagelse under programudførelsen stammer fra en defekt i programmet som igen er forårsaget af en fejl under programmets udvikling


Undtagelseshåndtering i Java

Oversigt over undtagelseshåndtering i Java
Slide Note Contents Index
References Speak
Inden vi kaster os over de mange detaljer i Java's undtagelseshåndtering giver vi her en oversigt over de væsentligste forhold i Javas dækning af emnet

  • Undtagelser materialiseres som et objekt

  • Undtagelser kan klassificeres i et klassehierarki

  • Undtagelser kan 'kastes' eksplicit i enhver metode eller implicit af Java køretidssystemet

  • En vilkårlig kommando-liste i en metode kan tilknytte kommandoer til undtagelseshåndtering

  • En metode kan erklære hvilke undtagelser som forbliver ubehandlede efter at metoden returnerer

Undtagelseshåndtering i Java bidrager både til de dynamiske og statiske aspekter af sproget

Til de dynamiske aspekter henregnes det faktum, at exceptions er objekter i Java samt at exceptions propageres langs kæden af kaldte metoder. Til de statiske aspekter bidrager at exceptions erklæres som klasser, at metoder erklærer hvilke exceptions metoden kan afstedkomme samt at compileren kan checke aspekter af undtagelseshåndteringen. Alle disse forhold vil blive diskuteret i yderligere detalje senere i denne lektion

Catch or specify princippet i Java
Slide Note Contents Index
References Speak
Inden vi går videre nævner vi et princip, som er karakteristisk for Java's omgang med exceptions. Vi vender tilbage til emnet senere i lektionen

En metode skal enten fange en fejl (catch) eller erklære at metodekaldet kan føre til kastning af fejlen (specify)

  • Catch:

    • Undtagelsen håndteres internt i metoden

    • Klienten behøver ikke at kende til eller bekymre sig om undtagelsen

  • Specify:

    • Metoden erklærer at den kan forårsage en exception

    • Undtagelsen skal håndteres eller videre specificeres af metoder i klienten

Program: Et program med compile fejl. Hovedprogrammet kalder eksplosion uden hverken at håndtere fejlen, eller specificere den.
class Problem extends Exception{
  Problem(){super();}
  Problem(String s) {super(s);}
}

public class CatchOrSpecifyDemo0 {

  static void eksplosion() throws Problem {
    System.out.println("Eksplosion!");
    throw new Problem("Vi har et eksplosivt problem");
  }

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

Program: Et program som håndterer et Problem. Hovedprogrammet håndterer via en try-catch konstruktion fejlen.
class Problem extends Exception{
  Problem(){super();}
  Problem(String s) {super(s);}
}

public class CatchOrSpecifyDemo1 {

  static void eksplosion() throws Problem{
    System.out.println("Eksplosion!");
    throw new Problem("Vi har et eksplosivt problem");
  }

  public static void main(String[] args){
    try {
      eksplosion();
    }
    catch (Problem e) {
      System.out.println("Vi håndterede problemet!");
      System.out.println("Eller gjorde vi?");
    } // try
  }
}
    

Program: Et program som specificerer et Problem. Programmet går ned under kørslen, fordi Problem ikke håndteres nogetsteds.
class Problem extends Exception{
  Problem(){super();}
  Problem(String s) {super(s);}
}

public class CatchOrSpecifyDemo2 {

  static void eksplosion() throws Problem{
    System.out.println("Eksplosion!");
    throw new Problem("Vi har et eksplosivt problem");
  }

  public static void main(String[] args) throws Problem  {
      eksplosion();
  }
}
    

Klassificering af undtagelser i Java
Slide Note Contents Index
References Speak
Der er mange forskellige undtagelser, som kan opstå når vi bruger Java bibliotekerne. Endvidere kan vi definere vore egne undtagelser. Vi ser her på hvordan eksisterende og nye undtagelser klassificeres på det mest generelle niveau

Undtagelser klassificeres via et klassehierarki i Java, hvor roden er klassen Throwable

Figure. Toppen af exception klassehierarkiet i Java. De med fedt fremhævede klasser er centrale i hierarkiet.

Java bidrager til forvirring af begreberne om undtagelse på grund af dårlig valgt terminologi

Vi tænker her på det forfærdelige ord 'throwable' og på den misvisende kategori af undtagelser som kaldes RuntimeExceptions. Alle undtagelser er runtime exceptions!

Exercise 10.1. Undtagelser i tallæsningsprogrammetÉn af de første øvelser vi lavede i kurset (lektion 2) gik ud på at indlæse et tal fra tastaturet ved at læse en række enkelte tegn. Genfind jeres løsning på denne opgave, eller tag min løsning , som også findes på filen talLaesning.java

  • Hvorfor erklærer readInt metoden at den kaster undtagelsen IOException?
  • Find tilbage det sted i Java API dokumentationen, der beskriver at der kan forekomme en exception i metoden readInt.
Vi går nu over til at foretage forskellige mindre ændringer i programmet fra lektion 2. Vi håndterer IOException og introducerer en anden mere specifik form for undtagelse:
  • Lav nu en variant af programmet fra lektion 2 som - på én eller anden måde - håndterer IOException. Vores beslutning kan f.eks. være at returnere 0 hvis der forekommer en IO undtagelse når vi læser fra standard input.
  • Der er naturligvis problemer hvis vi læser bogstaver eller specialtegn i metoden readInt. Definer nu selv en exception klasse NumberReadException; Vi ønsker at kaste en instans af denne undtagelse fra readInt hvis vi læser et bogstav eller et specialtegn.

References

Beskrivelse af exception klasser i Java (1)
Slide Note Contents Index
References Speak
Vi vil her karakterisere de generelle exception klasser i Java, som vi introducerede på forrige side

  • Throwable:

    • Superklasse for alle exceptions

    • Indeholder metoder til håndtering af 'stack tracing'

  • Error:

    • Afspejler alvorlige problemer (interne fejl i Java systemet) som normalt ikke forekommer i et kørende Java system

    • Håndteres ikke under normale omstændigheder

    • Er ikke underlagt 'catch or specify' princippet

    • Kastes kun sjældent af vore egne programmer

    • Eksempler: For dyb rekursion, ikke mere arbejdslager, manglende metode eller felt, instantering af abstrakt klasse

At Error exceptions ikke er underlagt catch or specify princippet betyder at disse exceptions ikke skal specificeres i metoders throws clauses

De sidstnævnte to eksempler på Errors forekommer ikke i 'normale' java programmer, idet de fanges under oversættelsen. Hvis man imidlertid tilgår objekter, som er lagret persistent på disken, eller hvis man via et klassenavn tilgår selv klassen med henblik på instantiering, kan disse fejl opstå

References

Beskrivelse af exception klasser i Java (2)
Slide Note Contents Index
References Speak
Vi fortsætter her vores beskrivelse af de centrale exception klasser i Java

  • RuntimeException:

    • Almindeligt forekommende køretidsfejl

    • Unchecked - compileren insisterer ikke på overholdelse af 'catch or specify' princippet

    • Eksempler: Aritmetisk fejl (division med nul), umulig casting, array indeks fejl, objekttilgang via null reference

  • IOException:

    • Undtagelser relateret til input eller output

    • Underlagt 'catch or specify' princippet

    • Eksempler: Ikke eksisterende fil, end of file, fejlformateret URL

Der er en pragmatisk årsag til at man vælger at afvige fra 'catch or specify' princippet for de mest hyppige undtagelser i Java. Det vil simpelthen være for stor en byrde at skulle fange (håndtere) eller erklære (specificere) alle sådanne fejl. Enhver metode ville være fuld af undtagelseshåndtering, og der ville være massevis af erklæringer af ikke håndterede exceptions på alle metoder.

References

Exercise 10.2. Klassificering af undtagelser i CircularListI klassen CircularList , som vi første gang mødte i lektionen om arrays og lister, er der flere forhold som på en naturlig måde giver anledning til kastning af undtagelser

  • Kortlæg først problemet ved at liste de mulige undtagelser, som kan forekomme i klassen
  • Design om nødvendigt et lille hierarki af undtagelsesklasser, som klassificerer fejlene. Hierarkiets rod bør være CircularListException.
Resten af opgaven går ud på at modificere klassen CircularList således at de respektive metoder i klassen kaster relevante exceptions.

Tag evt. udgangspunkt i min løsning fra den tidligere lektion.

Instantiering og 'kastning' af exceptions
Slide Note Contents Index
References Speak
Her vil vi se hvorledes man instantierer en exceptionklasse, samt ikke mindst hvordan den 'kastes'

Vi benytter os af et atletisk billedsprog når vi taler om at etablere en undtagelse, samt at bringe det i retning af det sted i programmet, som håndterer undtagelsen

Syntax: Syntaks for 'kastning af en undtagelse'. Exception refererer til et objekt, som er en instans af en exception klasse (eller mere præcis, en instans af en klasse der arver fra Throwable).

throw exception

Program: Et eksempel på en throw kommando samt den underliggende Exception klasse.
...
throw (new SomeProblem("Problembeskrivelse"));
...



class SomeProblem extends Exception{

  public SomeProblem(String problem){
    super(problem);
  }

} // end SomeProblem


Håndtering af exceptions i en metode
Slide Note Contents Index
References Speak
Når fejlen skal håndteres sker det i en metodes exception handler. Vi ser her på de sproglige mekanismer i Java, der tillader os at knyttet exception handlers til kommandoer i en metodes krop

Try konstruktionen udgør scopet for undtagelseshåndtering i Java

Syntax: Syntaks for try kommandoen i Java. Det giver mening at tænke på denne som en form for kontrolstruktur i sproget. En try konstruktion udgør scopet for fejlhåndtering. Kommandoblokken i try delen udføres (eller forsøges udført, som antydet af 'try syntaksen'). Hvis der herved opstår en undtagelse vil denne blive forsøgt håndteret af en catch længere fremme i konstruktionen. Den første catch som matcher det exception, som er opstået, binder undtagelsesobjektet til den formelle parameter (ligesom ved parameteroverførsel) hvorefter blokken efter catch udføres. Der udføres kun denne ene catch. Catches må ikke gentages, men det er tilladt at fange en specifik exception først for dernæst at fange en mere generel exception.

try{
 kommando-liste-0
}
catch (exception-klasse-1 formel-parameter-1){
 kommando-liste-1
}
catch (exception-klasse-2 formel-parameter-2){
 kommando-liste-2
}
...

Der udføres kun én catch clause, som matcher exception objektet

De første catch clauses kan være specialiserede - og de sidste mere generelle

Den formelle exception parameter er polymorf

At den formelle exception parameter er polymorf betyder, at den kan antage exceptions, som er instanser af vilkårlige subklasser af den angivne exception klasse

Program: Et konkret eksempel på en try catch konstruktion. De metoder, som kan forårsage kastning af et exception er refereret andetsteds fra denne side.
try {
  ...
  int i = Integer.parseInt(str.substring(j,k));
  ...
} 
catch (StringIndexOutOfBoundsException e){
  ...
}
catch (NumberFormatException e){
  ...
}
catch (Exception e){
  ...
}

References

Propagering af exceptions (1)
Slide Note Contents Index
References Speak
Et eksisterende exception objekt udbredes fra problemets kilde til det sted, hvor fejlen håndteres. Vi illustrerer her hvordan fejlen udbredes

En ikke-håndteret undtagelse propageres tilbage langs kæden af kaldte metoder

Figure. Illustration af fejludbredelse efter at der opstår et exception i metoden s.

Eksemplet fortsættes og uddybes på næste slide

Propagering af exceptions (2)
Slide Note Contents Index
References Speak
Her fortsætter vi diskussionen af exception propagering med en serie af billeder, der trin for trin illustrerer hvordan et kast af et exception kan forløbe når der indgår reparation af problemet i den sidste ende

Image series: En trin for trin variant af billedet om fejludbredelse, herunder recovery.En trin for trin variant af billedet om fejludbredelse, herunder recovery.

Image no. 1. Efter at main har kaldt p, som har kaldt q, som har kaldt s opstår der en undtagelse i s. s håndterer ikke undtagelsen selv (men erklærer i sin signatur at den kaster en bestemt slags exception)
 

Image no. 2. Metoden s kaster en exception til sin kalder, som i dette tilfælde er r. Metoden r har nu chancen for at håndtere undtagelsen. Lad os antage, at det ikke sker. r kaster altså ligesom s en exception
 

Image no. 3. På fuldstændig samme måde opstår der en exception i metoden q. Lad os videre antage at heller ikke q håndterer undtagelsen. q kaster altså undtagelsen videre til p
 

Image no. 4. Der opstår nu en exception i p. Lad os antage at p håndterer undtagelsen på en sådan måde at programmet bringes på sporet igen. Vi er efterladt i positionen hvor p i en try blok har kaldt q
 

Image no. 5. På en eller anden måde løser en catch i try konstruktionen i p problemet
 

Image no. 6. p kalder nu en bedre version af q, her kaldet better_q. I programeksemplet herunder svarer dette til kaldet q(false)
 

Image no. 7. q kalder videre til r, igen i en 'bedre udgave'
 

Image no. 8. r kalder videre til s, på samme måde i en bedre udgave
 

Image no. 9. s undgår at komme i en undtagelsessituation. Og alle er lykkelige efter disse hårde strabadser
 

Program: Et Java program som opfører sig på samme måde som ovenstående billedserie. I en gennemlæsning af programmet, se først på de blå dele (kaldskæden), den røde del (det sted hvor der sker et exception), og de brune steder (hvor undtagelsen bliver håndteret mv.)
public class ExceptionDemo{
  
  public static void main(String[] args) throws DemoException{
   ExceptionDemo object = new ExceptionDemo();
   System.out.println("metoden main");
   object.p();
  }

  public void p() throws DemoException{ 
   System.out.println("metoden p");
   try{
     q(true);
   }
   catch (DemoException e){
     System.out.println(e);
     System.out.println("Reparation i p");
     q(false); // false means better version
   }
  }

  public void q(boolean b) throws DemoException{  
   System.out.println("metoden q");
   r(b); 
  }

  public void r(boolean b) throws DemoException{   
   System.out.println("metoden r");
   s(b);
  }

  public void s(boolean b) throws DemoException{    
   System.out.println("metoden s");
   if (b)
     throw (new DemoException("Vi har et problem"));
   else 
     System.out.println("Nu går det bedre i s");
  }
}

class DemoException extends Exception{
  
  public DemoException(String problem){
    super(problem);
  }

}

Program: Output fra kørsel af ovenstående Java program.
metoden main
metoden p
metoden q
metoden r
metoden s
DemoException: Vi har et problem
Reparation i p
metoden q
metoden r
metoden s
Nu går det bedre i s

Finally i Java's try blok (1)
Slide Note Contents Index
References Speak
I forlængelse af ovenstående behandling af try catch er det naturligt at introducere finally konstruktionen. En finally konstruktion bliver udført uanset hvilken vej man vælger ud af en try

Finally konstruktionen i forlængelsen af try-catch muliggør en samlet afslutning af normaltilfældet og undtagelsestilfældet i Java

Syntax: Syntaks for try kommandoen i Java med en finally del.

try{
 kommando-liste-0
}
catch (exception-klasse-1 formel-parameter-1){
 kommando-liste-1
}
catch (exception-klasse-2 formel-parameter-2){
 kommando-liste-2
}
...
finally{
 kommando-liste-3
}

Finally i forhold til return, break og continue
Slide Note Contents Index
References Speak
Finally konstruktionen bør også studeres i forbindelse med de hop-agtige muligheder, som understøttes i Java, og som vi har mødt allerede tidligt i dette kursus.

Der er ingen mulighed for at forlade en 'try blok' uden at udføre 'finally blokken'

Specielt kan Java's hop kommandoer break, continue og return ikke komme uden om en 'finally blok'

Program: Illustration af finally i forhold til return: Læsning af en fil indtil et bestemt tegn mødes. I en try blok læser vi tegnene i filen in. Hvis vi møder tegnet letter (en streng af længde én) returnerer vi umiddelbart true. Hvis vi når hele vejen gennem løkken returnerer vi false. Pointen i dette eksempel er, at finally blokken udføres når return er på vej ud af metoden lookForLetter med enten true eller false. Læg iøvrigt mærke til, at vi i dette eksempel har en try blok uden catch clauses, men med en finally clause. Opstår der en IOException forplantes den til main.
import java.io.*;

public class FindLetterInFile {
    public static void main(String[] args) throws IOException {
      boolean result;
      result = lookForLetter(new FileReader(new File(args[0])), args[1]);
      if (result)
        System.out.println("We found the letter: " + args[1]);
      else
        System.out.println("No such letter: " + args[1]);
    }
      
    public static boolean lookForLetter(FileReader in, String letter) throws IOException {
        int c;
        try{
          do{
             c = in.read();
             if (c == letter.charAt(0))
               return(true);
          } while (c != -1);  
        }
        finally{
          in.close();
          System.out.println("Vi lukker filen");
        };  // end try
        return(false); // not found

    }
}

Program: Illustration af finally i forhold til break. I en while løkke fra i løbende fra 0 til 9 bryder vi løkken når i bliver 5. I hver udførelse af try-finally aktiveres udskrivninger både i try og finally delen naturligvis. Når i bliver 5 kaldes break, men vi kan ikke komme ud af try-finally uden også at udføre finally den sidste gang (altså for i == 5).
class FinallyBreak {

  public static void main(String[] args){

    int i = 0;

    while (i < 10){
      try{
        i = i + 1;
        System.out.println("Gentagelse for i = " + i);
        if (i == 5) break;
      }
      finally{
        System.out.println("Slutning med i = " + i);
      } // end try
    }
    System.out.println("Løkken slut");
  }
}

Program: Output af ovenstående program. Bemærk specielt det med rødt fremhævede som stammer fra finally konstruktionens udførelse efter at løkken er brudt med break kommandoen
Gentagelse for i = 1
Slutning med i = 1
Gentagelse for i = 2
Slutning med i = 2
Gentagelse for i = 3
Slutning med i = 3
Gentagelse for i = 4
Slutning med i = 4
Gentagelse for i = 5
Slutning med i = 5
Løkken slut

Program: Illustration af finally i forhold til continue. Eksemplet minder om break eksemplet ovenfor. Variablen i løber igen fra 0 til 9. Når i er lige afbrydes løkken med continue, hvilket bevirker at vi umiddelbart går til den næste i værdi i gennemløbet. Men uanset om i er lige eller ulige vil finally-delen blive udført.
class FinallyContinue {

  public static void main(String[] args){

    int i = 0;

    while (i < 10){
      try{
        i = i + 1;
        System.out.println("Gentagelse for i = " + i);
        if (even(i)) continue;
        System.out.println("Løkke beregninger med i = " + i);
      }
      finally{
        System.out.println("Løkkeafslutning med i = " + i);
      } // end try
    }
    System.out.println("Løkken slut");
  }

  public static boolean even(int i){
   return (i % 2 == 0);
  }

}

Program: Output af ovenstående program. Løkkegennemløb med en lige værdi af variablen i afbrydes midtvejs. Men uanset om i er lige eller ulige afsluttes løkken i finally blokken. De med rødt fremhævede liner stammer fra finally konstruktionen udført i de tilfælde, hvor løkken er blevet 'fortsat' med kald af continue
Gentagelse for i = 1
Løkke beregninger med i = 1
Løkkeafslutning med i = 1
Gentagelse for i = 2
Løkkeafslutning med i = 2
Gentagelse for i = 3
Løkke beregninger med i = 3
Løkkeafslutning med i = 3
Gentagelse for i = 4
Løkkeafslutning med i = 4
Gentagelse for i = 5
Løkke beregninger med i = 5
Løkkeafslutning med i = 5
Gentagelse for i = 6
Løkkeafslutning med i = 6
Gentagelse for i = 7
Løkke beregninger med i = 7
Løkkeafslutning med i = 7
Gentagelse for i = 8
Løkkeafslutning med i = 8
Gentagelse for i = 9
Løkke beregninger med i = 9
Løkkeafslutning med i = 9
Gentagelse for i = 10
Løkkeafslutning med i = 10
Løkken slut

Hvis vi anvender den grove måde at stoppe et program på, System.exit(0), forbigår vi alle finally konstruktioner. System.exit bør således undgås når andre midler er tilgængelige for programafslutning

Det giver mening at have en try-finally konstruktion uden catches

Reference

Erklæring af exceptions i metoder
Slide Note Contents Index
References Speak
Som et centralt element diskuterer vi her en udvidelse af den måde vi erklærer metoder, der videregiver ikke håndterede execeptions

Metoder som returnerer uden at håndtere checked exceptions skal annoncere dette i forbindelse med metodens definition

Java compileren checker om en metode 'efterlader' checked exceptions uhåndterede

Syntax: Syntaks for en metode definition med throw erklæringer. Det nye element, i forhold til hvad vi tidligere har set, er den anden linie som erklærer at metoden kan kaste bestemte typer af exceptions

egenskabsListe returType metodeNavn (parametre) 
         throws exceptionType-1, exceptionType-2 ... {   
  metodeKrop
}

Program: Et Java program med fokus på erklærede exceptions i metoder. Vi har tidligere i lektionen set på det samme program, nemlig i forbindelse med propagering af exceptions. Hvorfor skal main erklære, at der kastes en exception? Fordi p tilsyneladende kan give anledning til en exception. Men hvorfor specificerer p at der kan forekomme en exception - p håndterer jo netop en undtagelse i en try! Det er fordi at q(false) kaldet i catch delen kan afstedkomme en exception.
public class ExceptionDemo{
  
  public static void main(String[] args) throws DemoException{
   ExceptionDemo object = new ExceptionDemo();
   System.out.println("metoden main");
   object.p();
  }

  public void p() throws DemoException{ 
   System.out.println("metoden p");
   try{
     q(true);
   }
   catch (DemoException e){
     System.out.println(e);
     System.out.println("Reparation i p");
     q(false); // false means better version
   }
  }

  public void q(boolean b) throws DemoException{  
   System.out.println("metoden q");
   r(b); 
  }

  public void r(boolean b) throws DemoException{   
   System.out.println("metoden r");
   s(b);
  }

  public void s(boolean b) throws DemoException{    
   System.out.println("metoden s");
   if (b)
     throw (new DemoException("Vi har et problem"));
   else 
     System.out.println("Nu går det bedre i s");
  }
}

class DemoException extends Exception{
  
  public DemoException(String problem){
    super(problem);
  }

}

Reference

Exceptions: Fristelser og byrder
Slide Note Contents Index
References Speak
Exceptions er ikke altid en velsignelse for de programmører, som skal anvender klasser hvori metoderne kaster exceptions. Her ser vi på problemet

  • Håndter undtagelsen tæt på fejlkilden for at undgå at skulle skrive mange metoder med erklærede undtagelseskast

  • 'Dyk en exception' ved en pseudo-håndtering for at blive fri for at erklære den i direkte og indirekte klienter

  • Benyttelse af unchecked RuntimeExceptions i stedet for checked exceptions

  • Benyttelse af (unchecked) exceptions til at flytte kontrollen (hoppe) langs den dynamiske kæde af metodekald.

For god ordens skyld skal det bemærkes, at ovenstående fristelser bør modstås i de Java programmer, vi skriver

En programmør kan være fristet til at arbejde med unchecked exceptions for at blive fri for at erklærede exceptions i metode signaturer


Undtagelseshåndtering i forlængelse af kontraktbegrebet

Kontrakter og undtagelser
Slide Note Contents Index
References Speak
Vi har i en tidligere lektion studeret kontraktbegrebet. Vi vil her gøre historien om kontrakter færdig i den specialsituation hvor kontrakten brydes

Kontraktbrud bringer et program i en undtagelsessituation

Et kontraktbrud foranlediger et implicit kast af en exception

  • Kontraktbrud i en metode m i en klassen C:

    • Prebetingelsen af m er falsk

      • Klienten af m fejler

    • Postbetingelsen af m er falsk

      • m fejler

    • Invarianten af C er falsk

      • m fejler

Reference

En operation kan lykkes eller fejle
Slide Note Contents Index
References Speak
Når vi arbejder med metoder som er specificeret med pre- og postbetingelser har vi et godt grundlag til at definere success og fiasko. Vi vil benytte ordene hhv. 'at operationen lykkes' og 'operationen fejler'

The concept operation lykkes: En operation lykkes hvis den efterlader programmet i en tilstand der opfylder postbetingelsen og klassens invariantVi siger at en operation lykkes hvis den opfylder kontrakten, når operationen er kørt til ende. At opfylde kontrakten i denne situation betyder at postbetingelsen skal være sand, samt at klasseinvarianten i den klasse, hvor metoden befinder sig, skal være sand
The concept operation fejler: En operation siges at fejle hvis den ikke lykkesSom en naturlig modsætning siger vi at operationen fejler hvis den ikke lykkes

Hvis en prebetingelse af en metode m brydes (bliver falsk) fejler den metode, som har kaldt m

  • Kun to muligheder

    • En operation lykkes - kontrakten er overholdt

      • Programmet befinder sig i en normalsituation

    • En operation fejler - kontrakten er brudt

      • Programmet befinder sig i en undtagelsessituation

      • Exceptionhandling (langs kæden af kald) kan bringe programmet tilbage i normalsituationen

En operation med en ikke-trivielt opfyldt postbetingelse uden exception handling svarer til en metode i Java som erklærer at den kan kaste exceptions

Hvis en metode har en postbetingelse der ikke blot er 'true' betyder det, at under visse omstændigheder vil postbetingelsen kunne brydes. Dette forårsager en exception, som måske skal håndteres uden for metoden. Metoderne på den dynamiske kæde af kald får chancen for at håndtere undtagelsen inden programmet evt. stopper sin udførelse.

Exceptionhandling i en Eiffel routine
Slide Note Contents Index
References Speak
Vi viser her en en illustration af en routine (metode) i Eiffel, som har både pre- og postbetingelser. Vi fokuserer på de forskellige muligheder for success (lykkes) og failure (fejle)

Figure.
    Der opstår et exception. Rescue-konstruktionen aktiveres Efter reparation genudføres operationen, hvori exception opstod. Det anbefales af klasse-invarianten and pre-op opfyldes Operationen fejler. Klasse-invarianten skal være opfyldt Operationen lykkes. Klasse-invarianten and post-betingelsen skal være opfyldt

I Eiffel er scopet for undtagelseshåndtering en hel metode

Hvis en metode fejler skal invarianten alligevel opfyldes

I Eiffel er et exception ikke et (første klasses) objekt


Collected references
Contents Index
Java tutorial: Handling Errors with Exceptions
The reference above goes to a Java Tutorial pageThe references above goes to material on the Internet
Første møde med kopieringsprogrammet
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Det overansvarlige program
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Java's samlede klassehierarki
The reference from above goes to Java API pageThe references above goes to material on the Internet
Java's exception hierarki som en del af klassehierarkiet i java.lang
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen Error i java.lang
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen Throwable i java.lang
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen IOException i java.io
The reference from above goes to Java API pageThe references above goes to material on the Internet
Klassen RuntimeException i java.lang
The reference from above goes to Java API pageThe references above goes to material on the Internet
Metoden substring i klassen String
The reference from above goes to Java API pageThe references above goes to material on the Internet
Den statiske metode parseInt i klassen Integer
The reference from above goes to Java API pageThe references above goes to material on the Internet
Oversigt over break, continue og return i Java
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Om definition af metoder i klasser fra tidligere lektion
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes
Kontraktbegrebet
The reference above goes to a lecture note pageThe reference above points to an earlier page in the lecture notes

 

Chapter 10: Undtagelseshåndtering
Course home     Author home     About producing this web     Previous lecture (top)     Next lecture (top)     Previous lecture (bund)     Next lecture (bund)     
Generated: March 31, 2008, 12:09:11