2013-04-02 10 views
15

Quando eseguo questo codice le uscite app con un ClassNotFoundException:Se un NoClassDefFoundError è causato da una classe ClassNotFoundException, perché Java si aspetta che sia possibile catturare entrambi i materiali da gettare?

//uncaught ClassNotFoundException 
try 
{ 
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null); 
    table.put(clazz.getName(), clazz); 
} 
catch (NoClassDefFoundError e) 
{ 
} 

Quando tento di compilare questo codice, il compilatore si lamenta che il ClassNotFoundException non è raggiungibile perché non si butta all'interno del try-clausola la dichiarazione try-catch.

//Won't compile 
try 
{ 
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null); 
    table.put(clazz.getName(), clazz); 
} 
catch (ClassNotFoundException e) 
{ 
} 

Quando ho eseguito questo codice, l'unica throwable che viene catturato è un NoClassDefFoundError.

//catches throwable of type java.lang.NoClassDefFoundError, 
//with a java.lang.ClassNotFoundException as its cause 
try 
{ 
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null); 
    table.put(clazz.getName(), clazz); 
} 
catch (Throwable e) 
{ 
    System.out.println(e.getClass().getName()); 
    System.out.println(e.getCause().getClass().getName()); 
} 

Il seguente codice compilare e intercettare l'errore (e solo l'errore), ma è goffo:

//possible workaround 
try 
{ 
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null); 
    table.put(clazz.getName(), clazz); 
    if (1 == 0) throw new ClassNotFoundException(); // we want the code to compile 
} 
catch (ClassNotFoundException e) 
{ 
    System.out.println("ex"); 
} 
catch (NoClassDefFoundError e) 
{ 
    System.out.println("err"); 
} 

Eppure quando scrivo quanto segue, posso ottenere via senza una clausola catch per la causa dell'errore:

//and yet this works just fine... 
try 
{ 
    throw new Error(new IOException()); 
} 
catch (Error e) 
{ 
    System.out.println("err"); 
} 

Esempio 3 mi porterebbe a concludere che il throwable era un NoClassDefFoundError. L'esempio 1 mi porterebbe a concludere che il throwable era una ClassNotFoundException. Eppure, l'Esempio 2 mostra che java non mi lascerà nemmeno scrivere codice per catturare correttamente ClassNotFoundException.

Proprio quando stavo per concludere che il problema qui è l'errore-causato-da-un'eccezione, ho eseguito il codice mostrato nell'esempio precedente che mostra che quella non è la regola.

Qualcuno può spiegare cosa sta succedendo qui?

PS: questa è la traccia stack:

java.lang.NoClassDefFoundError: com/my/pckage/MyClass 
at java.lang.ClassLoader.defineClass1(Native Method) 
at java.lang.ClassLoader.defineClass(ClassLoader.java:791) 
at Main$MyClassLoader.getClasses(Main.java:78) 
at Main.main(Main.java:109) 
Caused by: java.lang.ClassNotFoundException: com.my.pckage.MyClass 
at java.lang.ClassLoader.findClass(ClassLoader.java:522) 
at java.lang.ClassLoader.loadClass(ClassLoader.java:423) 
at java.lang.ClassLoader.loadClass(ClassLoader.java:356) 
... 4 more 
+0

Qualcosa non si aggiunge. Presumibilmente, stai scrivendo un caricatore di classi personalizzato, includi eventuali metodi sovrascritti che potresti aver definito per esso. – Perception

+1

'defineClass' non genera ClassNotFoundException. Se ricevi questa eccezione, viene da qualche altra parte. –

+1

@ j-smith È meglio se si può dare una sscce per mostrare il problema. Ci sono alcune possibilità per l'eccezione ineguagliata. Ad esempio, l'eccezione "finale" che causa l'uscita dell'app può essere generata da un livello esterno, per il quale cattura il tuo NoClassDefFoundError e rethrow con ClassNotFoundException. È meglio se puoi controllare la "causa" dell'eccezione e lo stack di chiamate nell'eccezione. Ti dà un'idea su dove l'eccezione è effettivamente originata. –

risposta

1

NoClassDefFoundError è in realtà una sottoclasse di Error e questi non devono essere catturati. Vedi lo docs of Error per i dettagli. La nota importante qui sotto:

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions.

A method is not required to declare in its throws clause any subclasses of Error that might be thrown during the execution of the method but not caught, since these errors are abnormal conditions that should never occur.

