Java: Как воспроизвести Legen ... dary ClassNotFoundException в синглтоне? - PullRequest
5 голосов
/ 26 сентября 2011

В моем последнем интервью мне задали стандартный вопрос обо всех реализациях Singleton в Java. И как все они плохи.

И мне сказали, что даже статическая инициализация плоха из-за вероятности непроверенного исключения в конструкторе:

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...");
    }
}

И они также сказали мне, что Исключение будет «ClassNotFoundException», так что будет очень трудно найти проблему в реальном приложении.

Я пытался получить это исключение:

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

Но единственное, что я получаю, это ExceptionInInitializerError ...

Я гуглил об этом исключении, и везде, где я находил, - все они говорили об одной и той же проблеме, которую мне рассказали в моем интервью. Ничего о "реализации" =)

Спасибо за ваше внимание.

Ответы [ 4 ]

5 голосов
/ 26 сентября 2011

Иногда на собеседованиях возникают странные вопросы, всегда следует ожидать неожиданного.;)

Любая используемая вами техника имеет свои плюсы и минусы.Вы должны знать, когда подходящее время их использовать, и в чем может быть проблема, и как их обойти.

Важно помнить, что почти у каждой проблемы есть решение или обходной путь.

В моем последнем интервью мне задали стандартный вопрос обо всех реализациях Singleton в Java.И как все они плохи.

Звучит не столько как вопрос, сколько как религиозная дискуссия.

И мне сказали, что даже статическая инициализация плоха из-завероятность непроверенного исключения в конструкторе:

Человек-паук IV: Человек-паук против Синглтона и Статического Инициализатора.(плохие парни;)

выбросить новое RuntimeException («Ух ... исключение в конструкторе Singleton ...»);

Это плохая идея, поэтомуне делай этогоНа самом деле это даже не скомпилируется.Компилятор в Java 6 сообщает.

initializer must be able to complete normally

И они также сказали мне, что Исключение будет "ClassNotFoundException", поэтому найти проблему в реальном приложении будет крайне сложно.

Вы получаете ExceptionInInitializerError с причиной исключения, вызвавшего проблему.Помимо необходимости читать вложенное исключение, это не так сложно.

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

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

печатает

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)

Это происходит в первый раз, после этого вы получите NoClassDefFoundError, есливы пытаетесь использовать класс снова.

Раньше когда вы пытались получить доступ к классу с помощью отражений, но не получалось, вы получали ClassNotFoundException (без подробностей относительно того, что на самом деле происходит). Однако это недлиннее дела.

3 голосов
/ 26 сентября 2011

Имо, я не думаю, что вы когда-нибудь получите ClassNotFoundException из подобной конструкции. Загрузчик классов не сможет загрузить этот класс, но не сможет его инициализировать. ExceptionInInitializerError является правильным, согласно Javadoc:

ExceptionInInitializerError "указывает, что неожиданное исключение имеет произошло в статическом инициализаторе. ExceptionInInitializerError является брошенный, чтобы указать, что исключение произошло во время оценки статический инициализатор или инициализатор для статической переменной. ", который это точно ваш случай.

Примечание: наиболее пуристический способ реализации синглтона в Java, по словам Джошуа Блоха (автора части Java API и книги "Эффективная Java"), шаблон синглтона Enum (http://stackoverflow.com/questions/70689/efficient-way-to-implement-singleton-pattern-in-java).

В любом случае неконтролируемые исключения могут возникать в конструкторе любого класса, поэтому, на мой взгляд, эта возможность не является достаточной причиной, чтобы не использовать шаблон синглтона статической инициализации в Java.

0 голосов
/ 26 сентября 2011

Это очень просто. Ваш конструктор должен вызвать стороннюю библиотеку. Например log4j. Скомпилируйте его с log4j.jar в classpath и запустите без него. Вы получите ClassDefNotFoundError. Если вам действительно нужно ClassNotFoundException, инициируйте некоторый класс, используя динамическую загрузку класса: Class.forName("MyNotExistingClass")

Во всяком случае, я думаю, что ваш интервьюер не прав. Проблема со статической инициализацией невозможна. RunTimeExceptions: вы увидите их на STDERR вашего приложения. Проблема в том, что они запускаются до того, как потребуются реальные объекты, в то время как ленивая инициализация классического синглтона выполняется только тогда, когда экземпляр действительно будет использоваться.

0 голосов
/ 26 сентября 2011

Если вы говорите, что из-за того, что RuntimeException выбрасывается из ctr класса Singleton, ClassNotFoundException будет выброшено - тогда это не правильно - CNFEx является результатом того, что среда выполнения не смогла найти класс для загрузки - тот факт, что код ctr вызывается в первую очередь, является достаточным доказательством для исключения CNFEx.

...