Programmering

Unntak i Java, del 2: avanserte funksjoner og typer

JDK 1.0 introduserte et rammeverk for språkfunksjoner og bibliotektyper for å håndtere unntak, som er avvik fra forventet programatferd. Første halvdel av denne opplæringen dekket Java's grunnleggende unntakshåndteringsfunksjoner. Denne andre halvdelen introduserer mer avanserte muligheter levert av JDK 1.0 og dens etterfølgere: JDK 1.4, JDK 7 og JDK 9. Lær hvordan du kan forutse og administrere unntak i Java-programmene dine ved hjelp av avanserte funksjoner som stakkspor, årsaker og unntakskjeding, prøv -med ressurser, multi-catch, siste re-throw, og stack walking.

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.

Unntakshåndtering i JDK 1.0 og 1.4: Stakkspor

Hver JVM tråd (en utførelsessti) er assosiert med en stable som opprettes når tråden opprettes. Denne datastrukturen er delt inn i rammer, som er datastrukturer knyttet til metodeanrop. Av denne grunn blir hver trådstabel ofte referert til som en metode-samtalestabel.

En ny ramme opprettes hver gang en metode kalles. Hver ramme lagrer lokale variabler, parametervariabler (som inneholder argumenter overført til metoden), informasjon for å gå tilbake til anropsmetoden, plass til å lagre en returverdi, informasjon som er nyttig for å sende et unntak, og så videre.

EN stabelspor (også kjent som en stable tilbakesporingen) er en rapport om de aktive stablerammene på et bestemt tidspunkt under utførelsen av en tråd. Java-er Kastbar klasse (i java.lang pakke) gir metoder for å skrive ut en stakksporing, fylle ut en stablespor og få tilgang til elementene til en stackspor.

Skrive ut en stabelspor

Når kaste uttalelse kaster en kastbar, det ser først etter en passende å fange blokk i kjøringsmetoden. Hvis den ikke blir funnet, avvikler den metoden-samtalestakken på jakt etter den nærmeste å fange blokk som kan håndtere unntaket. Hvis ikke funnet, avsluttes JVM med en passende melding. Vurder oppføring 1.

Oppføring 1. PrintStackTraceDemo.java (versjon 1)

importere java.io.IOException; public class PrintStackTraceDemo {public static void main (String [] args) kaster IOException {throw new IOException (); }}

Oppføring 1s konstruerte eksempel skaper en java.io.IO Unntak objekt og kaster dette objektet ut av hoved() metode. Fordi hoved() takler ikke dette kastbare, og fordi hoved() er toppnivåmetoden, avsluttes JVM med en passende melding. For denne applikasjonen vil du se følgende melding:

Unntak i tråden "hoved" java.io.IO Unntak på PrintStackTraceDemo.main (PrintStackTraceDemo.java:7)

JVM sender ut denne meldingen ved å ringe Kastbars ugyldig printStackTrace () metoden, som skriver ut en stakkspor for påkallingen Kastbar objekt på standardfeilstrømmen. Den første linjen viser resultatet av å påkalle kastbare toString () metode. Neste linje viser data som tidligere er registrert av fillInStackTrace () (diskutert kort tid).

Ytterligere sporingsmetoder for utskrift

Kastbarer overbelastet ugyldig printStackTrace (PrintStream ps) og void printStackTrace (PrintWriter pw) metoder sender stabelsporet til den angitte strømmen eller forfatteren.

Stakksporingen avslører kildefilen og linjenummeret hvor kastet ble opprettet. I dette tilfellet ble den opprettet på linje 7 i PrintStackTrace.java kildefil.

Du kan påberope deg printStackTrace () direkte, typisk fra en å fange blokkere. Tenk for eksempel på en andre versjon av PrintStackTraceDemo applikasjon.

Oppføring 2. PrintStackTraceDemo.java (versjon 2)

importere java.io.IOException; public class PrintStackTraceDemo {public static void main (String [] args) kaster IOException {try {a (); } fange (IOException ioe) {ioe.printStackTrace (); }} statisk tomrom a () kaster IOException {b (); } statisk tomrom b () kaster IOException {kast nytt IOException (); }}