Per questo motivo, penso che si dovrebbe dare un'occhiata più da vicino il codice per vedere che cosa si sta facendo male.

-1

Come già sottolineato, Java non consente di gestire gli errori.

In ogni caso, non sono sicuro di quali siano le ragioni per tentare di aggirare queste eccezioni (e gli errori), ma si tratta di eventi di cui i programmatori non hanno realmente bisogno di preoccuparsi (il più delle volte). Per me questo è un sintomo che c'è un problema altrove nel tuo codice/progetto. Se il sistema lancia un ClassNotFoundException e ti permette di prenderlo, come lo gestiresti? O preferisci affrontare il problema reale che una determinata classe richiesta dalla tua applicazione non è nel classpath?

Inoltre, è possibile controllare lo difference between NoClassDefFoundError and ClassNotFoundException per risolvere il problema.

+5

Non è vero che java non ti consentirà di gestire gli errori. –

+1

Sì, puoi sicuramente "gestire" gli errori, dal punto di vista puramente meccanico di prenderli. In generale, tuttavia, potresti non essere in grado di ripulire * * in modo pulito da essi. –

+1

@JSmith - In generale, le applicazioni ragionevoli non gestiscono ** gli errori ** e le ** eccezioni non controllate **.Piuttosto, applicherebbero tali condizioni/meccanismi in modo da evitare che tali errori o eccezioni vengano lanciati, quindi, non si tratta di gestirli. Direi che dovrebbero essere prevenuti (dagli sviluppatori dell'applicazione) prima che vengano lanciati. – Lion

4

NoClassDefFoundError si verifica quando viene trovata la classe .class per una classe, ma la classe non può essere costruita da tale classe.

Ci sono diversi scenari che si verificano comunemente, più alcuni più oscuri.

  • Il file .class contiene un nome (e pacchetto) che non corrisponde al nome del file di classe/package
  • Una classe che era necessario per verificare e inizializzare la classe non è stata trovata
  • un errore si è verificato durante l'inizializzazione della classe

Nella maggior parte di questi scenari c'è un altro errore o eccezione che si verifica in precedenza, viene rilevato dal programma di caricamento classe e viene segnalato il nuovo errore.

Non è chiaro esattamente quale scenario si sta verificando nella traccia di eccezioni sopra, ma sto indovinando un qualche tipo di mancata corrispondenza del nome.

12

Quindi, si sta fraintendendo la traccia dello stack.

java.lang.NoClassDefFoundError: com/my/package/MyClass 
    at java.lang.ClassLoader.defineClass1(Native Method) 
    at java.lang.ClassLoader.defineClass(ClassLoader.java:791) 
    at Main$MyClassLoader.getClasses(Main.java:78) 
    at Main.main(Main.java:109) 
Caused by: java.lang.ClassNotFoundException: com.my.package.MyClass 

Il codice sta generando un NoClassDefFoundError. La causa sottostanteè un ClassNotFoundException. Ricorda che cause è una proprietà della classe Throwable e che durante la stampa di stacktraces, Java visualizzerà le informazioni sia sull'eccezione diretta che sulle cause sottostanti. È più difficile dire perché il metodo define non funziona internamente, ma una cosa è certa: non è possibile utilizzare la parola chiave package in un nome di pacchetto.

+1

Il fatto che il codice stia generando un NoClassDefFoundError con una causa sottostante di ClassNotFoundException non risponde alla domanda. Ho anche confermato che questo comportamento insolito persiste anche con un nome convenzionale del pacchetto. –

+0

@JSmith - per favore pubblica il tuo codice che mostra una ClassNotFoundException lanciata da un metodo 'defineClass' che viene chiamato, senza tuttavia consentire un blocco catch esplicito. – Perception

+0

@JSmith La risposta di Perception risponde molto bene alla domanda: La "causa sottostante" 'ClassNotFoundException' è avvolta da' NoClassDefFoundError' e quindi non verrà catturata da 'catch (ClassNotFoundException e)'. –

0
//and yet this works just fine... 
try 
{ 
    throw new Error(new IOException()); 
} 
catch (Error e) 
{ 
    System.out.println("err"); 
} 

sostituirlo con:

//and yet this still works fine... 
try 
{ 
    throw new NoClassDefFoundError(new ClassNotFoundException()); 
} 
catch (Error e) 
{ 
    System.out.println("err"); 
} 

Prova un e.printStackTrace() e vedrete un output simile.