ClassNotFoundException versus NoClassDefFoundError

1. Inleiding

Beide ClassNotFoundException en NoClassDefFoundError treden op als de JVM een gevraagde klasse niet kan vinden op het klassenpad. Hoewel ze er bekend uitzien, zijn er enkele kernverschillen tussen deze twee.

In deze tutorial bespreken we enkele van de redenen voor hun optreden en hun oplossingen.

2. ClassNotFoundException

ClassNotFoundException is een aangevinkte uitzondering die optreedt wanneer een toepassing probeert een klasse te laden via zijn volledig gekwalificeerde naam en de definitie ervan niet kan vinden op het klassenpad.

Dit gebeurt voornamelijk wanneer u probeert klassen te laden met Class.forName (), ClassLoader.loadClass () of ClassLoader.findSystemClass (). Daarom moeten we hier extra voorzichtig mee zijn java.lang.ClassNotFoundException tijdens het werken met reflectie.

Laten we bijvoorbeeld proberen de JDBC-stuurprogrammaklasse te laden zonder de nodige afhankelijkheden toe te voegen, waardoor we ClassNotFoundException:

@Test (verwacht = ClassNotFoundException.class) openbare ongeldige gegevenNoDrivers_whenLoadDriverClass_thenClassNotFoundException () gooit ClassNotFoundException {Class.forName ("oracle.jdbc.driver.OracleDriver"); }

3. NoClassDefFoundError

NoClassDefFoundError is een fatale fout. Het treedt op wanneer JVM de definitie van de klasse niet kan vinden tijdens het proberen om:

  • Start een klas met behulp van de nieuw trefwoord
  • Laad een klasse met een methodeaanroep

De fout treedt op wanneer een compiler de klasse met succes kon compileren, maar Java Runtime het klassenbestand niet kon vinden. Het gebeurt meestal als er een uitzondering is tijdens het uitvoeren van een statisch blok of het initialiseren van statische velden van de klasse, dus de initialisatie van de klasse mislukt.

Laten we eens kijken naar een scenario dat een eenvoudige manier is om het probleem te reproduceren. ClassWithInitErrors initialisatie genereert een uitzondering. Dus als we proberen een object van te maken ClassWithInitErrors, het gooit ExceptionInInitializerError.

Als we dezelfde klasse opnieuw proberen te laden, krijgen we de NoClassDefFoundError:

openbare klasse ClassWithInitErrors {statische int data = 1/0; }
openbare klasse NoClassDefFoundErrorExample {openbare ClassWithInitErrors getClassWithInitErrors () {ClassWithInitErrors-test; probeer {test = nieuwe ClassWithInitErrors (); } catch (Throwable t) {System.out.println (t); } test = nieuwe ClassWithInitErrors (); terugkeer test; }}

Laten we een testcase schrijven voor dit scenario:

@Test (verwacht = NoClassDefFoundError.class) openbare ongeldige gegevenInitErrorInClass_whenloadClass_thenNoClassDefFoundError () {NoClassDefFoundErrorExample sample = nieuwe NoClassDefFoundErrorExample (); sample.getClassWithInitErrors (); }

4. Resolutie

Soms kan het behoorlijk tijdrovend zijn om deze twee problemen te diagnosticeren en op te lossen. De belangrijkste reden voor beide problemen is de onbeschikbaarheid van het klassenbestand (in het klassenpad) tijdens runtime.

Laten we eens kijken naar enkele benaderingen die we kunnen overwegen bij het omgaan met een van deze:

  1. We moeten er zeker van zijn of class of jar met die class beschikbaar is in het classpath. Zo niet, dan moeten we het toevoegen
  2. Als het beschikbaar is op het klassenpad van de toepassing, wordt het klassenpad hoogstwaarschijnlijk overschreven. Om dat op te lossen, moeten we het exacte klassenpad vinden dat door onze applicatie wordt gebruikt
  3. Als een toepassing meerdere klassenladers gebruikt, zijn klassen die door één klassenlader zijn geladen, mogelijk niet beschikbaar voor andere klassenladers. Om het probleem goed op te lossen, is het essentieel om te weten hoe classloaders in Java werken

5. Samenvatting

Hoewel beide uitzonderingen verband houden met classpath en Java-runtime geen klasse kunnen vinden tijdens runtime, is het belangrijk om hun verschillen te noteren.

Java-runtime gooit ClassNotFoundException tijdens het laden van een klasse alleen tijdens runtime en de naam werd opgegeven tijdens runtime. In het geval van NoClassDefFoundError, het class was aanwezig tijdens het compileren, maar Java runtime kon het niet vinden in Java classpath tijdens runtime.

Zoals altijd is de volledige code voor alle voorbeelden te vinden op GitHub.