Hvornår kaster Java ExceptionInInitializerError?

1. Oversigt

I denne hurtige vejledning skal vi se, hvad der får Java til at kaste en forekomst af ExceptionInInitializerError undtagelse.

Vi starter med en lille smule teori. Så ser vi et par eksempler på denne undtagelse i praksis.

2. Den ExceptionInInitializerError

Det ExceptionInInitializerError angiver, at der er sket en uventet undtagelse i en statisk initialisering. Dybest set, når vi ser denne undtagelse, skal vi vide, at Java ikke evaluerede en statisk initialiseringsblok eller at instantere en statisk variabel.

Faktisk hver gang en undtagelse sker i en statisk initialisering, indpakker Java automatisk denne undtagelse i en forekomst af ExceptionInInitializerError klasse. På denne måde opretholder den også en henvisning til den faktiske undtagelse som grundårsagen.

Nu hvor vi kender begrundelsen bag denne undtagelse, lad os se det i praksis.

3. Statisk initialiseringsblok

For at have en mislykket statisk blokinitialisering deler vi et heltal med nul med vilje:

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

Nu hvis vi udløser klassens initialisering med noget som:

ny StaticBlock ();

Derefter ser vi følgende undtagelse:

java.lang.ExceptionInInitializerError at com.baeldung ... (ExceptionInInitializerErrorUnitTest.java:18) Forårsaget af: java.lang.ArithmeticException: / ved nul ved com.baeldung.StaticBlock. (ExceptionInInitializerErrorUnitTest.java:35) ...

Som tidligere nævnt kaster Java ExceptionInInitializerError undtagelse og samtidig opretholde en henvisning til grundårsagen:

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

Det er også værd at nævne, at metode er en klasse initialiseringsmetode i JVM.

4. Statisk variabel initialisering

Den samme ting sker, hvis Java ikke initialiserer en statisk variabel:

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

Igen, hvis vi udløser klassens initialiseringsproces:

ny StaticVar ();

Derefter forekommer den samme undtagelse:

java.lang.ExceptionInInitializerError at com.baeldung ... (ExceptionInInitializerErrorUnitTest.java:11) Forårsaget af: java.lang.RuntimeException på com.baeldung.StaticVar.initializeState (ExceptionInInitializerErrorUnitTest.javaar. 26. at. com. at. ExceptionInInitializerErrorUnitTest.java:23) ... 23 mere

I lighed med statiske initialiseringsblokke bevares grundårsagen til undtagelsen også:

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

5. Kontrollerede undtagelser

Som en del af Java-sprogspecifikationen (JLS-11.2.3) kan vi ikke smide kontrollerede undtagelser inde i en statisk initialiseringsblok eller en statisk variabel initialisering. For eksempel, hvis vi prøver at gøre det:

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

Compileren mislykkedes med følgende kompileringsfejl:

java: initialisering skal kunne udføres normalt

Som en konvention bør vi indpakke de mulige kontrollerede undtagelser i en forekomst af ExceptionInInitializerError når vores statiske initialiseringslogik kaster en kontrolleret undtagelse:

offentlig klasse CheckedConvention {privat statisk konstruktør konstruktør; statisk {prøv {constructor = CheckedConvention.class.getDeclaredConstructor (); } fange (NoSuchMethodException e) {kast ny ExceptionInInitializerError (e); }}}

Som vist ovenfor er getDeclaredConstructor () metode kaster en kontrolleret undtagelse. Derfor fangede vi den afkrydsede undtagelse og pakket den som konventionen antyder.

Da vi allerede returnerer en forekomst af ExceptionInInitializerError undtagelse eksplicit, vil Java ikke pakke denne undtagelse ind i endnu en anden ExceptionInInitializerError eksempel.

Men hvis vi kaster enhver anden ukontrolleret undtagelse, kaster Java en anden ExceptionInInitializerError:

statisk {prøv {constructor = CheckedConvention.class.getConstructor (); } fange (NoSuchMethodException e) {kast ny RuntimeException (e); }}

Her indpakker vi den afkrydsede undtagelse i en ukontrolleret. Fordi denne ukontrollerede undtagelse ikke er en forekomst af UndtagelseInInitializerError, Java indpakker det igen, hvilket resulterer i dette uventede stakspor:

java.lang.ExceptionInInitializerError at com.baeldung.exceptionininitializererror ... Forårsaget af: java.lang.RuntimeException: java.lang.NoSuchMethodException: ... Forårsaget af: 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 konventionen, ville stacksporingen være meget renere end dette.

5.1. OpenJDK

For nylig er denne konvention endda brugt i selve OpenJDK-kildekoden. For eksempel er her, hvordan AtomicReference bruger denne tilgang:

offentlig klasse AtomicReference implementerer java.io.Serializable {privat statisk endelig VarHandle VALUE; statisk {prøv {MethodHandles.Lookup l = MethodHandles.lookup (); VALUE = l.findVarHandle (AtomicReference.class, "value", Object.class); } fange (ReflectiveOperationException e) {throw new ExceptionInInitializerError (e); }} privat flygtig V-værdi; // udeladt}

6. Konklusion

I denne vejledning så vi, hvad der får Java til at smide en forekomst af ExceptionInInitializerError undtagelse.

Som sædvanligt er alle eksemplerne tilgængelige på GitHub.


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