



<html>
<head>
  <title>javabog.dk -  - Undtagelser og k&oslash;retidsfejl</title>
  <link rev="stylesheet" type="text/css" href="../typografi.css">
  <meta name="description" content="Lærebog i Java. Af Jacob Nordfalk. Udkommet hos Forlaget Globe">
  <meta name="keywords" content="designmønster, programmering, OOP, objekter, klasser, objektorienteret programmering, Java, JSP, lærebog, UML, IT">
</head>
<body bgcolor="#ffffff">



<a href='http://javabog.dk/'>javabog.dk</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel13.jsp'>&lt;&lt; forrige</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='indhold.jsp'>indhold</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel15.jsp'>n&aelig;ste &gt;&gt;</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kode/'>programeksempler</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='../index_OOP.html'>om bogen</a>

<H1 CLASS="western" STYLE="">14 <a name='afsn14'></a>Undtagelser
og k&oslash;retidsfejl</H1>
<P LANG="da-DK" CLASS="kapiteloversigt-western">Indhold:</P>
<UL>
  <LI VALUE=1><P LANG="da-DK" CLASS="kapiteloversigt-western">Forst&aring;
  stakspor</P>
  <LI><P LANG="da-DK" CLASS="kapiteloversigt-western">Fange
  undtagelser og udskrive stakspor</P>
  <LI><P LANG="da-DK" CLASS="kapiteloversigt-western">Sende
  undtagelser videre og h&aring;ndtere dem det rigtige sted</P>
</UL>
<P LANG="da-DK" CLASS="kapiteloversigt-western">Kapitlet foruds&aelig;ttes
i resten af bogen og evnen til at kunne l&aelig;se et stakspor er
vigtig, n&aring;r man skal finde fejl i sit program.</P>
<P LANG="da-DK" CLASS="kapiteloversigt-western">Foruds&aelig;tter
<a href='kapitel4.jsp'>kapitel 4</a>, Definition af klasser (<a href='kapitel5.jsp'>kapitel 5</a>, Nedarvning er en
fordel).</P>


