Når kaster Java ExceptionInInitializerError?

1. Oversikt

I denne raske opplæringen skal vi se hva som får Java til å kaste en forekomst av ExceptionInInitializerError unntak.

Vi begynner med litt teori. Så får vi se noen eksempler på dette unntaket i praksis.

2. Den ExceptionInInitializerError

De ExceptionInInitializerError indikerer at et uventet unntak har oppstått i en statisk initialisering. I utgangspunktet, når vi ser dette unntaket, bør vi vite at Java ikke klarte å evaluere en statisk initialiseringsblokk eller å sette i gang en statisk variabel.

Faktisk, hver gang noe unntak skjer i en statisk initialisering, pakker Java automatisk unntaket i en forekomst av ExceptionInInitializerError klasse. På denne måten opprettholder det også en referanse til det faktiske unntaket som grunnårsak.

Nå som vi vet begrunnelsen bak dette unntaket, la oss se det i praksis.

3. Statisk initialiseringsblokk

For å ha en mislykket initialisering av statisk blokk, skal vi dele et helt tall med null med vilje:

offentlig klasse StaticBlock {privat statisk int tilstand; statisk {tilstand = 42/0; }}

Nå hvis vi utløser klasseinitialisering med noe sånt som:

ny StaticBlock ();

Deretter vil vi se følgende unntak:

java.lang.ExceptionInInitializerError at com.baeldung ... (ExceptionInInitializerErrorUnitTest.java:18) Forårsaket av: java.lang.ArithmeticException: / av null ved com.baeldung.StaticBlock. (ExceptionInInitializerErrorUnitTest.java:35) ...

Som nevnt tidligere, kaster Java ExceptionInInitializerError unntak mens du opprettholder en referanse til grunnårsaken:

assertThatThrownBy (StaticBlock :: new) .isInstanceOf (ExceptionInInitializerError.class) .hasCauseInstanceOf (ArithmeticException.class);

Det er også verdt å nevne at metoden er en klasse initialiseringsmetode i JVM.

4. Statisk variabel initialisering

Det samme skjer hvis Java ikke klarer å initialisere en statisk variabel:

offentlig klasse StaticVar {private static int state = initializeState (); private static int initializeState () {throw new RuntimeException (); }}

Igjen, hvis vi utløser klasseinitialiseringsprosessen:

nye StaticVar ();

Da forekommer det samme unntaket:

java.lang.ExceptionInInitializerError at com.baeldung ... (ExceptionInInitializerErrorUnitTest.java:11) Forårsaket av: java.lang.RuntimeException på com.baeldung.StaticVar.initializeState (ExceptionInInitializerErrorUnitTest.javaar.26. at. ExceptionInInitializerErrorUnitTest.java:23) ... 23 mer

I likhet med statiske initialiseringsblokker bevares også årsaken til unntaket:

assertThatThrownBy (StaticVar :: new) .isInstanceOf (ExceptionInInitializerError.class) .hasCauseInstanceOf (RuntimeException.class);

5. Avmerkede unntak

Som en del av Java-språkspesifikasjonen (JLS-11.2.3), kan vi ikke kaste avmerkede unntak i en statisk initialiseringsblokk eller statisk variabel initialisering. For eksempel hvis vi prøver å gjøre det:

offentlig klasse NoChecked {static {throw new Exception (); }}

Kompilatoren mislyktes med følgende kompileringsfeil:

java: initialisereren må kunne fullføres normalt

Som en konvensjon, bør vi pakke inn de mulige kontrollerte unntakene i en forekomst av ExceptionInInitializerError når vår statiske initialiseringslogikk gir et merket unntak:

offentlig klasse CheckedConvention {private static Constructor constructor; statisk {prøv {constructor = CheckedConvention.class.getDeclaredConstructor (); } catch (NoSuchMethodException e) {throw new ExceptionInInitializerError (e); }}}

Som vist ovenfor, getDeclaredConstructor () metoden kaster et avkrysset unntak. Derfor fanget vi det avmerkede unntaket og pakket det inn som konvensjonen antyder.

Siden vi allerede returnerer en forekomst av ExceptionInInitializerError unntak eksplisitt, vil Java ikke pakke dette unntaket inn i enda en annen ExceptionInInitializerError forekomst.

Men hvis vi kaster noe annet ukontrollert unntak, vil Java kaste et annet ExceptionInInitializerError:

statisk {prøv {constructor = CheckedConvention.class.getConstructor (); } catch (NoSuchMethodException e) {throw new RuntimeException (e); }}

Her pakker vi det avmerkede unntaket i et ukontrollert. Fordi dette ukontrollerte unntaket ikke er en forekomst av UnntakInInitializerError, Java vil pakke det inn igjen, noe som resulterer i dette uventede stabelsporet:

java.lang.ExceptionInInitializerError at com.baeldung.exceptionininitializererror ... Forårsaket av: java.lang.RuntimeException: java.lang.NoSuchMethodException: ... Forårsaket av: java.lang.NoSuchMethodException: com.baeldung.CheckedCon java.base / java.lang.Class.getConstructor0 (Class.java:3427) på java.base / java.lang.Class.getConstructor (Class.java:2165)

Som vist ovenfor, hvis vi følger konvensjonen, ville stabelsporet være mye renere enn dette.

5.1. OpenJDK

Nylig er denne konvensjonen til og med brukt i selve OpenJDK-kildekoden. For eksempel, her er hvordan AtomicReference bruker denne tilnærmingen:

offentlig klasse AtomicReference implementerer java.io.Serializable {privat statisk slutt VarHandle VERDI; statisk {prøv {MethodHandles.Lookup l = MethodHandles.lookup (); VERDI = l.findVarHandle (AtomicReference.class, "value", Object.class); } catch (ReflectiveOperationException e) {throw new ExceptionInInitializerError (e); }} privat flyktig V-verdi; // utelatt}

6. Konklusjon

I denne opplæringen så vi hva som får Java til å kaste en forekomst av ExceptionInInitializerError unntak.

Som vanlig er alle eksemplene tilgjengelige på GitHub.


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