ClassNotFoundException vs NoClassDefFoundError
1. Introdução
TantoClassNotFoundExceptioneNoClassDefFoundError ocorrem quando a JVM não consegue encontrar uma classe solicitada no classpath. Embora pareçam familiares, existem algumas diferenças fundamentais entre esses dois.
Neste tutorial, discutiremos alguns dos motivos para suas ocorrências e suas soluções.
2. ClassNotFoundException
ClassNotFoundException é uma exceção verificada que ocorre quando um aplicativo tenta carregar uma classe por meio de seu nome totalmente qualificado e não consegue encontrar sua definição no caminho de classe.
Isso ocorre principalmente ao tentar carregar classes usandoClass.forName(),ClassLoader.loadClass() ouClassLoader.findSystemClass(). Portanto, precisamos ser extremamente cuidadosos comjava.lang.ClassNotFoundException ao trabalhar com reflexão.
Por exemplo, vamos tentar carregar a classe do driver JDBC sem adicionar dependências necessárias, o que nos levará aClassNotFoundException:
@Test(expected = ClassNotFoundException.class)
public void givenNoDrivers_whenLoadDriverClass_thenClassNotFoundException()
throws ClassNotFoundException {
Class.forName("oracle.jdbc.driver.OracleDriver");
}
3. NoClassDefFoundError
NoClassDefFoundError é um erro fatal. Ocorre quando a JVM não consegue encontrar a definição da classe ao tentar:
-
Instancie uma classe usando a palavra-chavenew
-
Carregar uma classe com uma chamada de método
O erro ocorre quando um compilador pôde compilar com êxito a classe, mas o Java Runtime não pôde localizar o arquivo de classe. Isso geralmente ocorre quando há uma exceção ao executar um bloco estático ou ao inicializar campos estáticos da classe, portanto, a inicialização da classe falha.
Vamos considerar um cenário que é uma maneira simples de reproduzir o problema. A inicialização deClassWithInitErrors lança uma exceção. Então, quando tentamos criar um objeto deClassWithInitErrors,, ele lançaExceptionInInitializerError.
Se tentarmos carregar a mesma classe novamente, obtemos oNoClassDefFoundError:
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;
}
}
Vamos escrever um caso de teste para este cenário:
@Test(expected = NoClassDefFoundError.class)
public void givenInitErrorInClass_whenloadClass_thenNoClassDefFoundError() {
NoClassDefFoundErrorExample sample
= new NoClassDefFoundErrorExample();
sample.getClassWithInitErrors();
}
4. Resolução
Às vezes, pode ser bastante demorado diagnosticar e corrigir esses dois problemas. O principal motivo para ambos os problemas é a indisponibilidade do arquivo de classe (no caminho de classe) no tempo de execução.
Vamos dar uma olhada em algumas abordagens que podemos considerar ao lidar com qualquer um destes:
-
Precisamos garantir que a classe ou jar que contenha essa classe esteja disponível no caminho de classe. Caso contrário, precisamos adicioná-lo
-
Se estiver disponível no classpath do aplicativo, provavelmente o classpath está sendo substituído. Para corrigir isso, precisamos encontrar o caminho de classe exato usado por nosso aplicativo
-
Além disso, se um aplicativo estiver usando vários carregadores de classes, as classes carregadas por um carregador de classes podem não estar disponíveis por outros carregadores de classes. Para solucionar bem isso, é essencial saberhow classloaders work in Java
5. Sumário
Embora ambas as exceções estejam relacionadas ao classpath e ao Java runtime incapaz de encontrar uma classe em runtime, é importante observar suas diferenças.
O Java runtime lançaClassNotFoundException ao tentar carregar uma classe apenas no tempo de execução e o nome foi fornecido durante o tempo de execução. No caso deNoClassDefFoundError, the, a classe estava presente no tempo de compilação, mas o Java runtime não conseguiu localizá-la no Java classpath durante a execução.
Como sempre, o código completo para todos os exemplos pode ser encontradoover on GitHub.