<P LANG="da-DK" CLASS="western" STYLE="">Som
programm&oslash;r skal man tage h&oslash;jde for fejlsituationer, som
kan opst&aring;, n&aring;r programmet udf&oslash;res. Det g&aelig;lder
f.eks. inddata fra brugeren, der kan v&aelig;re anderledes, end man
forventede (brugeren indtaster f.eks. bogstaver et sted, hvor
programmet forventer tal) og adgang til ydre enheder, som kan v&aelig;re
utilg&aelig;ngelige, f.eks. filer, printere og netv&aelig;rket.</P>
<P LANG="da-DK" CLASS="western">Hvis programmet pr&oslash;ver at
udf&oslash;re en ulovlig handling, vil der opst&aring; en <I>undtagelse</I>
(eng.:&nbsp;exception) og programudf&oslash;relsen vil blive afbrudt
p&aring; det sted, hvor undtagelsen opstod.</P>
<P LANG="da-DK" CLASS="western">Lad os unders&oslash;ge n&aelig;rmere,
hvad der sker. Herunder pr&oslash;ver vi at indeksere ud over en
listes gr&aelig;nser:</P>
<OL>
  <LI><PRE CLASS="kode-m-linienr--western">import java.util.*;</PRE>
  <LI><PRE CLASS="kode-m-linienr--western"></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">public class SimpelUndtagelse</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">{</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  public static void main(String[] arg)</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  {</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    System.out.println(&quot;Punkt A&quot;);       <I>// punkt A</I></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    ArrayList l = new ArrayList();</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    System.out.println(&quot;Punkt B&quot;);       <I>// punkt B</I></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    l.get(5);</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    System.out.println(&quot;Punkt C&quot;);       <I>// punkt C</I></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  }</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">}</PRE>
</OL>
<HR>
<PRE CLASS="kode-western">Punkt A
Punkt B
java.lang.ArrayIndexOutOfBoundsException: 5 &gt;= 0
  at java.util.ArrayList.get(ArrayList.java:417)
  at SimpelUndtagelse.main(SimpelUndtagelse.java:10)
Exception in thread &quot;main&quot;</PRE><P LANG="da-DK" CLASS="western">
N&aring;r vi k&oslash;rer programmet, kan vi se, at det stopper
mellem punkt B og C med en fejl:</P>
<PRE CLASS="kode-western">java.lang.ArrayIndexOutOfBoundsException: 5 &gt;= 0</PRE><P LANG="da-DK" CLASS="western">
Den efterf&oslash;lgende kode udf&oslash;res ikke og vi n&aring;r
aldrig punkt C.</P>
<BLOCKQUOTE LANG="da-DK" CLASS="definition-western">Programudf&oslash;relsen
afbrydes, n&aring;r der opst&aring;r en undtagelse</BLOCKQUOTE>
<P LANG="da-DK" CLASS="western">I dette kapitel vil vi illustrere,
hvordan undtagelser opst&aring;r og hvordan de h&aring;ndteres. Af
plads- og overskuelighedshensyn er eksemplerne ret sm&aring; og
undtagelsesh&aring;ndtering derfor ikke specielt n&oslash;dvendig.
Man skal forestille sig st&oslash;rre situationer, hvor der opst&aring;r
fejl, der ikke lige er til at gennemskue (i dette eksempel kunne der
v&aelig;re meget mere kode ved punkt B).</P>
<P LANG="da-DK" CLASS="western">Man kan t&aelig;nke p&aring;
undtagelser som en slags protester. Indtil nu har vi regnet med, at
objekterne p&aelig;nt &quot;parerede ordre&quot;, n&aring;r vi
gav dem kommandoer eller sp&oslash;rgsm&aring;l (kaldte metoder).
Fra nu af kan metoderne &quot;sp&aelig;nde ben&quot; og afbryde
programudf&oslash;relsen, hvis situationen er uacceptabel.</P>
<P LANG="da-DK" CLASS="western">Det er det, som get(5) p&aring; den
tomme ArrayList g&oslash;r: Som svar p&aring; &quot;giv mig element
nummer 5&quot; kaster den ArrayIndexOutOfBoundsException og siger &quot;5
&gt;= 0&quot;, dvs. &quot;det kan jeg ikke, for 5 er st&oslash;rre
end antallet af elementer i listen, som er 0!&quot;.</P>
<H2 CLASS="western" STYLE="">14.1 <a name='afsn14.1'></a>Almindelige
undtagelser</SPAN></H2>
<P LANG="da-DK" CLASS="western">Ud over
ArrayIndexOutOfBoundsException som beskrevet ovenfor kan der opst&aring;
en r&aelig;kke andre fejlsituationer. De mest almindelige er kort
beskrevet nedenfor.</P>
<P LANG="da-DK" CLASS="western">Der opst&aring;r en undtagelse af
typen NullPointerException, hvis man kalder metoder p&aring; en
variabel, der ingen steder refererer hen (en objektreference, der er
null):</P>
<PRE CLASS="kode-western" STYLE="font-weight: medium">    ArrayList l = null;
    l.add(&quot;x&quot;);</PRE>
<HR>
<PRE CLASS="kode-western">Exception in thread &quot;main&quot; java.lang.<B>NullPointerException</B>
        at SimpelUndtagelse.main(SimpelUndtagelse.java:6)</PRE>
<P LANG="da-DK" CLASS="western">Hvis man laver aritmetiske
udregninger, kan der opst&aring; undtagelsen ArithmeticException,
f.eks. ved division med nul:</P>
<PRE CLASS="kode-western" STYLE="font-weight: medium">    int a = 5;
    int b = 0;
    System.out.print(a/b);</PRE>
<HR>
<PRE CLASS="kode-western">Exception in thread &quot;main&quot; java.lang.<B>ArithmeticException: / by zero</B>
        at SimpelUndtagelse.main(SimpelUndtagelse.java:7)</PRE>
<P LANG="da-DK" CLASS="western">ClassCastException opst&aring;r, hvis
man pr&oslash;ver at typekonvertere en objektreference til en type,
som objektet ikke er, f.eks. en Gade til et Rederi:</P>
<PRE CLASS="kode-western">    Felt f = new Gade(&quot;Gade 2&quot;, 10000, 400, 1000);
    Rederi r = (Rederi) f;</PRE>
<HR>
<PRE CLASS="kode-western">Exception in thread &quot;main&quot; java.lang.<B>ClassCastException: Gade</B>
        at SimpelUndtagelse.main(SimpelUndtagelse.java:6)</PRE><H2 CLASS="western">
14.2 <a name='afsn14.2'></a>At fange og h&aring;ndtere undtagelser</SPAN></H2>
<P LANG="da-DK" CLASS="western">Undtagelser kan fanges og h&aring;ndteres.
Det g&oslash;res ved at indkapsle den kritiske kode i en try-blok og
behandle eventuelle undtagelser i en catch-blok:</P>
<PRE CLASS="kode-western">  try 
  {
<I>    ...                     // programkode hvor der er en risiko</I>
<I>    ...                     // for at en undtagelse opst&aring;r</I>
  }
<SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: medium">  catch (</SPAN></SPAN><I><SPAN STYLE="font-weight: medium">Undtagelsestype</SPAN></I><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: medium"> u) </SPAN></SPAN><I><SPAN STYLE="font-weight: medium">// undtagelsen der skal fanges, f.eks. Exception</SPAN></I>
  {
<I>    ...                     // kode som h&aring;ndterer fejl af</I>
<I>    ...                     // typen </I>Undtagelsestype
  }
<I>  ...                       // dette udf&oslash;res b&aring;de hvis ingen undtagelse opstod</I>
<I>  ...                       // og hvis der opstod fejl af typen </I><SPAN STYLE="font-style: normal">Undtagelsestype</SPAN></PRE><P LANG="da-DK" CLASS="western">
N&aring;r programmet k&oslash;rer normalt, springes catch-blokken
over. Hvis der opst&aring;r undtagelser i try-blokken, hoppes ned i
catch-blokken, der h&aring;ndterer fejlen og derefter udf&oslash;res
koden efter catch. 
</P>
<P LANG="da-DK" CLASS="western">Undtagelsestypen bestemmer, hvilke
slags undtagelser der fanges<A CLASS="sdfootnoteanc" NAME="sdfootnote1anc" HREF="#sdfootnote1sym"><SUP>1</SUP></A>.
</P>
<P LANG="da-DK" CLASS="western">Man kan fange alle slags ved at
angive en generel undtagelse, f.eks. Exception, eller kun fange en
bestemt slags undtagelser, f.eks. ArrayIndexOutOfBoundsException.</P>
<P LANG="da-DK" CLASS="western" STYLE="">Ser
vi p&aring; vores ArrayList-eksempel igen, kunne det med
undtagelsesh&aring;ndtering se ud som:</P>
<OL START=14>
  <LI><PRE CLASS="kode-m-linienr--western">import java.util.*;</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">public class SimpelUndtagelse2</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">{</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  public static void main(String[] arg)</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  {</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    System.out.println(&quot;Punkt A&quot;);               <I>// punkt A</I></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    try </PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    {</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">      ArrayList l = new ArrayList();</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">      System.out.println(&quot;Punkt B&quot;);           <I>// punkt B</I></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">      l.get(5);</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">      System.out.println(&quot;Punkt C&quot;);           <I>// punkt C</I></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    }</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    catch (Exception u)</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    {</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">      System.out.println(&quot;Der opstod en undtagelse!&quot;);</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    }</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    System.out.println(&quot;Punkt D&quot;);             <I>// punkt D</I></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  }</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">}</PRE>
</OL>
<HR>
<PRE CLASS="kode-western">Punkt A
Punkt B
Der opstod en undtagelse!
Punkt D</PRE><P LANG="da-DK" CLASS="western">
L&aelig;g m&aelig;rke til, at punkt C (der ligger i try-blokken,
efter at undtagelsen opstod) ikke bliver udf&oslash;rt. Punkt D
(efter catch-blokken) bliver udf&oslash;rt under alle omst&aelig;ndigheder.</P>
<H3 CLASS="western">14.2.1 <a name='afsn14.2.1'></a>Undtagelsesobjekter og deres stakspor</H3>
<P LANG="da-DK" CLASS="western">En undtagelse er, ligesom alt andet i
Java, repr&aelig;senteret ved et objekt. En reference til dette
undtagelses-objekt overf&oslash;res som parameter til catch-blokken. 
</P>
<P LANG="da-DK" CLASS="western">Objektet har nyttige informationer om
fejlen. Metoden printStackTrace() udskriver et stakspor<SPAN STYLE="font-style: normal">
(</SPAN>eng.: stack trace), der beskriver de metodekald, der f&oslash;rte
til, at undtagelsen opstod:</P>
<PRE CLASS="kode-western">    ...
    catch (Exception u)
    {
      System.out.println(&quot;Der opstod en undtagelse!&quot;);
<B>      u.printStackTrace()</B>;
    }
    ...</PRE>
<HR>
<PRE CLASS="kode-western">Punkt A
Punkt B
Der opstod en undtagelse!
java.lang.ArrayIndexOutOfBoundsException: 5 &gt;= 0
        at java.util.ArrayList.get(ArrayList.java:441)
        at SimpelUndtagelse2.main(<B>SimpelUndtagelse2.java:11</B>)
Punkt D</PRE><P LANG="da-DK" CLASS="western">
Staksporet er nyttigt, n&aring;r man skal finde ud af, hvordan fejlen
opstod. Det viser pr&aelig;cist, at undtagelsen opstod i get() i
ArrayList, som blev kaldt fra SimpelUndtagelse2.java i main()-metoden
linje 11.</P>

<H2 CLASS="western" STYLE="">14.3 <a name='afsn14.3'></a>Undtagelser
med tvungen h&aring;ndtering</SPAN></H2>
<P LANG="da-DK" CLASS="western">Indtil nu har overs&aelig;tteren
accepteret vores programmer, hvad enten vi h&aring;ndterede
eventuelle undtagelser eller ej, dvs. det var helt frivilligt,
om vi ville tage h&oslash;jde for de mulige fejlsituationer. 
</P>
<P LANG="da-DK" CLASS="western">Imidlertid er der nogle handlinger,
der kr&aelig;ver h&aring;ndtering, bl.a.:</P>
<UL>
  <LI><P LANG="da-DK" CLASS="western">l&aelig;sning og skrivning af
  filer (kaster bl.a.: FileNotFoundException, IOException)</P>
  <LI><P LANG="da-DK" CLASS="western">netv&aelig;rkskommunikation
  (UnknownHostException, SocketException, IOException)</P>
  <LI><P LANG="da-DK" CLASS="western">databaseforesp&oslash;rgsler
  (SQLException)</P>
  <LI><P LANG="da-DK" CLASS="western">indl&aelig;sning af klasser
  (ClassNotFoundException)</P>
</UL>
<P LANG="da-DK" CLASS="western">N&aring;r programm&oslash;ren kalder
metoder, der kaster disse undtagelser, <I>skal</I> han fange dem.</P>

<H3 CLASS="western">14.3.1 <a name='afsn14.3.1'></a>Fange undtagelser eller sende dem videre</H3>
<P LANG="da-DK" CLASS="western">Som eksempel vil vi indl&aelig;se en
linje fra tastaturet og udskrive den p&aring; sk&aelig;rmen:</P>
<PRE CLASS="ikke-javakode-western">import java.io.*;
public class TastaturbrugerFejl 
{
  public static void main(String[] arg) 
  {
    BufferedReader ind = new BufferedReader(new InputStreamReader(System.in));
    String linje;
    linje = ind.readLine();
    System.out.println(&quot;Du skrev: &quot;+linje);
  }
}</PRE><P LANG="da-DK" CLASS="western">
Metoden readLine() l&aelig;ser en linje fra datastr&oslash;mmen
(tastaturet), men n&aring;r den udf&oslash;res, kan der opst&aring;
undtagelsen IOException<A CLASS="sdfootnoteanc" NAME="sdfootnote2anc" HREF="#sdfootnote2sym"><SUP>2</SUP></A>.
</P>
<P LANG="da-DK" CLASS="western">Overs&aelig;tteren tvinger os til at
tage h&oslash;jde for den mulige undtagelse:</P>
<PRE CLASS="kode-western">TastaturbrugerFejl.java:8: unreported exception java.io.IOException; must be caught or declared to be thrown
    linje = ind.readLine();</PRE><P LANG="da-DK" CLASS="western">
Fejlmeddelelsen ville p&aring; dansk lyde: &quot;I
TastaturbrugerFejl.java linje 8 er der en uh&aring;ndteret undtagelse
IOException; den skal fanges, eller det skal erkl&aelig;res, at den
bliver kastet&quot;:</P>

<P LANG="da-DK" CLASS="western">Vi er alts&aring; tvunget til<SPAN STYLE="font-style: normal">
</SPAN><SPAN STYLE="font-style: normal"><SPAN STYLE="font-weight: medium">enten</SPAN></SPAN><SPAN STYLE="font-style: normal">
</SPAN>at:</P>
<P LANG="da-DK" CLASS="western"> <I>1) fange undtagelsen</I> ved at
indkapsle koden i en try-catch-blok, f.eks.:</P>
<PRE CLASS="kode-western"><B>    try {</B>
      linje = ind.readLine();
      System.out.println(&quot;Du skrev: &quot;+linje);
<B>    } catch (Exception u) {</B>
      u.printStackTrace();
<B>    }</B></PRE>

<P LANG="da-DK" CLASS="western" STYLE="font-style: normal; font-weight: medium; ">
... eller:</P>
<P LANG="da-DK" CLASS="western"> <I><SPAN STYLE="font-weight: medium">2)</SPAN></I><I>
erkl&aelig;re, at den bliver kastet</I><SPAN STYLE="font-style: normal">,
dvs. at den kan opst&aring; i main()-metoden. Det g&oslash;r man med
ordet </SPAN><I>throws</I>:</P>
<PRE CLASS="kode-western">  public static void main(String[] arg) <B>throws IOException</B></PRE><P LANG="da-DK" CLASS="western">
Det sidste signalerer, at hvis undtagelsen opst&aring;r, skal metoden
afbrydes helt og kalderen m&aring; h&aring;ndtere fejlen (i dette
tilf&aelig;lde er det systemet, der har kaldt main(), men oftest vil
det v&aelig;re os selv).</P>

<BLOCKQUOTE LANG="da-DK" CLASS="definition-western">Undtagelser med
tvungen h&aring;ndtering skal enten fanges (med try-catch i
metodekroppen) eller sendes videre til kalderen (med throws i
metodehovedet)</BLOCKQUOTE>

<H3 CLASS="western">14.3.2 <a name='afsn14.3.2'></a>Konsekvenser af at sende undtagelser videre</H3>
<P LANG="da-DK" CLASS="western">Det har konsekvenser at sende
undtagelser videre, for da skal kalderen h&aring;ndtere dem. 
</P>
<P LANG="da-DK" CLASS="western"><IMG SRC="bog15_html_m25399528.gif" NAME="Objekt63" ALIGN=RIGHT>Eksempel:
Lad os sige, at vi har uddelegeret l&aelig;sningen fra tastaturet til
en separat Tastatur-klasse, der kan l&aelig;se en linje fra
tastaturet med l&aelig;sLinje() eller l&aelig;se en linje og oms&aelig;tte
den til et tal med l&aelig;sTal():</P>
<OL START=34>
  <LI><PRE CLASS="kode-m-linienr--western">import java.io.*;</PRE>
  <LI><PRE CLASS="kode-m-linienr--western"></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">public class Tastatur</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">{</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  private BufferedReader ind;</PRE>
  <LI><PRE CLASS="kode-m-linienr--western"></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  public Tastatur()</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  {</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    ind = new BufferedReader(new InputStreamReader(System.in));</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  }</PRE>
  <LI><PRE CLASS="kode-m-linienr--western"></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  public String l&aelig;sLinje()</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  {</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    try {</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">      String linje = ind.readLine();</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">      return linje;</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    } catch (IOException u)</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    {</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">      u.printStackTrace();</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    }</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    return null;</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  }</PRE>
  <LI><PRE CLASS="kode-m-linienr--western"></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  public double l&aelig;sTal()</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  {</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    String linje = l&aelig;sLinje();</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    return Double.parseDouble(linje);</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  }</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">}</PRE>
</OL>
<P LANG="da-DK" CLASS="western">Herover fanger vi undtagelsen
IOException ved dens &quot;rod&quot; i l&aelig;sLinje().</P>

<P LANG="da-DK" CLASS="western">Den kunne g&oslash;res simplere ved
at fjerne h&aring;ndteringen og erkl&aelig;re IOException kastet:</P>
<PRE CLASS="kode-western">  public String l&aelig;sLinje() throws IOException
  {
    String linje = ind.readLine();
    return linje;
  }</PRE><P LANG="da-DK" CLASS="western">
Nu sender l&aelig;sLinje() undtagelserne videre, s&aring; nu er det
kalderens problem at h&aring;ndtere den.</P>


<P LANG="da-DK" CLASS="western">Vi kalder selv metoden fra l&aelig;sTal(),
s&aring; her er vi nu enten n&oslash;dt til at fange eventuelle
undtagelser:</P>
<PRE CLASS="kode-western">  public double l&aelig;sTal()
  {
    try {
      String linje = l&aelig;sLinje();
      return Double.parseDouble(linje);
    } catch (IOException u)
    {
      u.printStackTrace();
    }
    return 0;
  }</PRE><P LANG="da-DK" CLASS="western">
... eller igen sende dem videre. 
</P>
<P LANG="da-DK" CLASS="western">Herunder er Tastatur igen, men
IOException kastes nu videre fra begge metoder.</P>
<PRE CLASS="kode-western">import java.io.*;

public class TastaturKasterUndtagelser
{
  private BufferedReader ind;

  public TastaturKasterUndtagelser()
  {
    ind = new BufferedReader(new InputStreamReader(System.in));
  }

  public String l&aelig;sLinje()<B> throws IOException</B>
  {
    String linje = ind.readLine();
    return linje;
  }

  public double l&aelig;sTal()<B> throws IOException</B>
  {
    String linje = l&aelig;sLinje();
    return Double.parseDouble(linje);
  }
}</PRE><P LANG="da-DK" CLASS="western">
Om man skal fange undtagelser eller lade dem &quot;ryge videre&quot;
afh&aelig;nger af, om man selv kan h&aring;ndtere dem fornuftigt,
eller kalderen har brug for at f&aring; at vide, at noget gik galt.</P>
<P LANG="da-DK" CLASS="western">Hvad sker der f.eks. i Tastatur, hvis
der opst&aring;r en undtagelse i l&aelig;sLinje() kaldt fra
l&aelig;sTal()?</P>
<P LANG="da-DK" CLASS="western">Jo, l&aelig;sLinje() returnerer en
null-reference til l&aelig;sTal(), der sender denne reference til
parseDouble(), der sandsynligvis &quot;protesterer&quot; med en
NullPointerException, for man kan ikke konvertere null til et
tal. Der opst&aring;r alts&aring; en f&oslash;lgefejl, fordi vi
forts&aelig;tter, som om intet var h&aelig;ndt.</P>
<P LANG="da-DK" CLASS="western">I dette tilf&aelig;lde m&aring;
TastaturKasterUndtagelser alts&aring; siges at v&aelig;re bedst,
selvom den alts&aring; giver kalderen mere arbejde.</P>
<H2 CLASS="western" STYLE="">14.4 <a name='afsn14.4'></a>Pr&aelig;cis
h&aring;ndtering af undtagelser</SPAN></H2>
<P LANG="da-DK" CLASS="western">Det kan have v&aelig;sentlige
konsekvenser, p&aring; hvilket niveau undtagelserne fanges, selv
inden for samme metode. 
</P>
<P LANG="da-DK" CLASS="western">Lad os bruge Tastatur til at lave et
lille regneprogram, der l&aelig;gger tal sammen. Vi sp&oslash;rger
f&oslash;rst brugeren, hvor mange tal det skal v&aelig;re (med
l&aelig;sTal()) og derefter kan han taste tallene ind. Til sidst
sp&oslash;rger vi, om han vil pr&oslash;ve igen. 
</P>
<OL START=63>
  <LI><PRE CLASS="kode-m-linienr--western">public class SumMedTastatur</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">{</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  public static void main(String[] arg)</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  {</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    Tastatur t = new Tastatur();</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    boolean stop = false;</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    <B>try</B> </PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    <B>{</B></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">      while (!stop)</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">      {</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">        System.out.print(&quot;Hvor mange tal vil du l&aelig;gge sammen? &quot;);</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">        double antalTal = t.l&aelig;sTal();</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">        double sum = 0;</PRE>
  <LI><PRE CLASS="kode-m-linienr--western"></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">        for (int i=0; i&lt;antalTal; i=i+1)</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">        {</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">          System.out.print(&quot;Indtast tal: &quot;);</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">          sum = sum + t.l&aelig;sTal();</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">        }</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">        System.out.println(&quot;Summen er: &quot;+sum);</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">        System.out.print(&quot;Vil du pr&oslash;ve igen (j/n)? &quot;);</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">        if (&quot;n&quot;.equals(t.l&aelig;sLinje())) stop = true; <I>// unders&oslash;g om det er &quot;n&quot;</I></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">      }</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    <B>}   catch (Exception u) {</B></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    <B>  System.out.println(&quot;Der opstod en undtagelse!&quot;);</B></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    <B>  u.printStackTrace();</B></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">    <B>}</B></PRE>
  <LI><PRE CLASS="kode-m-linienr--western">  }</PRE>
  <LI><PRE CLASS="kode-m-linienr--western">}</PRE>
</OL>
<HR>
<PRE CLASS="kode-western">Hvor mange tal vil du l&aelig;gge sammen? 2
Indtast tal: 1
Indtast tal: 2
Summen er: 3.0
Vil du pr&oslash;ve igen (j/n)? j
Hvor mange tal vil du l&aelig;gge sammen? 3
Indtast tal: 1
Indtast tal: 3
Indtast tal: 5
Summen er: 9.0
Vil du pr&oslash;ve igen (j/n)? n</PRE><P LANG="da-DK" CLASS="western">
Brugeren taster og taster ... men hvad sker der, hvis han taster
forkert?</P>
<PRE CLASS="kode-western">Hvor mange tal vil du l&aelig;gge sammen? 3
Indtast tal: 1
Indtast tal: 17xx&oslash;f&oslash;f
Der opstod en undtagelse!
java.lang.NumberFormatException: 17xx&oslash;f&oslash;f
        at java.lang.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1182)
        at java.lang.<B>Double.parseDouble</B>(Double.java:190)
        at Tastatur.l&aelig;sTal(<B>Tastatur.java:27</B>)
        at SumMedTastatur.main(<B>SumMedTastatur.java:18</B>)</PRE><P LANG="da-DK" CLASS="western">
Her opstod en anden undtagelse: 17xx&oslash;f&oslash;f kunne ikke
konverteres til et tal. Igen er staksporet nyttigt til at finde
fejlen (l&aelig;st nedefra og op viser det, at main() i linje 18
kaldte l&aelig;sTal(), der i linje 27 kaldte parseDouble(), der er en
del af standardbiblioteket<A CLASS="sdfootnoteanc" NAME="sdfootnote3anc" HREF="#sdfootnote3sym"><SUP>3</SUP></A>).
</P>
<P LANG="da-DK" CLASS="western">Programmet afslutter, da
try-catch-blokken er yderst. En smartere opf&oslash;rsel ville v&aelig;re,
at den igangv&aelig;rende sum blev afbrudt og brugeren blev bedt om
at starte forfra. 
</P>

<P LANG="da-DK" CLASS="western">Det kan vi opn&aring; ved at have
try-catch <I>inde</I> i while-l&oslash;kken:</P>
<PRE CLASS="kode-western">public class SumMedTastatur2
{
  public static void main(String[] arg)
  {
    Tastatur t = new Tastatur();
    boolean stop = false;

    while (!stop)
    {
      System.out.print(&quot;Hvor mange tal vil du l&aelig;gge sammen? &quot;);
<B>      try </B>
<B>      {</B>
        double antalTal = t.l&aelig;sTal();
        double sum = 0;

        for (int i=0; i&lt;antalTal; i=i+1)
        {
          System.out.print(&quot;Indtast tal: &quot;);
          sum = sum + t.l&aelig;sTal();
        }
        System.out.println(&quot;Summen er: &quot;+sum);
<B>      }   catch (Exception u) {</B>
<B>        System.out.println(&quot;Indtastningsfejl - &quot; + u);</B>
<B>      }</B>
      System.out.print(&quot;Vil du pr&oslash;ve igen (j/n)? &quot;);
      if (&quot;n&quot;.equals(t.l&aelig;sLinje())) stop = true;
    }
  }
}</PRE>
<HR>
<PRE CLASS="kode-western">Hvor mange tal vil du l&aelig;gge sammen? 5
Indtast tal: 1
Indtast tal: x2z
<SPAN STYLE="font-weight: medium">Indtastnings</SPAN>fejl - java.lang.NumberFormatException: x2z
Vil du pr&oslash;ve igen (j/n)? j
Hvor mange tal vil du l&aelig;gge sammen? 3
Indtast tal: 1200
Indtast tal: 1
Indtast tal: 1.9
Summen er: 1202.9
Vil du pr&oslash;ve igen (j/n)? n</PRE><P LANG="da-DK" CLASS="western">
Hvis en undtagelse opst&aring;r, smides den aktuelle sum v&aelig;k og
programmet sp&oslash;rger brugeren, om han vil pr&oslash;ve igen med
en ny sum (efter catch-blokken). Svarer han ja, starter programmet
forfra i while-l&oslash;kken.</P>
<P LANG="da-DK" CLASS="western">Med omhyggelig placering af
try-catch-blokke kan man alts&aring; kontrollere, pr&aelig;cis
hvordan programmet skal opf&oslash;re sig i fejlsituationer:</P>
<BLOCKQUOTE LANG="da-DK" CLASS="definition-western">Kode, hvori der
kan opst&aring; en undtagelse og efterf&oslash;lgende afh&aelig;ngig
kode, b&oslash;r v&aelig;re i samme try-catch-blok</BLOCKQUOTE>
<P LANG="da-DK" CLASS="western">I eksemplet ovenfor finder vi f&oslash;rst
antallet af tal med l&aelig;sTal(). Hvis det g&aring;r galt, giver
det heller ikke mening at g&aring; i gang med at udregne en sum, da
vi ikke ved, hvor mange tal den skal best&aring; af.</P>
<H2 CLASS="western" STYLE="">14.5 <a name='afsn14.5'></a>Fange flere
slags undtagelser</SPAN></H2>
<P LANG="da-DK" CLASS="western">Ovenfor har vi behandlet alle
undtagelser ens. Det er muligt at h&aelig;gte flere catch-s&aelig;tninger
med hver sin type undtagelse p&aring; samme try-blok.</P>
<PRE CLASS="kode-western" STYLE="font-weight: medium">    try {
      ...
    }
    catch (NumberFormatException u1)
    {
      System.out.println(&quot;Fejl i fortolkningen af inddata&quot;);
    } 
    catch (IOException u2)
    {
      System.out.println(&quot;Inddata kunne ikke l&aelig;ses:&quot;+u2);
    }
    catch (NullPointerException u3)
    {
      u3.printStackTrace();
    }</PRE><P LANG="da-DK" CLASS="western">
Alle undtagelses-klasser arver fra Exception og man kan fange <I>enhver</I>
undtagelse ved, at fange deres f&aelig;lles superklasse.
Fejlh&aring;ndteringen bliver s&aring; generel, ligegyldigt hvilken
type undtagelse der opstod (men husk at udskrive staksporet, s&aring;
du kan se hvad der skete!)</P>
<PRE CLASS="kode-western" STYLE="font-weight: medium">    try {
      ...
    }
    catch (<B>Exception</B> u)
    {
      System.out.println(&quot;Fejl:&quot;);
      u.printStackTrace();
    }</PRE><H2 CLASS="western">
14.6 <a name='afsn14.6'></a>Resum&eacute;</SPAN></H2>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_OOP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/OOP/kapitel14.jsp#afsn14.6">
  <input type='checkbox' name='vis' value='14.6'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='14.6'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H2 CLASS="western">14.7 <a name='afsn14.7'></a>Opgaver</SPAN></H2>
<OL>
  <LI><P LANG="da-DK" CLASS="western">Flyt try og catch i
  SumMedTastatur2 s&aring;dan, at programmet smider den aktuelle sum
  v&aelig;k og pr&oslash;ver igen uden at sp&oslash;rge brugeren (g&oslash;r
  det ved kun at bytte om p&aring; linjerne). 
  </P>
  <LI><P LANG="da-DK" CLASS="western">Ret programmet, s&aring; det
  t&aelig;ller antallet af gange, en sum blev p&aring;begyndt. <BR>Det
  er klart, at man skal t&aelig;lle en variabel op, men hvor skal
  opt&aelig;llingen placeres?</P>
  <LI><P LANG="da-DK" CLASS="western">Ret programmet, s&aring; det
  ogs&aring; t&aelig;ller antallet af gange, en sum blev korrekt
  afsluttet.</P>
  <LI><P LANG="da-DK" CLASS="western">&AElig;ndr s&aring;dan, at
  programmet smider den aktuelle indtastning v&aelig;k, men lader
  brugeren forts&aelig;tte med at regne p&aring; den samme sum (vink:
  Lav for-l&oslash;kken om til en while-l&oslash;kke og plac&eacute;r
  opt&aelig;llingen s&aring;dan, at den kun udf&oslash;res, hvis
  indtastningen g&aring;r godt).</P>
</OL>
<H2 CLASS="western" STYLE="">14.8 <a name='afsn14.8'></a>Avanceret</SPAN></H2>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_OOP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/OOP/kapitel14.jsp#afsn14.8">
  <input type='checkbox' name='vis' value='14.8'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='14.8'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">14.8.1 <a name='afsn14.8.1'></a>Fange Throwable</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_OOP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/OOP/kapitel14.jsp#afsn14.8.1">
  <input type='checkbox' name='vis' value='14.8.1'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='14.8.1'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">
14.8.2 <a name='afsn14.8.2'></a>Selv kaste undtagelser (throw)</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_OOP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/OOP/kapitel14.jsp#afsn14.8.2">
  <input type='checkbox' name='vis' value='14.8.2'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='14.8.2'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">14.8.3 <a name='afsn14.8.3'></a>try - finally</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_OOP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/OOP/kapitel14.jsp#afsn14.8.3">
  <input type='checkbox' name='vis' value='14.8.3'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='14.8.3'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">14.8.4 <a name='afsn14.8.4'></a>Selv definere undtagelsestyper</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_OOP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/OOP/kapitel14.jsp#afsn14.8.4">
  <input type='checkbox' name='vis' value='14.8.4'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='14.8.4'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  
<DIV ID="sdfootnote1">
  <P LANG="da-DK" CLASS="sdfootnote-western"><A CLASS="sdfootnotesym" NAME="sdfootnote1sym" HREF="#sdfootnote1anc">1</A>Andre
  typer undtagelser fanges ikke. Hvis de opst&aring;r, afbrydes
  programmet ligesom uden try-catch.</P>
</DIV>
<DIV ID="sdfootnote2">
  <P LANG="da-DK" CLASS="sdfootnote-western"><A CLASS="sdfootnotesym" NAME="sdfootnote2sym" HREF="#sdfootnote2anc">2</A>Det
  er ikke s&aring; sandsynligt netop for tastaturindl&aelig;sning, men
  klasserne, vi bruger, er beregnet til at l&aelig;se vilk&aring;rlige
  datastr&oslash;mme, m&aring;ske endda over netv&aelig;rket, og her
  vil IOException opst&aring;, f.eks. hvis datastr&oslash;mmen er
  blevet lukket, der ikke er mere data at l&aelig;se, eller der er
  opst&aring;et en netv&aelig;rksfejl. Scanner-klassen, beskrevet
  i <a href='kapitel2.jsp#afsn2.3.1'>afsnit 2.3.1</a>, er mere velegnet til netop tastaturindl&aelig;sning.</P>
</DIV>
<DIV ID="sdfootnote3">
  <P LANG="da-DK" CLASS="sdfootnote-western"><A CLASS="sdfootnotesym" NAME="sdfootnote3sym" HREF="#sdfootnote3anc">3</A>Selvom
  det er mindre v&aelig;sentligt, kan man ogs&aring; se, at
  parseDouble() faktisk har kaldt en anden metode, nemlig
  readJavaFormatString().</P>
</DIV>

<a href='http://javabog.dk/'>javabog.dk</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel13.jsp'>&lt;&lt; forrige</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='indhold.jsp'>indhold</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel15.jsp'>n&aelig;ste &gt;&gt;</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kode/'>programeksempler</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='../index_OOP.html'>om bogen</a>
<hr>
<font size=-2>http://javabog.dk/ - <b></b> af Jacob Nordfalk.
<br>
  Licens og kopiering under <a href='http://www.linuxbog.dk/licens.html'>&Aring;ben Dokumentlicens</a> (&Aring;DL)
  hvor intet andet er nævnt (79% af værket).
</font>
<br>
Ønsker du at se de sidste 21% af dette værk (226970 tegn)
skal du købe bogen. Så får du pæne figurer og layout, stikordsregister og en trykt bog med i købet.
<!-- netlæser: Wget/1.10, autoHent: true  -->
     

</body>
</html>
