Programmering

Undtagelser i Java, del 1: Grundlæggende om håndtering af undtagelser

Java-undtagelser er bibliotektyper og sprogfunktioner, der bruges til at repræsentere og håndtere programfejl. Hvis du har ønsket at forstå, hvordan fiasko er repræsenteret i kildekoden, er du kommet til det rette sted. Ud over en oversigt over Java-undtagelser, får jeg dig i gang med Java's sprogfunktioner til at kaste objekter, prøve kode, der muligvis mislykkes, fange kastede objekter og rydde op i din Java-kode, efter at en undtagelse er blevet kastet.

I første halvdel af denne vejledning lærer du om grundlæggende sprogfunktioner og bibliotektyper, der har eksisteret siden Java 1.0. I anden halvdel opdager du avancerede muligheder introduceret i nyere Java-versioner.

Bemærk, at kodeeksempler i denne vejledning er kompatible med JDK 12.

download Hent koden Download kildekoden for eksempel applikationer i denne vejledning. Oprettet af Jeff Friesen til JavaWorld.

Hvad er Java-undtagelser?

Fejl opstår, når et Java-programs normale adfærd afbrydes af uventet adfærd. Denne afvigelse er kendt som en undtagelse. For eksempel forsøger et program at åbne en fil for at læse dens indhold, men filen findes ikke. Java klassificerer undtagelser i et par typer, så lad os overveje hver enkelt.

Kontrollerede undtagelser

Java klassificerer undtagelser, der skyldes eksterne faktorer (såsom en manglende fil) som kontrollerede undtagelser. Java-kompilatoren kontrollerer, at sådanne undtagelser er enten håndteres (korrigeret) hvor de forekommer eller dokumenteres håndteres andetsteds.

Undtagelsesbehandlere

En undtagelsesbehandler er en sekvens af kode, der håndterer en undtagelse. Det forhører konteksten - hvilket betyder, at den læser værdier gemt fra variabler, der var inden for omfanget på det tidspunkt, hvor undtagelsen opstod - bruger derefter det, den lærer, til at gendanne Java-programmet til en strøm af normal adfærd. For eksempel kan en undtagelsesbehandler muligvis læse et gemt filnavn og bede brugeren om at erstatte den manglende fil.

Runtime (ikke markeret) undtagelser

Antag, at et program forsøger at dele et heltal med heltal 0. Denne umulighed illustrerer en anden slags undtagelse, nemlig a runtime undtagelse. I modsætning til afkrydsede undtagelser stammer undtagelser fra runtime typisk fra dårligt skrevet kildekode og bør derfor rettes af programmøren. Da kompilatoren ikke kontrollerer, at undtagelser for runtime håndteres eller dokumenteres håndteres andetsteds, kan du tænke på en runtime-undtagelse som en ukontrolleret undtagelse.

Om undtagelser fra runtime

Du kan muligvis ændre et program for at håndtere en runtime-undtagelse, men det er bedre at rette kildekoden. Runtime-undtagelser opstår ofte fra at overføre ugyldige argumenter til et biblioteks metoder; buggy-opkaldskoden skal være rettet.

Fejl

Nogle undtagelser er meget alvorlige, fordi de bringer et programs evne til at fortsætte udførelsen i fare. For eksempel forsøger et program at tildele hukommelse fra JVM, men der er ikke nok ledig hukommelse til at imødekomme anmodningen. En anden alvorlig situation opstår, når et program forsøger at indlæse en klassefil via en Class.forName () metodeopkald, men klassefilen er korrupt. Denne form for undtagelse er kendt som en fejl. Du bør aldrig prøve at håndtere fejl selv, fordi JVM muligvis ikke kan komme sig fra det.

Undtagelser i kildekode

En undtagelse kan i kildekoden være repræsenteret som en Fejlkode eller som en objekt. Jeg introducerer begge dele og viser dig, hvorfor objekter er overlegne.

