Синглтон и исключение
Каков наилучший способ создания одноэлементного класса, который может генерировать исключение?
Здесь у меня есть Singleton (с использованием метода Билла Пью, задокументированного в Wiki для 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;
}
Если исключение выбрано в 2, я хотел бы распространить его на вызывающего.
Однако я не могу исключить исключение из строки 1.
Итак, мой единственный вариант - вернуть нулевой объект, если объект singleton был создан неправильно?
Спасибо
P.S Я понимаю, что этот Singleton может сломаться, если он загружен через разные загрузчики классов или если он загружен рефлексивно, но он достаточно хорош для моей цели.
//UPDATE
Мне любопытно, не могу ли я изменить порядок моего дизайна, как показано ниже, для исключения исключений?
Кроме того, мне не нужна синхронизация (загрузчик классов гарантирует, что статический внутренний класс будет загружаться только один раз и только когда вызывается getInstance()). Таким образом, поточно-безопасный и лениво-экземпляр?
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();
}
Еще раз спасибо.
Ответы
Ответ 1
Используйте статический инициализатор и перезапустите Exception
как ExceptionInInitializerError
. Нажмите ссылку, чтобы прочитать Javadoc, вы увидите, что она подходит именно для этого конкретного функционального требования: обработка исключений во время статической инициализации. Синглтон на самом деле не меньше или больше, чем статически и лениво инициализированный глобальный объект.
private static class SingletonObjectFactoryHolder{
private static final ObjectFactory INSTANCE;
static {
try {
INSTANCE = new ObjectFactory();
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
}
Нет необходимости в двойной проверенной блокировке идиомы, которая считается анти-шаблоном и в некоторых случаях даже небезопасной.
Ответ 2
Просто не бросайте исключение из конструктора объекта. Вы можете предоставить метод init ()
и отбросить свое исключение, если это необходимо.
Ответ 3
Вы можете проверить нуль INSTANCE внутри getInstance и лениво инициализировать его. Но обычно лучше всего, если конструкторы не бросают, если вы можете сделать конструктор более безопасным, что, вероятно, будет лучше.
Ответ 4
Я согласен с Арне Бурмейстером, код для этого будет выглядеть так:
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.
}
}