Как вырвать блок инициализации?
У меня класс выглядит так
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
в любом месте.
Есть несколько проблем с вашим кодом:
У вас неверное имя исключения. Исключение, которое вы пытаетесь создать, называется
ExceptionInInitializerError
неExceptionInitializerError
, Это одна из причин, почему он не скомпилируется.Никогда 1 бросок
Error
или подклассыError
,Если вам нужно сгенерировать непроверенное исключение, бросьте
RuntimeException
, Или, что еще лучше, выберите что-то более конкретное или определите и используйте свой собственный (исключенный) класс исключений.Это должно (вероятно) быть
static
блок инициализатора, а не простой инициализатор (экземпляр). Вы хотите, чтобы этот код выполнялся один раз... не каждый разSomeTest
Экземпляр создан.Выход из
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
все в порядке... при условии, что вы намерены его никогда не поймать / не восстановить. В этом случае восстановление является спорным в любом случае.
Есть пара вопросов:
- Исключение всегда выбрасывается
- Вы присваиваете последнюю переменную в цикле
- Блок инициализации не является статическим и присваивается статической конечной переменной
Проверь это:
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;
}
}