开发者

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 onlyt开发者_开发技巧hing 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.


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.


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.


If you saying that on account of a RuntimeException being thrown from the ctr of the Singleton class , a ClassNotFoundException will be throw - then that is not correct - CNFEx is a results of the runtime failing to locate the class to load - the fact that the ctr code is called at the first place is evidence enough to rule out CNFEx.


It is very simple. Your constructor should call some third party library. For example log4j. Compile it with log4j.jar in classpath and then run without. You will get ClassDefNotFoundError. If you really need ClassNotFoundException initiate some class using dynamic class loading: Class.forName("MyNotExistingClass")

Anyway, I think that your interviewer is wrong. The problem with static initialization is not possible RunTimeExceptions: you will see them on STDERR of your application. The problem is that they run before the real objects are needed while lazy initialization of classic singleton is running only when the instance is really going to be used.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