Programmering

Unntak i Java, del 1: Grunnleggende om unntakshåndtering

Java-unntak er bibliotektyper og språkfunksjoner som brukes til å representere og håndtere programfeil. Hvis du har ønsket å forstå hvordan feil er representert i kildekoden, har du kommet til rett sted. I tillegg til en oversikt over Java-unntak, vil jeg komme i gang med Java sine språkfunksjoner for å kaste objekter, prøve kode som kan mislykkes, fange kastede gjenstander og rydde opp Java-koden etter at et unntak er kastet.

I første halvdel av denne opplæringen lærer du om grunnleggende språkfunksjoner og bibliotektyper som har eksistert siden Java 1.0. I andre halvdel vil du oppdage avanserte funksjoner introdusert i nyere Java-versjoner.

Merk at kodeeksempler i denne opplæringen er kompatible med JDK 12.

last ned Få koden Last ned kildekoden for eksempel applikasjoner i denne opplæringen. Skapt av Jeff Friesen for JavaWorld.

Hva er Java-unntak?

Feil oppstår når et Java-programs normale oppførsel blir avbrutt av uventet oppførsel. Denne avviket er kjent som en unntak. For eksempel prøver et program å åpne en fil for å lese innholdet, men filen eksisterer ikke. Java klassifiserer unntak i noen få typer, så la oss vurdere hvert enkelt.

Sjekket unntak

Java klassifiserer unntak som oppstår fra eksterne faktorer (for eksempel en manglende fil) som sjekket unntak. Java-kompilatoren sjekker at slike unntak er det håndtert (korrigert) der de oppstår eller er dokumentert for å bli håndtert andre steder.

Unntakshåndterere

An unntakshåndterer er en sekvens med kode som håndterer et unntak. Det avhører konteksten - noe som betyr at den leser verdier som er lagret fra variabler som var i omfang på det tidspunktet unntaket skjedde - og bruker deretter det den lærer å gjenopprette Java-programmet til en strøm av normal oppførsel. For eksempel kan en unntaksbehandler lese et lagret filnavn og be brukeren om å erstatte den manglende filen.

Runtime (ukontrollerte) unntak

Anta at et program prøver å dele et heltall med heltall 0. Denne umuligheten illustrerer en annen slags unntak, nemlig a kjøretid unntak. I motsetning til sjekket unntak, oppstår unntak for kjøretid vanligvis fra dårlig skrevet kildekode, og bør derfor løses av programmereren. Fordi kompilatoren ikke sjekker at unntak for kjøretid håndteres eller dokumenteres for å bli håndtert andre steder, kan du tenke på et unntak for kjøretid som et ukontrollert unntak.

Om unntak for kjøretid

Du kan endre et program for å håndtere et unntak for kjøretid, men det er bedre å fikse kildekoden. Runtime-unntak oppstår ofte fra å overføre ugyldige argumenter til et biblioteks metoder; buggy-koden skal være løst.

Feil

Noen unntak er veldig alvorlige fordi de bringer et programs evne til å fortsette utførelsen i fare. For eksempel prøver et program å tildele minne fra JVM, men det er ikke nok ledig minne til å tilfredsstille forespørselen. En annen alvorlig situasjon oppstår når et program prøver å laste en klassefil via en Class.forName () metodeanrop, men klassefilen er korrupt. Denne typen unntak er kjent som en feil. Du bør aldri prøve å håndtere feil selv, fordi JVM kanskje ikke kan komme seg fra den.

Unntak i kildekoden

Et unntak kan vises i kildekoden som et feil kode eller som en gjenstand. Jeg introduserer begge deler og viser deg hvorfor gjenstander er overlegne.

Feilkoder versus objekter

Programmeringsspråk som C bruker heltalsbasert feilkoder å representere svikt og årsaker til svikt - dvs. unntak. Her er et par eksempler:

hvis (chdir ("C: \ temp")) printf ("Kan ikke endre til tempkatalog:% d \ n", errno); FIL * fp = fopen ("C: \ temp \ foo"); if (fp == NULL) printf ("Kan ikke åpne foo:% d \ n", errno);

C-er chdir () (endre katalog) -funksjonen returnerer et helt tall: 0 ved suksess eller -1 ved feil. Tilsvarende C fopen () (fil åpen) -funksjonen returnerer en null pekeren (heltall adresse) til a FIL struktur på suksess eller en null (0) peker (representert med konstant NULL) på feil. I begge tilfeller må du lese det globale for å identifisere unntaket som forårsaket feilen errno variabels heltallbaserte feilkode.