Oppføring 2 avslører a hoved() metode som kaller metode en(), som kaller metode b (). Metode b () kaster en IO Unntak motsette seg JVM, som avvikler metodekallestakken til den finner hoved()s å fange blokk, som kan håndtere unntaket. Unntaket håndteres ved å påkalle printStackTrace () på kastet. Denne metoden genererer følgende utdata:

java.io.IOException på PrintStackTraceDemo.b (PrintStackTraceDemo.java:24) på ​​PrintStackTraceDemo.a (PrintStackTraceDemo.java:19) på PrintStackTraceDemo.main (PrintStackTraceDemo.java:9)

printStackTrace () sender ikke ut trådens navn. I stedet påkaller den seg toString () på kastet for å returnere kastets fullt kvalifiserte klassenavn (java.io.IO Unntak), som sendes ut på første linje. Den sender deretter ut metoden-anropshierarkiet: den sist kallte metoden (b ()) er på toppen og hoved() er i bunnen.

Hvilken linje identifiserer stabelsporet?

Stakksporet identifiserer linjen der en kastbar opprettes. Det identifiserer ikke linjen der kastbar kastes (via kaste), med mindre kastbar kastes på samme linje der den er opprettet.

Fyll ut et stabelspor

Kastbar erklærer en Kastbar fillInStackTrace () metoden som fyller ut kjøringsstakkspor. I påkallingen Kastbar objektet, registrerer den informasjon om den gjeldende tilstanden til den nåværende trådens stabelrammer. Vurder oppføring 3.

Oppføring 3. FillInStackTraceDemo.java (versjon 1)

importere java.io.IOException; public class FillInStackTraceDemo {public static void main (String [] args) kaster IOException {try {a (); } fange (IOException ioe) {ioe.printStackTrace (); System.out.println (); kaste (IOException) ioe.fillInStackTrace (); }} statisk tomrom a () kaster IOException {b (); } statisk tomrom b () kaster IOException {kast nytt IOException (); }}

Hovedforskjellen mellom Listing 3 og Listing 2 er å fange blokker kaste (IOException) ioe.fillInStackTrace (); uttalelse. Denne uttalelsen erstatter ioebunnspor, hvoretter kastet kastes på nytt. Du bør følge denne utgangen:

java.io.IOException på FillInStackTraceDemo.b (FillInStackTraceDemo.java:26) på FillInStackTraceDemo.a (FillInStackTraceDemo.java:21) på FillInStackTraceDemo.main (FillInStackTraceDemo.java:9) Exception java: 9) Exception at main. FillInStackTraceDemo.main (FillInStackTraceDemo.java:15)

I stedet for å gjenta den første stakksporingen, som identifiserer stedet der IO Unntak objektet ble opprettet, avslører den andre stabelsporet plasseringen av ioe.fillInStackTrace ().

Kastbare konstruktører og fillInStackTrace ()

Hver av Kastbarkonstruktører påberoper seg fillInStackTrace (). Imidlertid vil følgende konstruktør (introdusert i JDK 7) ikke påkalle denne metoden når du passerer falsk til skrivbarStackTrace:

Kastbar (strengmelding, kastbar årsak, boolsk mulig undertrykkelse, boolsk skrivbarStackTrace)

fillInStackTrace () påkaller en innfødt metode som går nedover den gjeldende trådens metode-anropsbunke for å bygge stabelsporet. Denne turen er kostbar og kan påvirke ytelsen hvis den forekommer for ofte.

Hvis du kommer inn i en situasjon (kanskje involverer en innebygd enhet) der ytelse er kritisk, kan du forhindre at stack-spor blir bygget ved å overstyre fillInStackTrace (). Sjekk ut oppføring 4.

Oppføring 4. FillInStackTraceDemo.java (versjon 2)

{public static void main (String [] args) kaster NoStackTraceException {try {a (); } fange (NoStackTraceException nste) {nste.printStackTrace (); }} statisk tomrom a () kaster NoStackTraceException {b (); } statisk tomrom b () kaster NoStackTraceException {kast nytt NoStackTraceException (); }} klasse NoStackTraceException utvider Unntak {@Override offentlig synkronisert Throwable fillInStackTrace () {returner dette; }}

Listing 4 introduserer NoStackTraceException. Denne tilpassede kontrollerte unntaksklassen tilsidesetter fillInStackTrace () å returnere dette - en referanse til påkallingen Kastbar. Dette programmet genererer følgende utdata:

NoStackTraceException

Kommenter den overordnede fillInStackTrace () metode og du vil observere følgende utdata:

NoStackTraceException på FillInStackTraceDemo.b (FillInStackTraceDemo.java:22) på FillInStackTraceDemo.a (FillInStackTraceDemo.java:17) på FillInStackTraceDemo.main (FillInStackTraceDemo.java:7)

Få tilgang til elementene til en stakkspor

Noen ganger må du få tilgang til elementene til en stakkspor for å hente ut detaljer som kreves for logging, identifisere kilden til en ressurslekkasje og andre formål. De printStackTrace () og fillInStackTrace () metoder støtter ikke denne oppgaven, men JDK 1.4 introduserte java.lang.StackTraceElement og dens metoder for dette formålet.

De java.lang.StackTraceElement klasse beskriver et element som representerer en stabelramme i en stakkspor. Dens metoder kan brukes til å returnere det fullt kvalifiserte navnet på klassen som inneholder utførelsespunktet som representeres av dette stakkesporelementet, sammen med annen nyttig informasjon. Her er hovedmetodene:

  • String getClassName () returnerer det fullt kvalifiserte navnet på klassen som inneholder utførelsespunktet som er representert av dette stabile sporelementet.
  • String getFileName () returnerer navnet på kildefilen som inneholder kjøringspunktet som er representert av dette stakksporelementet.
  • int getLineNumber () returnerer linjenummeret til kildelinjen som inneholder utførelsespunktet som er representert av dette stack-sporelementet.
  • String getMethodName () returnerer navnet på metoden som inneholder kjøringspunktet som er representert av dette stakksporelementet.
  • boolsk isNativeMethod () returnerer ekte når metoden som inneholder utførelsespunktet representert av dette stakksporelementet, er en naturlig metode.

JDK 1.4 introduserte også StackTraceElement [] getStackTrace () metoden til java.lang.Tråd og Kastbar klasser. Denne metoden returnerer henholdsvis en matrise av stakksporelementer som representerer påkallertrådens stakkdump og gir programmatisk tilgang til stakkens sporingsinformasjon skrevet ut av printStackTrace ().

Oppføring 5 viser StackTraceElement og getStackTrace ().

Oppføring 5. StackTraceElementDemo.java (versjon 1)

importere java.io.IOException; offentlig klasse StackTraceElementDemo {public static void main (String [] args) kaster IOException {try {a (); } fange (IOException ioe) {StackTraceElement [] stackTrace = ioe.getStackTrace (); for (int i = 0; i <stackTrace.length; i ++) {System.err.println ("Unntak kastet fra" + stackTrace [i] .getMethodName () + "i klasse" + stackTrace [i] .getClassName () + "on line" + stackTrace [i] .getLineNumber () + "av fil" + stackTrace [i] .getFileName ()); System.err.println (); }}} statisk tomrom a () kaster IOException {b (); } statisk tomrom b () kaster IOException {kast nytt IOException (); }}

Når du kjører dette programmet, vil du observere følgende utdata:

Unntak kastet fra b i klasse StackTraceElementDemo på linje 33 i filen StackTraceElementDemo.java Unntak kastet fra en i klassen StackTraceElementDemo på linje 28 i filen StackTraceElementDemo.java Unntak kastet fra hoved i klasse StackTraceElementDemo på linje 9 i filen StackTraceElementDemo.java

Til slutt introduserte JDK 1.4 setStackTrace () metode til Kastbar. Denne metoden er designet for bruk av RPC-rammer (Remote Procedure Call) og andre avanserte systemer, slik at klienten kan overstyre standard stack-spor som genereres av fillInStackTrace () når en kastbar er konstruert.

Jeg har tidligere vist hvordan jeg kan overstyre fillInStackTrace () for å forhindre at det bygges en stabel. I stedet kan du installere en ny stakksporing ved å bruke StackTraceElement og setStackTrace (). Lag et utvalg av StackTraceElement objekter initialisert via følgende konstruktør, og overfører denne matrisen til setStackTrace ():

StackTraceElement (String deklarererClass, String methodName, String fileName, int lineNumber)

Oppføring 6 demonstrerer StackTraceElement og setStackTrace ().