Java: ExceptionInInitializerError, вызванный NullPointerException при создании объекта Locale

Я работаю над локализацией программы, которую написал с парой других ребят. Большинство строк теперь загружаются на соответствующем языке из файла ini. Пытаюсь сделать то же самое с форматом валюты в программе. Однако я получаю исключение во время выполнения, как только пытаюсь запустить приложение.

Я использую объект Locale в качестве параметра для нескольких NumberFormat.getCurrencyInstance(), например:

private static final NumberFormat decf;
static 
{
    decf = NumberFormat.getCurrencyInstance(Lang.cLocale);
    decf.setRoundingMode(RoundingMode.HALF_UP);
}

Lang — это класс, который содержит все необходимое для локализации. Код, на который IDE жалуется при попытке запуска: public static Locale cLocale = new Locale(GUI.DB_info[19],GUI.DB_info[20]);

GUI — это класс, в котором содержится GUI, и в котором мы решили построить массив DB_info (который сам содержит информацию, загруженную из удаленной базы данных в другом классе). DB_info[19] — это код языка (сейчас es), а DB_info[20] — это код страны (США). Элементы массива заполняются должным образом - или были, я не могу вникнуть в программу достаточно глубоко, чтобы сказать прямо сейчас; а вот с кодом заполнения DB_info ничего не изменилось.

Полное исключение выглядит следующим образом:

Exception in thread "main" java.lang.ExceptionInInitializerError
at greetingCard.GUI.<clinit>(GUI.java:118)
Caused by: java.lang.NullPointerException
at java.util.Locale.<init>(Unknown Source)
at java.util.Locale.<init>(Unknown Source)
at greetingCard.Lang.<clinit>(Lang.java:13)
... 1 more

Упомянутая строка в графическом интерфейсе: static String welcome = Lang.L_WELCOME + ", " + empName;, и Lang.java в основном выглядит так:

// Set locale for currency display
public static Locale cLocale = new Locale(GUI.DB_info[19],GUI.DB_info[20]); // language, country

// Employee specific strings
public static String L_AMT_REMAIN = "";
public static String L_AMT_TEND = "";
public static String L_APPROVED = "";
public static String L_ARE_YOU_SURE = "";
[...]

public static void Main(String emp_lang)
{
    String header = "";

    if (emp_lang.equals("ENG"))
    {
        header = "ENG";
    }
    else if (emp_lang.equals("SPA"))
    {
        header = "SPA";
    }
    else if (emp_lang.equals("FRE"))
    {
        header = "FRE";
    }
    else if (emp_lang.equals("GER"))
    {
        header = "GER";
    }
    else
    {
        header = "ENG";
    }

    try 
    {
        Ini ini = new Ini(new File("C:/lang.ini"));

        L_AMT_REMAIN = ini.get(header, "L_AMT_REMAIN");
        L_AMT_TEND = ini.get(header, "L_AMT_TEND");
        L_APPROVED = ini.get(header, "L_APPROVED");
        L_ARE_YOU_SURE = ini.get(header, "L_ARE_YOU_SURE");
                    [...]
                                L_WELCOME = ini.get(header, "L_WELCOME");
        L_WELCOME2 = ini.get(header, "L_WELCOME2");
        L_XACT_CHNG = ini.get(header, "L_XACT_CHNG");  
        L_YES = ini.get(header, "L_YES");

        System.err.println("Employee Language: " + header);
    } 
    catch (InvalidFileFormatException e) 
    {
        e.printStackTrace();
    } 
    catch (IOException e) 
    {
        e.printStackTrace();
    }
} // end public static void main

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

Порядок, в котором запускаются эти классы/методы, следующий: GUI.Main вызывает класс Login, который вызывает метод CreateLogin. Этот метод вызывает Clients.main, который получает переданный ему массив DB_info из GUI. Клиенты заполняют массив DB_info. Затем вызывается Lang.other (чтобы получить строки для страницы входа в систему), и создаются кнопки входа и метки. После успешного входа в систему предпочтительный язык сотрудника, входящего в систему (из БД), передается в Lang.main для загрузки других строк (следовательно, emp_lang передается в приведенном выше коде).

Пока я не добавил код для объекта Locale, все это работало нормально. Теперь я получаю исключение ExceptionInInitializerError. Кто-нибудь знает, что происходит?

Кстати, для загрузки из ini-файла я использую ini4j. Некоторые сообщения на форуме, которые я нашел во время поиска в Google, предполагают, что это проблема с этим, но я не понимаю, как это связано с проблемой с объектами Locale. Материал ini работает (работал) нормально.


person electrickoolaid42    schedule 26.04.2012    source источник


Ответы (2)


Похоже, у вас есть цикл в ваших статических инициализаторах, поэтому что-то еще не инициализировано.

GUI вызывает статический инициализатор Lang перед получением Lang.L_WELCOME. Lang вызывает статический инициализатор GUIs в строке 2. Ваша трассировка исключения делает его похожим на то, что GUI по какой-то причине вызывает статический инициализатор Langs.

В целом, подобные циклы означают, что кто-то собирается сослаться на статически инициализированный объект и получить null вместо того, что он ожидал получить. В этом случае я подозреваю, что Lang.java, строка 2, передает два указателя null конструктору Locale.

person Keith Randall    schedule 26.04.2012
comment
Ты был прав. Мы исправили это, переставив некоторые инициализаторы и разделив код локализации между двумя методами, чтобы все вызывалось тогда, когда это необходимо. - person electrickoolaid42; 28.04.2012
comment
Был просто подсказкой, которая нам была нужна по другому, но как-то связанному вопросу. спасибо - person wwkudu; 20.05.2014

Как отмечает Кит, у вас есть статический цикл инициализации. Чтобы помочь будущим читателям...

Чтобы свести к минимуму эти ошибки, инициализируйте (простые) константы (без конструкторов или с минимальным количеством конструкторов) перед (сложными) переменными, поэтому здесь String перед Locale — меньше места для циклов, вызывающих проблемы. .

С точки зрения отладки, NullPointerException в статическом поле и 2 <clinit> в трассировке стека с более ранним классом, появляющимся в ошибочной строке, являются подсказками, что это неинициализированное поле, вызванное статическим инициализатором цикл.

person Nils von Barth    schedule 16.07.2015