30

Whats the best way to design a singleton class that could throw an exception?

Here I have a Singleton (using Bill Pugh's method, documented in Wiki for Singleton).

    private static class SingletonObjectFactoryHolder{
    //1  
        private static final ObjectFactory INSTANCE = new ObjectFactory();
    }

    private ObjectFactory() throws Exception{
    //2
            //create the factory
    }


    public static ObjectFactory getInstance(){
    //3
        return SingletonObjectFactoryHolder.INSTANCE;
    }

If an exception is thrown at 2, I would like to propagate it to the caller. However, I can't throw an exception from line 1.

So, is my only option to return a null object if the singleton object wasn't created correctly?

Thanks

P.S I do realize that this Singleton can break if its loaded via different classloaders or if loaded reflexively, but it's good enough for my purpose.

//UPDATE

I am curious, can I not rearrange my design as below to throw exceptions?

Also, I don't need any synchronization (the classloader guarantees that the static inner class will only loaded once and only when getInstance() is called). Thus, thread-safe and lazily-instantiated?

 private static class SingletonObjectFactoryHolder{
        //1  
           public static ObjectFactory getInstance() throws Exception{
         return new ObjectFactory();
           }
 }

 private ObjectFactory() throws Exception{
        //2
        //create the factory
 }


 public static ObjectFactory getInstance(){
        //3
    return SingletonObjectFactoryHolder.getInstance();
 }

Thanks again.

CaptainHastings
  • 1,557
  • 1
  • 15
  • 32

4 Answers4

38

Use a static initializer and rethrow the Exception as ExceptionInInitializerError. Click the link to read the Javadoc, you'll see that it suits exactly for this particular functional requirement: handling exceptions during static initialization. A singleton is in fact nothing less or more than a statically and lazily initialized global object.

private static class SingletonObjectFactoryHolder{
    private static final ObjectFactory INSTANCE;
    static {
        try {
            INSTANCE = new ObjectFactory();
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }
}

No need for double checked locking idiom which is considered an anti-pattern and in some circumstances even unsafe.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • @BalusC isn't it easier to create the instance inside a private constructor and handle the exception there? – oldergod Nov 05 '13 at 08:40
  • @oldergod: I'd wonder how you intend to create an instance in instance's constructor without running into an infinite loop creating multiple instances -- violating the singleton pattern. Besides, OP explicitly mentioned to use Bill Pugh's method, so I continued on that method. – BalusC Nov 05 '13 at 08:43
  • @BalusC I was refering to the example 1 on this page http://www.javaworld.com/javaworld/jw-04-2003/jw-0425-designpatterns.html ※ I missed the part for the OP's request about Bill Pugh's method. – oldergod Nov 05 '13 at 09:00
-1

Just don't throw exception from object's constructor. You can provide init () method and throw your exception from there if it's necessary.

Roman
  • 64,384
  • 92
  • 238
  • 332
-1

You could check for null INSTANCE inside of getInstance, and lazily initialize it. But typically its best if constructors don't throw, if you can make the constructor safer that would probably be best.

Zac
  • 3,235
  • 4
  • 25
  • 30
-2

I agree with Arne Burmeister, the code for that would look like:

private static class SingletonObjectFactoryHolder
{
    private static ObjectFactory INSTANCE;


    private ObjectFactory() 
    {

    }

    public static String getInstance() throws Exception
    {
      return (INSTANCE == null) ? (INSTANCE = new ObjectFactory()) : INSTANCE; 
     // A ternary operator might not be the best fit if you need to throw an exception, but I think it looks nicer than the if(INSTANCE==null){} else{} for lazy instantiation.
    }

}
Tom Neyland
  • 6,860
  • 2
  • 36
  • 52