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 forhvis (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 ignorerehvis (fp == NULL)
kontrollere. Desuden behøver programmøren ikke undersøgeerrno
. 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
(ijava.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
, RuntimeException
og 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
medbesked
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 kastes
og 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 ijava.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 Undtagelse
og 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
, LinkageError
og 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:
- Brug
kaste
erklæring om at smide en undtagelsesgenstand. - 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.