Fejlkoder versus objekter

Programmeringssprog som C bruger heltal-baseret fejlkoder at repræsentere fiasko og årsager til fiasko - dvs. undtagelser. Her er et par eksempler:

hvis (chdir ("C: \ temp")) printf ("Kan ikke skifte til temp-katalog:% d \ n", errno); FIL * fp = fopen ("C: \ temp \ foo"); hvis (fp == NULL) printf ("Kan ikke åbne foo:% d \ n", errno);

C'er chdir () (skift mappe) -funktionen returnerer et heltal: 0 ved succes eller -1 ved fiasko. Tilsvarende C'er fopen () (fil åben) -funktionen returnerer en nullull markør (heltal adresse) til a FIL struktur på succes eller en nul (0) markør (repræsenteret af konstant NUL) ved fiasko. I begge tilfælde skal du læse det globale for at identificere undtagelsen, der forårsagede fejlen errno variabels heltal-baserede fejlkode.

Fejlkoder giver nogle problemer:

  • Heltal er meningsløse; de beskriver ikke de undtagelser, de repræsenterer. Hvad betyder f.eks. 6?
  • At knytte kontekst til en fejlkode er akavet. For eksempel vil du muligvis sende navnet på den fil, der ikke kunne åbnes, men hvor skal du gemme filens navn?
  • Heltal er vilkårlige, hvilket kan føre til forvirring ved læsning af kildekode. For eksempel at specificere hvis (! chdir ("C: \ temp")) (! betyder IKKE) i stedet for hvis (chdir ("C: \ temp")) at teste for fiasko er tydeligere. Imidlertid blev 0 valgt for at indikere succes, og så hvis (chdir ("C: \ temp")) skal specificeres for at teste for fejl.
  • Fejlkoder er for lette at ignorere, hvilket kan føre til fejlkode. For eksempel kunne programmøren specificere chdir ("C: \ temp"); og ignorere hvis (fp == NULL) kontrollere. Desuden behøver programmøren ikke undersøge errno. Ved ikke at teste for fejl, opfører programmet sig uretmæssigt, når en af ​​funktionerne returnerer en fejlindikator.

For at løse disse problemer omfavnede Java en ny tilgang til håndtering af undtagelser. I Java kombinerer vi objekter, der beskriver undtagelser, med en mekanisme baseret på at kaste og fange disse objekter. Her er nogle fordele ved at bruge objekter versus fejlkode til at betegne undtagelser:

  • Et objekt kan oprettes fra en klasse med et meningsfuldt navn. For eksempel, FileNotFoundException (i java.io pakke) er mere meningsfuld end 6.
  • Objekter kan gemme kontekst i forskellige felter. For eksempel kan du gemme en besked, navnet på filen, der ikke kunne åbnes, den seneste position, hvor en parseringshandling mislykkedes, og / eller andre elementer i et objekts felter.
  • Du bruger ikke hvis udsagn for at teste for fiasko. I stedet kastes undtagelsesobjekter til en handler, der er adskilt fra programkoden. Som et resultat er kildekoden lettere at læse og mindre tilbøjelige til at være buggy.

Kan kastes og dens underklasser

Java giver et hierarki af klasser, der repræsenterer forskellige slags undtagelser. Disse klasser er forankret i java.lang pakke er Kan kastes klasse sammen med dens Undtagelse, RuntimeExceptionog Fejl underklasser.

Kan kastes er den ultimative superklasse, når det gælder undtagelser. Kun objekter oprettet fra Kan kastes og dens underklasser kan kastes (og efterfølgende fanges). Sådanne genstande er kendt som kastbare.

