Thursday, September 29, 2011

ClassNotFoundException and NoClassDefFoundError - Similar, but different.


ClassNotFoundException and NoClassDefFoundError are very similar by name. Unless someone looks at there definition very carefully, there name conveys very similar meaning. However, they are different. Lets explore.

First the Definition;
java.lang.NoClassDefFoundError : Thrown if the Java Virtual Machine or a ClassLoader instance tries to load in the definition of a class (as part of a normal method call or as part of creating a new instance using the new expression) and no definition of the class could be found.
The searched-for class definition existed when the currently executing class was compiled, but the definition can no longer be found.

java.lang.ClassNotFoundException :  Thrown when an application tries to load in a class through its string name using:

  • The forName method in class Class.
  • The findSystemClass method in class ClassLoade.
  • The loadClass method in class ClassLoader.

but no definition for the class with the specified name could be found.


One difference with respect there class hierarchy is that ClassNotFoundException extends the java.lang.Exception class and NoClassDefFoundError extends the java.lang.Error class , indirectly. (NoClassDefFoundError actually extends LinkageError class which extends Error class.)


To understand the difference with respect to when they would occur lets take an example.
Suppose there is class Student with 2 attributes, id and name.

package com.example.dev;

public class Student {
      private String id;
      private String name;
     
      public Student1(String id, String name) {
            this.id = id;
            this.name = name;
      }

      public String getId() { return id; }

      public void setId(String id) { this.id = id; }

      public String getName() { return name; }

      public void setName(String name) { this.name = name;}
}


Lets assume that this class comes from a third party packaged in jar file and further that this jar is present in classpath.
Lets take a class StudentService which uses two ways to use this class.

public class StudentService {

    public void createUsingRef() throws Exception {
      Class student = Class.forName("com.example.dev.Student");
      System.out.println(student.getName());
    }
     
    public void createUsingNew() {
      Student s = new Student("roll_1", "Arjun");
    }
}

Note the difference in the uses. While in method createUsingRef(), reflection mechanism is used to instantiate the class, in createUsingNew() the new operator is used.

Now due to some reason, the jar containing Student class is deleted or is accidently removed from classpath. What would happen when the above 2 functions are invoked ?

The createUsingRef() will throw ClassNotFoundException, because here the class is loaded using the String name and using reflection mechanism. Note that, here since the ClassNotfoundException extends Exception it can be re-covered. Also note that , if there was only createUsingRef() method and with its current form, then even the absence of Student class would not have stopped successful compilation of StudentService. It is only during run-time that ClassNotFoundException would have been thrown.

If createUsingNew() is called during run-time, then NoClassDefFoundError is thrown. What this means is that the class Student was available during compile time, but when the JVM or class loader tries to load the class during run-time it could not find the definition. This may happen if the jar file containing Student class accidently got misplaced before run-time.
And since it is JVM that could not find the class, it flags it as fatal and non-recoverable.

2 comments: