Как вырвать блок инициализации?

У меня класс выглядит так

class Some {

    private enum Inner {
    }
}

И я пытаюсь найти Inner класс в блоке инициализации моего тестового класса.

class SomeTest {

    private static final Class<?> INNER_CLASS;

    {
        for (final Class<?> declaredClass: Some.class.getDeclaredClasses()) {
            if (declaredClass.getSimpleName().equals("Inner")) {
                INNER_CLASS = declaredClass;
                // Variable `INNER_CLASS` might be assigned in loop
                // break? return?
            }
        }
        throw new ExceptionInitializerError("failed to find Inner.class");
    }
}

Компилятору это не нравится, и я не смог найти лучшего способа.

Как я могу решить это? Есть ли хороший шаблон для этого?

4 ответа

static а также instance Блок инициализации не может генерировать проверенные исключения, поскольку нет способа объявить, что эти блоки генерируют эти исключения. + Изменить ExceptionInitializerError в RuntimeException (или любой подкласс) и оберните ваш код в try-catch

Кроме того, здесь вы не возвращаетесь и не ломаетесь, поэтому вы всегда выбрасываете исключение.

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

Есть несколько проблем с вашим кодом:

  1. У вас неверное имя исключения. Исключение, которое вы пытаетесь создать, называется ExceptionInInitializerError не ExceptionInitializerError, Это одна из причин, почему он не скомпилируется.

  2. Никогда 1 бросок Error или подклассы Error,

  3. Если вам нужно сгенерировать непроверенное исключение, бросьте RuntimeException, Или, что еще лучше, выберите что-то более конкретное или определите и используйте свой собственный (исключенный) класс исключений.

  4. Это должно (вероятно) быть static блок инициализатора, а не простой инициализатор (экземпляр). Вы хотите, чтобы этот код выполнялся один раз... не каждый раз SomeTest Экземпляр создан.

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


Сказав это, следующие могут быть более подходящей структурой:

 static {
     BlahType tmp = null;
     label: {
         for (...) {
             if (...) {
                 tmp = ...;
                 break label;
             }
         }
         throw new SomeException(...);
     }
     FINAL_VAR = tmp;
}

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

И более естественный способ написать выше было бы:

static {
     BlahType tmp = null;
     for (...) {
         if (...) {
             tmp = ...;
             break;
         }
     }
     if (tmp == null) {
         throw new SomeException(...);
     }
     FINAL_VAR = tmp;
}

1 - Может быть, слишком сильно. Я бы сказал, что бросали AssertionError все в порядке... при условии, что вы намерены его никогда не поймать / не восстановить. В этом случае восстановление является спорным в любом случае.

Есть пара вопросов:

  1. Исключение всегда выбрасывается
  2. Вы присваиваете последнюю переменную в цикле
  3. Блок инициализации не является статическим и присваивается статической конечной переменной

Проверь это:

class SomeTest {

    private static final Class<?> INNER_CLASS;

    static {
        Class<?> foundClass = null;
        for (final Class<?> declaredClass : Some.class.getDeclaredClasses()) {
            if (declaredClass.getSimpleName().equals("Inner")) {
                foundClass = declaredClass;
                // Variable `INNER_CLASS` might be assigned in loop
                // break? return?
            }
        }
        INNER_CLASS = foundClass;
        // throw new Exception("failed to find Inner.class");
    }
}

Используйте промежуточную переменную перед окончательным назначением.

class SomeTest {

    private static final Class<?> INNER_CLASS;
    static {
        Class<?> innerClass = null;
        for (final Class<?> declaredClass: Some.class.getDeclaredClasses()) {
            if (declaredClass.getSimpleName().equals("Inner")) {
                innerClass = declaredClass;
            }
        }
        if (innerClass == null) {
            throw new ExceptionInitializerError("failed to find Inner.class");
        }
        INNER_CLASS = innerClass;
    }
}
Другие вопросы по тегам