EN Kan kastes objekt er forbundet med en detaljeret besked der beskriver en undtagelse. Flere konstruktører, herunder paret beskrevet nedenfor, er tilvejebragt for at skabe en Kan kastes objekt med eller uden en detaljeret besked:

  • Kan kastes () skaber en Kan kastes uden detaljeret besked. Denne konstruktør er passende i situationer, hvor der ikke er nogen sammenhæng. For eksempel vil du kun vide, at en stak er tom eller fuld.
  • Kan kastes (streng besked) skaber en Kan kastes med besked som detalje besked. Denne meddelelse kan sendes til brugeren og / eller logges.

Kan kastes giver den String getMessage () metode til at returnere detalje besked. Det giver også yderligere nyttige metoder, som jeg introducerer senere.

Undtagelsesklassen

Kan kastes har to direkte underklasser. En af disse underklasser er Undtagelse, der beskriver en undtagelse, der skyldes en ekstern faktor (såsom forsøg på at læse fra en ikke-eksisterende fil). Undtagelse erklærer de samme konstruktører (med identiske parameterlister) som Kan kastesog hver konstruktør påberåber sig dens Kan kastes modstykke. Undtagelse arver Kan kastes's metoder; det erklærer ingen nye metoder.

Java tilbyder mange undtagelsesklasser, der direkte underklasser Undtagelse. Her er tre eksempler:

  • CloneNotSupportedException signalerer et forsøg på at klone et objekt, hvis klasse ikke implementerer Klonabel interface. Begge typer findes i java.lang pakke.
  • IOUndtagelse signalerer, at der er opstået en form for I / O-fejl. Denne type er placeret i java.io pakke.
  • ParseException signalerer, at der er opstået en fejl under parsing af tekst. Denne type findes i java.text pakke.

Bemærk, at hver Undtagelse underklassens navn slutter med ordet Undtagelse. Denne konvention gør det let at identificere klassens formål.

Du vil typisk underklasse Undtagelse (eller en af ​​dens underklasser) med dine egne undtagelsesklasser (hvis navne skal slutte med Undtagelse). Her er et par eksempler på brugerdefinerede underklasseeksempler:

offentlig klasse StackFullException udvider undtagelse {} offentlig klasse EmptyDirectoryException udvider undtagelse {private String directoryName; offentlig EmptyDirectoryException (streng besked, streng katalognavn) {super (besked); this.directoryName = katalognavn; } public String getDirectoryName () {return directoryName; }}

Det første eksempel beskriver en undtagelsesklasse, der ikke kræver en detaljeret besked. Det er standard noargument-konstruktør påberåber sig Undtagelse(), som påberåber sig Kan kastes ().

Det andet eksempel beskriver en undtagelsesklasse, hvis konstruktør kræver en detaljeret besked og navnet på den tomme mappe. Konstruktøren påberåber sig Undtagelse (strengbesked), som påberåber sig Kan kastes (streng besked).

Genstande instantieret fra Undtagelse eller en af ​​dens underklasser (undtagen RuntimeException eller en af ​​dens underklasser) er kontrollerede undtagelser.

Klassen RuntimeException

Undtagelse er direkte underklasseret af RuntimeException, der beskriver en undtagelse, der sandsynligvis stammer fra dårligt skrevet kode. RuntimeException erklærer de samme konstruktører (med identiske parameterlister) som Undtagelseog hver konstruktør påberåber sig dens Undtagelse modstykke. RuntimeException arver Kan kastes's metoder. Den erklærer ingen nye metoder.

Java tilbyder mange undtagelsesklasser, der direkte underklasser RuntimeException. De følgende eksempler er alle medlemmer af java.lang pakke:

  • Aritmetisk undtagelse signalerer en ulovlig aritmetisk operation, såsom at forsøge at dele et heltal med 0.
  • IllegalArgumentException signalerer, at et ulovligt eller upassende argument er videregivet til en metode.
  • NullPointerException signalerer et forsøg på at påkalde en metode eller få adgang til et instansfelt via null-referencen.

Genstande instantieret fra RuntimeException eller en af ​​dens underklasser er ukontrollerede undtagelser.

