ClassNotFoundException vs NoClassDefFoundError

1. Uvod

Oba ClassNotFoundException i NoClassDefFoundError javljaju se kada JVM ne može pronaći traženu klasu na putu predavanja. Iako izgledaju poznato, između ove dvije postoje neke osnovne razlike.

U ovom uputstvu razmotrit ćemo neke od razloga njihovih pojava i njihova rješenja.

2. ClassNotFoundException

ClassNotFoundException je provjerena iznimka koja se događa kada aplikacija pokušava učitati klasu kroz njezino potpuno kvalificirano ime i ne može pronaći njezinu definiciju na putu klase.

To se uglavnom događa kada pokušavate učitati klase pomoću Class.forName (), ClassLoader.loadClass () ili ClassLoader.findSystemClass (). Stoga moramo biti posebno oprezni java.lang.ClassNotFoundException dok radim s refleksijom.

Na primjer, pokušajmo učitati klasu JDBC upravljačkog programa bez dodavanja potrebnih ovisnosti koje će nas dobiti ClassNotFoundException:

@Test (očekuje se = ClassNotFoundException.class) javna praznina givenNoDrivers_whenLoadDriverClass_thenClassNotFoundException () baca ClassNotFoundException {Class.forName ("oracle.jdbc.driver.OracleDriver"); }

3. NoClassDefFoundError

NoClassDefFoundError je fatalna pogreška. To se događa kada JVM ne može pronaći definiciju klase dok pokušava:

  • Instancirajte predavanje pomoću novi ključna riječ
  • Učitajte klasu pozivom metode

Pogreška se događa kada je kompajler mogao uspješno kompilirati klasu, ali Java runtime nije mogao pronaći datoteku klase. Obično se to dogodi kada postoji iznimka tijekom izvršavanja statičkog bloka ili inicijalizacije statičkih polja klase, pa inicijalizacija klase ne uspije.

Razmotrimo scenarij koji je jedan od jednostavnih načina za reprodukciju problema. ClassWithInitErrors inicijalizacija baca iznimku. Dakle, kada pokušavamo stvoriti objekt od ClassWithInitErrors, baca ExceptionInInitializerError.

Ako pokušamo ponovo učitati istu klasu, dobit ćemo NoClassDefFoundError:

javna klasa ClassWithInitErrors {static int data = 1/0; }
javna klasa NoClassDefFoundErrorExample {public ClassWithInitErrors getClassWithInitErrors () {Test ClassWithInitErrors; isprobajte {test = new ClassWithInitErrors (); } catch (Throwable t) {System.out.println (t); } test = nove ClassWithInitErrors (); povratni test; }}

Napišimo test za ovaj scenarij:

@Test (očekuje se = NoClassDefFoundError.class) javna praznina givenInitErrorInClass_whenloadClass_thenNoClassDefFoundError () {NoClassDefFoundErrorExample sample = new NoClassDefFoundErrorExample (); sample.getClassWithInitErrors (); }

4. Razlučivost

Ponekad dijagnosticiranje i rješavanje ova dva problema može biti prilično dugotrajno. Glavni razlog oba problema je nedostupnost datoteke klase (u stazi razreda) za vrijeme izvođenja.

Pogledajmo nekoliko pristupa koje možemo uzeti u obzir kada se bavimo bilo kojim od ovih:

  1. Moramo biti sigurni je li klasa ili staklenka koja sadrži taj razred dostupna na putu predavanja. Ako nije, trebamo ga dodati
  2. Ako je dostupan na stazi klase aplikacije, tada se najvjerojatnije classpath zamjenjuje. Da bismo to popravili, moramo pronaći točan put do klase koji koristi naša aplikacija
  3. Također, ako aplikacija koristi učitavače više klasa, učitavači koje učitava jedan učitavač klase možda neće biti dostupni drugim učitavačima klasa. Da biste ga dobro riješili, bitno je znati kako učitavači razreda rade na Javi

5. Sažetak

Iako su obje ove iznimke povezane s putovima razreda i Java runtimeom koji ne mogu pronaći klasu u vrijeme izvođenja, važno je primijetiti njihove razlike.

Java runtime baca ClassNotFoundException dok je pokušavao učitati klasu samo u vrijeme izvođenja, a ime je navedeno tijekom izvođenja. U slučaju NoClassDefFoundError, class je bio prisutan u vrijeme kompajliranja, ali Java runtime ga nije mogao pronaći u Java classpathu za vrijeme izvođenja.

Kao i uvijek, cjelovit kod za sve primjere možete pronaći na GitHubu.