ClassNotFoundException vs NoClassDefFoundError

1. Introduzione

Sia ClassNotFoundException che NoClassDefFoundError si verificano quando la JVM non riesce a trovare una classe richiesta sul classpath. Sebbene sembrino familiari, ci sono alcune differenze fondamentali tra questi due.

In questo tutorial, discuteremo alcuni dei motivi delle loro occorrenze e delle loro soluzioni.

2. ClassNotFoundException

ClassNotFoundException è un'eccezione controllata che si verifica quando un'applicazione tenta di caricare una classe tramite il suo nome completo e non riesce a trovare la sua definizione sul classpath.

Ciò si verifica principalmente quando si cerca di caricare le classi utilizzando Class.forName () , ClassLoader.loadClass () o ClassLoader.findSystemClass () . Pertanto, dobbiamo stare molto attenti a java.lang.ClassNotFoundException mentre lavoriamo con la reflection.

Ad esempio, proviamo a caricare la classe del driver JDBC senza aggiungere le dipendenze necessarie che ci daranno ClassNotFoundException:

@Test(expected = ClassNotFoundException.class) public void givenNoDrivers_whenLoadDriverClass_thenClassNotFoundException() throws ClassNotFoundException { Class.forName("oracle.jdbc.driver.OracleDriver"); }

3. NoClassDefFoundError

NoClassDefFoundError è un errore irreversibile. Si verifica quando JVM non riesce a trovare la definizione della classe durante il tentativo di:

  • Crea un'istanza di una classe utilizzando la nuova parola chiave
  • Carica una classe con una chiamata al metodo

L'errore si verifica quando un compilatore può compilare correttamente la classe, ma il runtime Java non è in grado di individuare il file di classe. Di solito accade quando si verifica un'eccezione durante l'esecuzione di un blocco statico o l'inizializzazione dei campi statici della classe, quindi l'inizializzazione della classe fallisce.

Consideriamo uno scenario che è un modo semplice per riprodurre il problema. L' inizializzazione di ClassWithInitErrors genera un'eccezione. Quindi, quando proviamo a creare un oggetto di ClassWithInitErrors, viene lanciato ExceptionInInitializerError.

Se proviamo a caricare di nuovo la stessa classe, otteniamo NoClassDefFoundError:

public class ClassWithInitErrors { static int data = 1 / 0; }
public class NoClassDefFoundErrorExample { public ClassWithInitErrors getClassWithInitErrors() { ClassWithInitErrors test; try { test = new ClassWithInitErrors(); } catch (Throwable t) { System.out.println(t); } test = new ClassWithInitErrors(); return test; } }

Scriviamo un test case per questo scenario:

@Test(expected = NoClassDefFoundError.class) public void givenInitErrorInClass_whenloadClass_thenNoClassDefFoundError() { NoClassDefFoundErrorExample sample = new NoClassDefFoundErrorExample(); sample.getClassWithInitErrors(); }

4. Risoluzione

A volte, diagnosticare e risolvere questi due problemi può richiedere molto tempo. Il motivo principale di entrambi i problemi è l'indisponibilità del file di classe (nel classpath) in fase di esecuzione.

Diamo un'occhiata ad alcuni approcci che possiamo considerare quando si tratta di uno di questi:

  1. Dobbiamo assicurarci che la classe o il jar contenente quella classe sia disponibile nel classpath. In caso contrario, dobbiamo aggiungerlo
  2. Se è disponibile nel percorso di classe dell'applicazione, molto probabilmente il percorso di classe viene sovrascritto. Per risolvere questo problema dobbiamo trovare il classpath esatto utilizzato dalla nostra applicazione
  3. Inoltre, se un'applicazione utilizza più programmi di caricamento classi, le classi caricate da un programma di caricamento classi potrebbero non essere disponibili da altri programmi di caricamento classi. Per risolverlo bene, è essenziale sapere come funzionano i classloader in Java

5. Riepilogo

Sebbene entrambe queste eccezioni siano correlate al percorso di classe e al runtime Java che non è in grado di trovare una classe in fase di esecuzione, è importante notare le loro differenze.

Il runtime Java genera ClassNotFoundException durante il tentativo di caricare una classe solo in runtime e il nome è stato fornito durante il runtime. Nel caso di NoClassDefFoundError, la classe era presente in fase di compilazione, ma il runtime Java non è riuscito a trovarla nel classpath Java durante il runtime.

Come sempre, il codice completo per tutti gli esempi può essere trovato su GitHub.