Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: How to reproduce Legen...dary ClassNotFoundException in Singleton?

On my last interview I was asked a standard question about all Singleton implementations in java. And how bad they all are.

And I was told that even the static initialization is bad because of the probability of unchecked exception in constructor:

public class Singleton {
    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }
    private Singleton() {
       throw new RuntimeException("Wow... Exception in Singleton constructor...");
    }
}

And they also told me that the Exception is gonna be "ClassNotFoundException" so it would be extremely hard to find the problem in real app.

I tried to get that Exception:

public static void main(String[] args) {
    new Thread(new Runnable(){
            public void run() {
                Singleton.getInstance();
            }
        }).start();
}

But the onlything I get is ExceptionInInitializerError...

I googled about that exception and everywhere I found - they all talked about the same problem I was told on my interview. Nothing about the "implementation"=)

Thanks for your attention.

like image 205
leshka Avatar asked Sep 26 '11 09:09

leshka


2 Answers

Sometimes you get strange questions in interviews, you should always expect the unexpected. ;)

Any technique you use has positives and minuses. You have to know when is a good time to use them and what the problem might be and how to work around them.

The important thing to remember that almost every problem has a solution or a work around.

On my last interview I was asked a standard question about all Singleton implementations in java. And how bad they all are.

Sounds less like a question, more like a religious debate.

And I was told that even the static initialization is bad because of the probability of unchecked exception in constructor:

Siderman IV: Spider man vs Singleton and the Static Initialiser. (the bad guys ;)

throw new RuntimeException("Wow... Exception in Singleton constructor...");

That is a bad idea, so don't do that. In fact it won't even compile. The compiler in Java 6 reports.

initializer must be able to complete normally

And they also told me that the Exception is gonna be "ClassNotFoundException" so it would be extremely hard to find the problem in real app.

You get a ExceptionInInitializerError with a cause of the exception which caused the problem. Apart from having to read the nested exception its not that tricky.

static class Inner {
    static {
        Integer.parseInt(null);
    }
}

public static void main(String... args) {
    try {
        new Inner();
    } catch (Throwable e) {
        e.printStackTrace();
    }
    new Inner();
}

prints

Exception in thread "main" java.lang.ExceptionInInitializerError
at Main.main(Main.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.NumberFormatException: null
at java.lang.Integer.parseInt(Integer.java:417)
at java.lang.Integer.parseInt(Integer.java:499)
at Main$Inner.<clinit>(Main.java:8)

Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class Main$Inner
at Main.main(Main.java:14)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

This happens the first time, after that you get NoClassDefFoundError if you try to use the class again.

It used to be that when you tried to access a class using reflections, and it failed you got a ClassNotFoundException (with no details as to what really happens) However this is no longer the case.

like image 104
Peter Lawrey Avatar answered Nov 02 '22 05:11

Peter Lawrey


Imo, I don't think you'll ever get a ClassNotFoundException out of a construction like that. The classloader will not fail to load that class, but will fail to initialize it. The ExceptionInInitializerError is correct, according to Javadoc:

ExceptionInInitializerError "signals that an unexpected exception has occurred in a static initializer. An ExceptionInInitializerError is thrown to indicate that an exception occurred during evaluation of a static initializer or the initializer for a static variable.", which is exactly your case.

Side note: the most purist way of implementing a singleton in Java is, according to Joshua Bloch (author of part of the Java API and the book "Effective Java") the Singleton Enum Pattern (http://stackoverflow.com/questions/70689/efficient-way-to-implement-singleton-pattern-in-java).

In any case, unchecked exceptions can potentially happen in the constructor of any class, so in my opinion this possibility is not a reason enough to not use the Static Initialization Singleton Pattern in Java.

like image 44
jjmontes Avatar answered Nov 02 '22 05:11

jjmontes