Undantagshantering

Från Wikipedia
Hoppa till: navigering, sök
För fastighetsrätten, se undantag (fastighetsrätt).

Undantagshantering (engelska exception handling) är mekanismer i programspråk eller datorhårdvara som är avsedda att hantera tillstånd där det normala programflödet behöver ändras. Dessa tillstånd kallas undantag (engelska exception), och orsakas av hårdvaran eller mjukvaran upptäcker ett undantagstillstånd som måste hanteras särskilt.

Varje processor har ett bestämt antal undantag som den kan utlösa. Exempel på vanliga hårdvaruundantag är sidfel eller division med noll. Mjukvaruundantag kan definieras av programmeraren själv och kan till exempel utlösas av övertrassering på ett konto, eller att mätvärdet från en termometer över- eller underskrider gränserna för det tillåtna temperaturintervallet.

I allmänhet avbryts processorn och dess tillstånd sparas på ett i förhand definierat ställe, varefter en undantagshanterare (engelska exception handler) tar över programflödet. Beroende på situationen kan hanteraren välja att återuppta kontrollflödet där det avbröts, genom att använda det sparade tillståndet. Till exempel återupptas flödet vid hanteringen av sidfel oftast utan att huvudprogrammet ens märker avbrottet. I andra fall, som till exempel nolldivision, finns det inget bra sätt att återuppta programflödet. Därför brukar undantagshanteraren vid nolldivision avsluta de felande programmet.

Hårdvaruundantag hanteras på liknande sätt som avbrott, med den väsentliga skillnaden att undantag alltid orsakas av något som det nuvarande programflödet har orsakat eller påträffat, medan avbrott alltid orsakas av externa fenomen (exempelvis signaler från hårddiskar eller tangentbordstryckningar) som inte har något att göra med det för tillfället exekverande programflödet.

Från ett programmerarperspektiv är mjukvaruundantag ett praktiskt sätt att signalera att en programprocedur inte kunde utföras på normalt vis, som när dess inparametrar är ogiltiga (exempelvis ogiltigt personnummer) eller när en resurs som proceduren behöver saknas (en datafil som saknas, eller diskenheten full). I system som saknar undantagshantering måste proceduren skicka en felkod till anropande procedurer. Detta komplicerar dock programkoden avsevärt och gör den betydligt mer svåröverskådlig.

Undantagshantering i programspråk[redigera | redigera wikitext]

Många programspråk har inbyggt stöd för undantagshantering. I sådana språk orsakar ett undantag att stacken rullas upp tills en undantagshanterare hittas. Det vill säga om funktionen f, som har en hanterare H för undantag U, anropar funktionen g som i sin tur anropar h, och ett undantag av typen U inträffar i h, kommer h och g att avbrytas och H i f kommer att hantera U.

Med bortseende från mindre syntaktiska skillnader förekommer allmänt endast ett fåtal olika undantagshanteringstyper. I den mest populära typen utlöses ett undantag med en specifik programsats (throw, raise) med ett undantagsobjekt som beskriver undantaget. Den del av programmet som täcks av en undantagshanterare markeras med try eller liknande och avslutas med den första hanteringsklausulen som markeras med catch, except, rescue eller liknande. Flera hanteringsklausuler kan förekomma och var och en specificerar då det undantag som hanteras.

Några språk har ytterligare en klausul (finally eller ensure) som exekveras oavsett om ett undantag inträffat eller inte, ofta för att frigöra resurser som används inom programblocket som undantagsskyddats.

Det kan rekommenderas att undantag baserat på felaktig indata från utanför programmet fångas nära indatats upphov, så att till exempel ett relevant felmeddelande kan ges till användaren. Undantag baserat på felaktig indata som skapats inom programmet är en bug, och det rekommenderas att inte fånga sådana undantag, utan låta det synas och rätta till buggen.

Exempel[redigera | redigera wikitext]

Ett exempel på hur felhanteringskod kan se ut följer (med C#-liknande syntax):

FileStream stm = null;
try {   // Här börjar undantagshanteringen.
    // Följande sats försöker öppnar en fil som kanske inte finns.
    stm = new FileStream("datafil.txt", FileMode.Open);  // **** 
    if (FilInnehållOgiltigt(stm))
        throw new InvalidFileContentsException("datafil.dat");
    // ... ytterligare programsater
 
} catch (InvalidFileContentsException ex) {
    Console.WriteLine("Innehållet i filen '" + ex.Filename + "' är ogiltigt.");
} catch (IOException ex) {
    // Undantagshantering för IO-fel som kanske uppstod vid raden
    // markerad med '****'
    Console.WriteLine("Ett fel uppstod vid bearbetningen av datafil.txt.");
} catch {
    // Sådana här generella undantag bör tas på allvar eftersom de brukar bero på en bugg alternativt ett användarfel som bör ges ett bättre meddelande.
    Console.WriteLine("Ett okänt fel har inträffat.");
} finally {
    if (stm != null)     // städa upp eventuell öppen fil.
        stm.Close();
}