Feilkoder gir noen problemer:

  • Heltall er meningsløst; de beskriver ikke unntakene de representerer. Hva betyr for eksempel 6?
  • Å knytte sammenheng med en feilkode er vanskelig. For eksempel vil du kanskje sende navnet på filen som ikke kunne åpnes, men hvor skal du lagre filnavnet?
  • Heltall er vilkårlig, noe som kan føre til forvirring når du leser kildekoden. For eksempel å spesifisere hvis (! chdir ("C: \ temp")) (! betyr IKKE) i stedet for hvis (chdir ("C: \ temp")) å teste for feil er tydeligere. Imidlertid ble 0 valgt for å indikere suksess, og så hvis (chdir ("C: \ temp")) må spesifiseres for å teste for feil.
  • Feilkoder er for enkle å ignorere, noe som kan føre til feilkode. For eksempel kan programmereren spesifisere chdir ("C: \ temp"); og ignorere hvis (fp == NULL) Sjekk. Videre trenger ikke programmereren å undersøke errno. Ved ikke å teste for feil, oppfører programmet seg uberegnelig når en av funksjonene returnerer en feilindikator.

For å løse disse problemene omfavnet Java en ny tilnærming til unntakshåndtering. I Java kombinerer vi objekter som beskriver unntak med en mekanisme basert på å kaste og fange disse objektene. Her er noen fordeler ved å bruke objekter versus feilkode for å betegne unntak:

  • Et objekt kan opprettes fra en klasse med et meningsfylt navn. For eksempel, FileNotFoundException (i java.io pakke) er mer meningsfull enn 6.
  • Objekter kan lagre kontekst i forskjellige felt. For eksempel kan du lagre en melding, navnet på filen som ikke kunne åpnes, den siste posisjonen der en analyseoperasjon mislyktes, og / eller andre elementer i et objekts felt.
  • Du bruker ikke hvis uttalelser for å teste for feil. I stedet kastes unntaksobjekter til en behandler som er skilt fra programkoden. Som et resultat er kildekoden lettere å lese og mindre sannsynlig å være buggy.

Kastbar og dens underklasser

Java gir et hierarki av klasser som representerer forskjellige typer unntak. Disse klassene er forankret i java.lang pakken er Kastbar klasse, sammen med sin Unntak, RuntimeException, og Feil underklasser.

Kastbar er den ultimate superklassen når det gjelder unntak. Bare gjenstander opprettet fra Kastbar og dens underklasser kan kastes (og deretter fanges). Slike gjenstander er kjent som kasteutstyr.

EN Kastbar objekt er assosiert med en detaljmelding som beskriver et unntak. Flere konstruktører, inkludert paret beskrevet nedenfor, er gitt for å lage en Kastbar objekt med eller uten detaljmelding:

  • Kastbar () skaper en Kastbar uten detaljmelding. Denne konstruktøren passer for situasjoner der det ikke er noen sammenheng. For eksempel vil du bare vite at en bunke er tom eller full.
  • Kastbar (strengmelding) skaper en Kastbar med beskjed som detaljmeldingen. Denne meldingen kan sendes til brukeren og / eller logges.

Kastbar gir den String getMessage () metode for å returnere detaljmeldingen. Det gir også flere nyttige metoder, som jeg vil introdusere senere.

Unntaksklassen

Kastbar har to direkte underklasser. En av disse underklassene er Unntak, som beskriver et unntak som oppstår fra en ekstern faktor (for eksempel å prøve å lese fra en ikke-eksisterende fil). Unntak erklærer de samme konstruktørene (med identiske parameterlister) som Kastbar, og hver konstruktør påberoper seg Kastbar motstykke. Unntak arver Kastbarsine metoder; den erklærer ingen nye metoder.

Java tilbyr mange unntaksklasser som direkte underklasser Unntak. Her er tre eksempler:

  • CloneNotSupportedException signaliserer et forsøk på å klone et objekt hvis klasse ikke implementerer Klonbar grensesnitt. Begge typene er i java.lang pakke.
  • IO Unntak signaliserer at det har oppstått en slags I / O-feil. Denne typen ligger i java.io pakke.
  • ParseException signaliserer at det har oppstått en feil under parsing av tekst. Denne typen finnes i java.text pakke.

Legg merke til at hver Unntak underklassens navn ender med ordet Unntak. Denne konvensjonen gjør det enkelt å identifisere klassens formål.

Du vil vanligvis underklasse Unntak (eller en av underklassene) med dine egne unntaksklasser (hvis navn skal slutte med Unntak). Her er et par egendefinerte underklasseeksempler:

offentlig klasse StackFullException utvider unntak {} offentlig klasse EmptyDirectoryException utvider unntak {private String directoryName; offentlig EmptyDirectoryException (strengmelding, streng katalognavn) {super (melding); this.directoryName = katalognavn; } offentlig streng getDirectoryName () {return katalognavn; }}

Det første eksemplet beskriver en unntaksklasse som ikke krever detaljmelding. Det er standard noargument-konstruktør påberoper seg Unntak(), som påberoper seg Kastbar ().

Det andre eksemplet beskriver en unntaksklasse hvis konstruktør krever en detaljmelding og navnet på den tomme katalogen. Konstruktøren påberoper seg Unntak (strengmelding), som påberoper seg Kastbar (strengmelding).

