Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

NoClassDefFoundError When Using Lambda Instead of Anonymous Class [Snippets]

DZone's Guide to

NoClassDefFoundError When Using Lambda Instead of Anonymous Class [Snippets]

While it is often recommended to use lambda instead of the anonymous class in Java, the NoClassDefFoundError is becoming a problem for some. Here's how to solve it.

· Java Zone ·
Free Resource

Get the Edge with a Professional Java IDE. 30-day free trial.

It's recommended to use Lambda instead of the anonymous class, but there are some pitfalls, such as the potential  NoClassDefFoundError.

In this post, I will explore this error and how to avoid it. I have two classes, RequiredObject and OptionalObject. The latter one is optional at runtime, and optional dependency is common especially for this framework.

public class RequiredObject {

    public void doSomethingElse() {
        System.out.println("doSomethingElse() called");
    }

    public void doSomething() {
        boolean optionalPresent = false;
        try {
            Class.forName("test.OptionalObject");
            optionalPresent = true;
        } catch (ClassNotFoundException e) {

        }
        OptionalObject optional = optionalPresent ? new OptionalObject() : null;
        Runnable runnable = () - > {
            if (optional != null)
                optional.doSomething();
            System.out.println("doSomething() called");
        };
        runnable.run();
    }

}
public class OptionalObject {

    public void doSomething() {
        System.out.println("I am optional");
    }

}
import org.junit.Test;

public class Tests {

    @Test
    public void methodCallWithoutNoClassDefFoundError() {
        RequiredObject required = new RequiredObject();
        required.doSomethingElse();
    }

    @Test // (expected = NoClassDefFoundError.class)
    public void methodCallWithNoClassDefFoundError() {
        RequiredObject required = new RequiredObject();
        required.doSomething();
    }

    @Test
    public void reflectWithoutNoClassDefFoundError() {
        RequiredObject.class.getMethods();
    }

    @Test // (expected = NoClassDefFoundError.class)
    public void reflectWithNoClassDefFoundError() {
        RequiredObject.class.getDeclaredMethods();
    }

}


Tests that failed were caused by the NoClassDefFoundError. This is because the compiler addes a synthetic method  private static void RequiredObject.lambda$0(OptionalObject) . It captures the OptionalObject as the parameter type, and call or get via reflection will trigger the NoClassDefFoundError. It's remarkable that Spring will call the getDeclaredMethods   on bean classes.

There is a workaround — you can use the upcase OptionalObject to Object outside lambda and downcast it inside lambda.

Object optional = optionalPresent ? new OptionalObject() : null;
Runnable runnable = () - > {
    if (optional != null)
        ((OptionalObject) optional).doSomething();
    System.out.println("doSomething() called");
};
runnable.run();

Get the Java IDE that understands code & makes developing enjoyable. Level up your code with IntelliJ IDEA. Download the free trial.

Topics:
java ,lambda ,snippet ,code ,anonymous class ,noclassdeffounferror

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}