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.