giovedì 13 dicembre 2012

Differenza tra ClassNotFoundException e NoClassDefFoundError

Le due eccezioni sono concettualmente simili (manca qualche jar o .class nel classpath) ma è diversa la tipologia di eccezione, la ClassNotFoundException è di tipo checked (che estende dunque da java.lang.Exception e che ha bisogno del try/catch) mentre la NoClassDefFoundError è di tipo Error , quindi unchecked

java.lang.ClassNotFoundException

L' eccezione ClassNotFoundException si verifica quando una applicazione tenta di chiamare una classe utilizzando :

  • Il metodo forName nella classe Class.
  • Il metodo findSystemClass nella classe  ClassLoader .
  • Il metodo loadClass nella classe ClassLoader
Esempio classico:


public static void main(String[] args) throws Exception{
  Class c=Class.forName("classenonEsistente");
  System.out.println(c.getName());
 }


Tale codice produce il seguente risultato:

Exception in thread "main" java.lang.ClassNotFoundException: classenonEsistente
 at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
 at java.lang.Class.forName0(Native Method)
 at java.lang.Class.forName(Class.java:169)
 at ExceptionSample.main(ExceptionSample.java:5)



java.lang.NoClassDefException

Questa eccezione è sollevata dalla JVM quando cerca di caricare una classe a runtime e non la trova.
E' una sottoclasse di java.lang.LinkageError, il problema è che la classe che stiamo chiamando ne utilizza un'altra a runtime non presente.
Il classico esempio si ha quando proviamo ad invocare da console una classe java dimenticandoci il nome completo del package (il classico Hello World che all'inizio non funziona mai).
Esempio:
Supponiamo di utilizzare la libreria jmimemagic (descritta in un precedente post) e di usarla dimenticandoci di aggiungere al classpath la libreria commons-logging.jar.
Il codice compila correttamente, in quanto la nostra classe richiama esclusivamente la classe MagicMatcher che fa parte della libreria jmimemagic e che è inclusa nel classpath.

A  Runtime abbiamo una NoClassDefException .


public static void main(String[] args)  {
  try
  {
  Magic m=new Magic();
  byte[] lb=FileUtil.load(new File("file/WS.png"));
  MagicMatch match = m.getMagicMatch(lb);
  System.out.println(match.getMimeType());
  }
  catch (Exception e) {
   System.out.println("Eccezione!!!");
   e.printStackTrace();
  }
 }


Eseguendo il codice non si passa per il catch (si ricordi che l'eccezione è sottoclasse di LinkageError e quindi di Throwable, non di Exception) e in console sarà stampata direttamente la NoClassDefException, nel cui stacktrace troviamo anche l'origine dell'errore, che è una eccezione di tipo ClassNotFoundException per l'appunto.

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
 at net.sf.jmimemagic.Magic.(Magic.java:46)
 at MatchMagic.main(MatchMagic.java:21)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
 at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
 ... 2 more


Nessun commento:

Posta un commento