Mikor dobja a Java az ExceptionInInitializerError programot?

1. Áttekintés

Ebben a gyors bemutatóban meg fogjuk vizsgálni, hogy mi okozza a Java-t a ExceptionInInitializerError kivétel.

Kezdjük egy kis elmélettel. Ezután a gyakorlatban látunk néhány példát erre a kivételre.

2. A ExceptionInInitializerError

A ExceptionInInitializerError azt jelzi, hogy váratlan kivétel történt egy statikus inicializálóban. Alapvetően, amikor ezt a kivételt látjuk, tudnunk kell, hogy a Java nem értékelte a statikus inicializáló blokkot, vagy nem példázott egy statikus változót.

Valójában minden alkalommal, amikor bármilyen kivétel történik egy statikus inicializálón belül, a Java automatikusan beburkolja ezt a kivételt a ExceptionInInitializerError osztály. Így fenntartja a tényleges kivételre, mint kiváltó okra való hivatkozást is.

Most, hogy tudjuk a kivétel okait, lássuk a gyakorlatban.

3. Statikus inicializáló blokk

A sikertelen statikus blokk inicializálásához egy egész számot szándékosan nullával osztunk el:

Public class StaticBlock {private static int állapot; statikus {állapot = 42/0; }}

Most, ha valami hasonlóval indítjuk az osztály inicializálását:

új StaticBlock ();

Ezután a következő kivételt látnánk:

java.lang.ExceptionInInitializerError at com.baeldung ... (ExceptionInInitializerErrorUnitTest.java:18) Okozta: java.lang.ArithmeticException: / nullával a com.baeldung.StaticBlock. (ExceptionInInitializerErjaUnitTest ...

Mint korábban említettük, a Java dobja a ExceptionInInitializerError kivétel, miközben megmarad a hivatkozás a kiváltó okra:

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

Érdemes megemlíteni azt is, hogy a módszer egy osztály inicializálási módszer a JVM-ben.

4. Statikus változó inicializálása

Ugyanez történik, ha a Java nem inicializálja a statikus változót:

nyilvános osztály StaticVar {private static int state = initizeState (); privát statikus int InitializeState () {dobjon új RuntimeException (); }}

Ismét, ha elindítjuk az osztály inicializálási folyamatát:

új StaticVar ();

Ekkor ugyanaz a kivétel fordul elő:

java.lang.ExceptionInInitializerError at com.baeldung ... (ExceptionInInitializerErrorUnitTest.java:11) Okozta: java.lang.RuntimeException at com.baeldung.StaticVar.initializeState (ExceptionInInitializerEstatorestrest.est.est.esticat.est.esticat.est.est) Comics ExceptionInInitializerErrorUnitTest.java:23) ... még 23

A statikus inicializáló blokkokhoz hasonlóan a kivétel kiváltó oka is megmaradt:

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

5. Ellenőrzött kivételek

A Java nyelvi specifikáció (JLS-11.2.3) részeként nem dobhatjuk be az ellenőrzött kivételeket egy statikus inicializáló blokkba vagy egy statikus változó inicializálóba. Például, ha megpróbáljuk ezt megtenni:

nyilvános osztály NoChecked {static {dobjon új Kivételt (); }}

A fordító a következő fordítási hibával bukik meg:

java: az inicializálónak képesnek kell lennie a normális befejezésre

Megállapodásként be kell vonni a lehetséges ellenőrzött kivételeket a ExceptionInInitializerError amikor a statikus inicializálási logikánk ellenőrzött kivételt dob:

public class CheckedConvention {private static Constructor konstruktor; statikus {try {konstruktor = CheckedConvention.class.getDeclaredConstructor (); } catch (NoSuchMethodException e) {dobja új ExceptionInInitializerError (e); }}}

Amint fentebb látható, a getDeclaredConstructor () metódus ellenőrzött kivételt dob. Ezért elkaptuk az ellenőrzött kivételt, és becsomagoltuk, ahogy az egyezmény javasolja.

Mivel már adunk vissza egy példányt ExceptionInInitializerError kivétel kifejezetten, a Java nem fogja beilleszteni ezt a kivételt egy másikba ExceptionInInitializerError példa.

Ha azonban bármilyen más ellenőrizetlen kivételt dobunk, akkor a Java dob egy újabbat ExceptionInInitializerError:

statikus {try {konstruktor = CheckedConvention.class.getConstructor (); } catch (NoSuchMethodException e) {dobjon új RuntimeException (e); }}

Itt bejelöljük a bejelölt kivételt egy nem ellenőrzöttbe. Mivel ez az ellenőrizetlen kivétel nem a ExceptionInInitializerError, A Java újra becsomagolja, és ez a váratlan veremkövetés lesz:

java.lang.ExceptionInInitializerError at com.baeldung.exceptionininitializererror ... Okozta: java.lang.RuntimeException: java.lang.NoSuchMethodException: ... Okozta: java.lang.NoSuchMhetbaExcon. java.base / java.lang.Class.getConstructor0 (Class.java:3427) a java.base / java.lang.Class.getConstructor (Class.java:2165)

Amint a fentiekből látható, ha követjük az egyezményt, akkor a veremnyom sokkal tisztább lenne ennél.

5.1. OpenJDK

Nemrégiben ezt a megállapodást még magában az OpenJDK forráskódban is használják. Például, itt van, hogyan AtomicReference ezt a megközelítést használja:

az AtomicReference nyilvános osztály a java.io.Serializable {private static final VarHandle VALUE; statikus {próbáld meg {MethodHandles.Lookup l = MethodHandles.lookup (); ÉRTÉK = l.findVarHandle (AtomicReference.class, "érték", Object.class); } catch (ReflectiveOperationException e) {dobjon új ExceptionInInitializerError (e); }} saját volatilis V értéke; // kihagyva}

6. Következtetés

Ebben az oktatóanyagban azt láttuk, hogy mi okozza a Java-t a ExceptionInInitializerError kivétel.

Szokás szerint az összes példa elérhető a GitHubon.