5

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.

leshka
  • 1,764
  • 6
  • 32
  • 42
  • 6
    What are you trying to do with the Runnable here? You know that the code is absolutely identical to calling Singleton.getInstance() directly? – Philipp Wendler Sep 26 '11 at 09:19
  • 3
    I think you might mean [NoClassDefFoundError](http://download.oracle.com/javase/6/docs/api/java/lang/NoClassDefFoundError.html) rather than [ClassNotFoundException](http://download.oracle.com/javase/6/docs/api/java/lang/ClassNotFoundException.html). I believe the former is what's thrown after an `ExceptionInInitializerError` has left a class a smoking crater. Not 100% sure about how it works though. – Paul Bellora Sep 26 '11 at 09:22
  • Philipp Wendler, not exactly - I'm trying to get the situation when my app continues working but strange exception happens. That happens because runtime exception is being thrown not in the main thread. – leshka Sep 26 '11 at 09:28
  • Kublai Khan, yeah maybe you're right I've heard about this one... I'll try that but it's not exactly what I was looking for... – leshka Sep 26 '11 at 09:30
  • Philipp Wendler, Oh, sorry. I'm a stupid cow=) corrected the question, thank you – leshka Sep 26 '11 at 10:05

4 Answers4

5

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.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    +1 indeed you'll only see the ExceptionInInitializerException once, becoming a NoClassDefFoundError afterwards. – jjmontes Sep 26 '11 at 09:40
  • The true cause only appears once as well. – Peter Lawrey Sep 26 '11 at 09:42
  • thank you for your answer. Btw the code I've presented compiles well on jdk7=) you can't throw an exception in static initializer block but you can do it in any method including constructor. And jdk doesn't check that. And of course this is bad - I just tried to reproduce the exception I was told about – leshka Sep 26 '11 at 10:00
3

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.

jjmontes
  • 24,679
  • 4
  • 39
  • 51
  • Note the ExceptionInInitializerError will only be thrown once, becoming a NoClassDefFoundError afterwards as Peter Lawrey explained. – jjmontes Sep 26 '11 at 09:41
0

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.

Bhaskar
  • 7,443
  • 5
  • 39
  • 51
0

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.

AlexR
  • 114,158
  • 16
  • 130
  • 208
  • I'm starting to think that you all are right=)... I thought the same on my interview but didn't argue because I wasn't sure So now I'll try to find my interviewer and get the truth (may be I misunderstand him) (btw I got that job=)) – leshka Sep 26 '11 at 09:43