Fejlklassen

Kan kastes's anden direkte underklasse er Fejl, som beskriver et alvorligt (endda unormalt) problem, som en rimelig applikation ikke skal forsøge at håndtere - såsom at løbe tør for hukommelse, oversvømme JVM's stak eller forsøge at indlæse en klasse, der ikke kan findes. Synes godt om Undtagelse, Fejl erklærer identiske konstruktører til Kan kastes, arver Kan kastes's metoder og erklærer ikke nogen af ​​sine egne metoder.

Du kan identificere Fejl underklasser fra den konvention, som deres klassenavne slutter med Fejl. Eksempler inkluderer OutOfMemoryError, LinkageErrorog StackOverflowError. Alle tre typer hører til java.lang pakke.

Kaster undtagelser

En C-biblioteksfunktion giver en undtagelse besked om opkaldskoden ved at indstille den globale errno variabel til en fejlkode og returnere en fejlkode. I modsætning hertil kaster en Java-metode et objekt. At vide, hvordan og hvornår man skal kaste undtagelser, er et væsentligt aspekt af effektiv Java-programmering. At kaste en undtagelse involverer to grundlæggende trin:

  1. Brug kaste erklæring om at smide en undtagelsesgenstand.
  2. Brug kaster klausul for at informere kompilatoren.

Senere sektioner vil fokusere på at fange undtagelser og rydde op efter dem, men lad os først lære mere om kastbare.

Kasterklæringen

Java leverer kaste erklæring om at kaste et objekt, der beskriver en undtagelse. Her er syntaksen for kaste udmelding :

kaste kastbar;

Objektet identificeret af kastbar er en forekomst af Kan kastes eller nogen af ​​dets underklasser. Du kaster dog normalt kun genstande instantieret fra underklasser af Undtagelse eller RuntimeException. Her er et par eksempler:

smid ny FileNotFoundException ("kan ikke finde fil" + filnavn); smid nyt IllegalArgumentException ("argumentet, der sendes til at tælle, er mindre end nul");

Den kastbare kastes fra den nuværende metode til JVM, som kontrollerer denne metode for en passende handler. Hvis den ikke findes, afvikler JVM metoden til opkaldsstak og leder efter den nærmeste kaldemetode, der kan håndtere undtagelsen beskrevet af kastbar. Hvis den finder denne metode, videresendes den kastbare til metodens handler, hvis kode udføres for at håndtere undtagelsen. Hvis der ikke findes nogen metode til at håndtere undtagelsen, afsluttes JVM med en passende besked.

Kast-klausulen

Du er nødt til at informere compileren, når du smider en afkrydset undtagelse ud af en metode. Gør dette ved at tilføje en kaster klausul til metodens overskrift. Denne klausul har følgende syntaks:

kaster checkedExceptionClassName (, checkedExceptionClassName)*

EN kaster klausul består af nøgleord kaster efterfulgt af en komma-adskilt liste over klassenavne på kontrollerede undtagelser, der er kastet ud af metoden. Her er et eksempel:

offentlig statisk ugyldig hoved (String [] args) kaster ClassNotFoundException {if (args.length! = 1) {System.err.println ("brug: java ... classfile"); Vend tilbage; } Class.forName (args [0]); }

Dette eksempel forsøger at indlæse en klassefil identificeret ved et kommandolinjeargument. Hvis Class.forName () ikke kan finde klassefilen, kaster den en java.lang.ClassNotFoundException objekt, som er en kontrolleret undtagelse.

Kontrolleret undtagelseskontrovers

Det kaster klausul og kontrollerede undtagelser er kontroversielle. Mange udviklere hader at blive tvunget til at specificere kaster eller håndter de markerede undtagelser. Lær mere om dette fra mine Er afkrydsede undtagelser gode eller dårlige? blogindlæg.

$config[zx-auto] not found$config[zx-overlay] not found