Objekter instantiert fra Unntak eller en av underklassene (unntatt RuntimeException eller en av underklassene) er sjekket unntak.

RuntimeException-klassen

Unntak er direkte underklassert av RuntimeException, som beskriver et unntak som mest sannsynlig oppstår fra dårlig skrevet kode. RuntimeException erklærer de samme konstruktørene (med identiske parameterlister) som Unntak, og hver konstruktør påberoper seg Unntak motstykke. RuntimeException arver Kastbarsine metoder. Den erklærer ingen nye metoder.

Java tilbyr mange unntaksklasser som direkte underklasser RuntimeException. Følgende eksempler er alle medlemmer av java.lang pakke:

  • Aritmetisk unntak signaliserer en ulovlig aritmetisk operasjon, for eksempel å prøve å dele et heltall med 0.
  • IllegalArgumentException signaliserer at et ulovlig eller upassende argument har blitt overført til en metode.
  • NullPointerException signaliserer et forsøk på å påkalle en metode eller få tilgang til et forekomstfelt via nullreferansen.

Objekter instantiert fra RuntimeException eller en av dens underklasser er ukontrollerte unntak.

Feilklassen

Kastbarsin andre direkte underklasse er Feil, som beskriver et alvorlig (til og med unormalt) problem som en fornuftig applikasjon ikke skal prøve å håndtere - for eksempel å gå tom for minne, overfylle JVM-stakken eller prøve å laste en klasse som ikke blir funnet. Som Unntak, Feil erklærer identiske konstruktører til Kastbar, arver Kastbarsine metoder, og erklærer ikke noen av sine egne metoder.

Du kan identifisere deg Feil underklasser fra konvensjonen som klassenavnene deres slutter med Feil. Eksempler inkluderer OutOfMemoryError, LinkageError, og StackOverflowError. Alle tre typene tilhører java.lang pakke.

Kaster unntak

En C-biblioteksfunksjon varsler anropskoden om et unntak ved å angi den globale errno variabel til en feilkode og returnere en feilkode. Derimot kaster en Java-metode et objekt. Å vite hvordan og når man skal kaste unntak er et viktig aspekt av effektiv Java-programmering. Å kaste et unntak innebærer to grunnleggende trinn:

  1. Bruke kaste uttalelse for å kaste et unntaksobjekt.
  2. Bruke kaster klausul for å informere kompilatoren.

Senere seksjoner vil fokusere på å fange unntak og rydde opp etter dem, men la oss først lære mer om kastevarer.

Kasterklæringen

Java tilbyr kaste uttalelse for å kaste et objekt som beskriver et unntak. Her er syntaksen til kaste uttalelse:

kaste kastbar;

Objektet identifisert av kastbar er en forekomst av Kastbar eller noen av underklassene. Imidlertid kaster du vanligvis bare gjenstander instantiert fra underklasser av Unntak eller RuntimeException. Her er et par eksempler:

kaste ny FileNotFoundException ("finner ikke fil" + filnavn); kaste nye IllegalArgumentException ("argumentet overført til telling er mindre enn null");

Kastbar kastes fra den nåværende metoden til JVM, som sjekker denne metoden for en passende handler. Hvis den ikke blir funnet, avvikler JVM metoden samtalestakken og ser etter den nærmeste anropsmetoden som kan håndtere unntaket beskrevet av kastet. Hvis den finner denne metoden, overføres den kastbar til metodens håndterer, hvis kode blir utført for å håndtere unntaket. Hvis det ikke finnes noen metode for å håndtere unntaket, avsluttes JVM med en passende melding.

Kast-klausulen

Du må informere kompilatoren når du kaster et avkrysset unntak ut av en metode. Gjør dette ved å legge til en kaster klausul til metodens overskrift. Denne paragrafen har følgende syntaks:

kaster checkedExceptionClassName (, checkedExceptionClassName)*

EN kaster klausul består av nøkkelord kaster etterfulgt av en kommaseparert liste over klassenavnene på avmerkede unntak kastet ut av metoden. Her er et eksempel:

public static void main (String [] args) kaster ClassNotFoundException {if (args.length! = 1) {System.err.println ("bruk: java ... classfile"); komme tilbake; } Class.forName (args [0]); }

Dette eksemplet prøver å laste inn en klassefil som er identifisert av et kommandolinjeargument. Hvis Class.forName () finner ikke klassefilen, kaster den en java.lang.ClassNotFoundException objekt, som er et sjekket unntak.

Sjekket unntakskontrovers

De kaster klausul og sjekket unntak er kontroversielle. Mange utviklere hater å bli tvunget til å spesifisere kaster eller håndter det avmerkede unntaket. Lær mer om dette fra min. Er avmerkede unntak gode eller dårlige? blogg innlegg.

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