Kada Java baca ExceptionInInitializerError?

1. Pregled

U ovom brzom vodiču vidjet ćemo što uzrokuje da Java baci instancu ExceptionInInitializerError iznimka.

Počet ćemo s malo teorije. Tada ćemo u praksi vidjeti nekoliko primjera ove iznimke.

2. The ExceptionInInitializerError

The ExceptionInInitializerError označava da se u statičkom inicijalizatoru dogodila neočekivana iznimka. U osnovi, kad vidimo ovu iznimku, trebali bismo znati da Java nije uspjela procijeniti statički blok inicijalizatora ili pokrenuti statičku varijablu.

U stvari, svaki put kad se bilo koja iznimka dogodi unutar statičkog inicijalizatora, Java automatski umota tu iznimku u instancu ExceptionInInitializerError razred. Na taj način, također se zadržava referenca na stvarnu iznimku kao osnovni uzrok.

Sad kad znamo obrazloženje ove iznimke, pogledajmo to u praksi.

3. Blok statičkog pokretača

Da bismo imali neuspjeli pokretač statičkog bloka, namjerno ćemo podijeliti cijeli broj s nulom:

javna klasa StaticBlock {private static int state; statički {stanje = 42/0; }}

Sada ako pokrenemo inicijalizaciju klase nečim poput:

novi StaticBlock ();

Tada bismo vidjeli sljedeću iznimku:

java.lang.ExceptionInInitializerError na com.baeldung ... (ExceptionInInitializerErrorUnitTest.java:18) Uzrok: java.lang.ArithmeticException: / nula na com.baeldung.StaticBlock. (ExceptionInInitializerErrorUnitTest 23 more.java

Kao što je ranije spomenuto, Java baca ExceptionInInitializerError iznimka uz održavanje reference na osnovni uzrok:

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

Također je vrijedno spomenuti da metoda je metoda inicijalizacije klase u JVM-u.

4. Inicijalizacija statičke varijable

Ista se stvar događa ako Java ne uspije inicijalizirati statičku varijablu:

javna klasa StaticVar {private static int state = initializeState (); privatni statički int initializeState () {baciti novi RuntimeException (); }}

Opet, ako pokrenemo postupak inicijalizacije klase:

novi StaticVar ();

Tada se javlja ista iznimka:

java.lang.ExceptionInInitializerError na com.baeldung ... (ExceptionInInitializerErrorUnitTest.java:11) Uzročnik: java.lang.RuntimeException na com.baeldung.StaticVar.initializeState (ExceptionInInitializerErrorUnitTta.tata. ExceptionInInitializerErrorUnitTest.java:23) ... još 23

Slično statičkim blokovima inicijalizatora, i osnovni uzrok iznimke je sačuvan:

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

5. Označene iznimke

Kao dio specifikacije jezika Java (JLS-11.2.3), provjerene iznimke ne možemo ubaciti u blok statičkog inicijalizatora ili pokretač statičke varijable. Na primjer, ako to pokušamo učiniti:

javna klasa NoChecked {static {throw new Exception (); }}

Prevodnik ne bi uspio sa sljedećom pogreškom kompilacije:

java: inicijalizator mora biti u mogućnosti normalno dovršiti

Kao dogovor, trebali bismo omotati moguće provjerene iznimke unutar instance ExceptionInInitializerError kada naša logika statičke inicijalizacije baci provjereni izuzetak:

javna klasa CheckedConvention {privatni statički konstruktor konstruktora; static {try {constructor = CheckedConvention.class.getDeclaredConstructor (); } catch (NoSuchMethodException e) {throw new ExceptionInInitializerError (e); }}}

Kao što je gore prikazano, getDeclaredConstructor () metoda baca provjerenu iznimku. Stoga smo uhvatili provjerenu iznimku i omotali je kako konvencija sugerira.

Budući da već vraćamo primjerak ExceptionInInitializerError iznimke izričito, Java ovu iznimku neće umotati u još jednu ExceptionInInitializerError primjer.

Međutim, ako bacimo bilo koju drugu neprovjerenu iznimku, Java će baciti drugu ExceptionInInitializerError:

static {try {constructor = CheckedConvention.class.getConstructor (); } catch (NoSuchMethodException e) {throw new RuntimeException (e); }}

Ovdje uvrćujemo provjerenu iznimku u neprovjerenu. Budući da ova neprovjerena iznimka nije instanca ExceptionInInitializerError, Java će ga ponovno omotati, što će rezultirati ovim neočekivanim praćenjem stoga:

java.lang.ExceptionInInitializerError na com.baeldung.exceptionininitializererror ... Uzrok: java.lang.RuntimeException: java.lang.NoSuchMethodException: ... Uzrok: java.lang.NoSuchMethodException:. java.base / java.lang.Class.getConstructor0 (Class.java:3427) na java.base / java.lang.Class.getConstructor (Class.java:2165)

Kao što je gore prikazano, ako slijedimo konvenciju, trag steka bio bi puno čišći od ovog.

5.1. OpenJDK

Nedavno se ova konvencija koristi čak i u samom izvornom kodu OpenJDK. Na primjer, evo kako AtomicReference koristi ovaj pristup:

javna klasa AtomicReference provodi java.io.Serializable {privatni statički konačni VarHandle VALUE; static {try {MethodHandles.Lookup l = MethodHandles.lookup (); VRIJEDNOST = l.findVarHandle (AtomicReference.class, "value", Object.class); } catch (ReflectiveOperationException e) {throw new ExceptionInInitializerError (e); }} privatna hlapljiva V vrijednost; // izostavljeno}

6. Zaključak

U ovom smo tutorijalu vidjeli što Java uzrokuje bacanje instance ExceptionInInitializerError iznimka.

Kao i obično, svi su primjeri dostupni na GitHubu.