Как обрабатывать инициализатор статического конечного поля, который выдает проверенное исключение

Я сталкиваюсь с вариантом использования, когда я хотел бы объявить поле static final с оператором инициализации, который объявлен для создания проверенного исключения. Как правило, это выглядело бы так:

public static final ObjectName OBJECT_NAME = new ObjectName("foo:type=bar");

Проблема, с которой я столкнулся, заключается в том, что конструктор ObjectName может генерировать различные проверенные исключения, которые меня не волнуют (потому что я буду знать, что мое имя действительно, и все в порядке, если он с треском падает, если это не так). Компилятор Java не позволит мне просто игнорировать это (поскольку это проверенное исключение), и я бы предпочел не прибегать к:

public static final ObjectName OBJECT_NAME;
static {
    try {
        OBJECT_NAME = new ObjectName("foo:type=bar");
    } catch (final Exception ex) {
        throw new RuntimeException("Failed to create ObjectName instance in static block.", ex);
    }
}

Потому что статические блоки действительно трудно читать. Есть ли у кого-нибудь предложения о том, как справиться с этим случаем в хорошем, чистом виде?


person Romain    schedule 08.12.2009    source источник
comment
Мое личное решение состоит в том, чтобы выдать CheckedExceptionsAreAPainInTheAssSometimesException, что является исключением во время выполнения. После этого программа просто вылетает.   -  person Bassinator    schedule 18.10.2017


Ответы (4)


Если вам не нравятся статические блоки (некоторые люди не любят), тогда альтернативой является использование статического метода. IIRC, Джош Блох рекомендовал это (очевидно, не в Эффективной Java при быстрой проверке).

public static final ObjectName OBJECT_NAME = createObjectName("foo:type=bar");

private static ObjectName createObjectName(final String name) {
    try {
        return new ObjectName(name);
    } catch (final SomeException exc) {
        throw new Error(exc);
    }  
}

Or:

public static final ObjectName OBJECT_NAME = createObjectName();

private static ObjectName createObjectName() {
    try {
        return new ObjectName("foo:type=bar");
    } catch (final SomeException exc) {
        throw new Error(exc);
    }  
}

(Отредактировано: исправлен второй пример для возврата из метода вместо назначения static.)

person Tom Hawtin - tackline    schedule 08.12.2009
comment
Я не думал об этом, хотя теперь, когда я прочитал это, я на 100% уверен, что использовал этот подход давным-давно. Я буду использовать это, так как я не люблю статические блоки, а также хочу, чтобы мой код был удобочитаемым для новичков (вы никогда не знаете, кто будет поддерживать ваш код после вас :)). - person Romain; 08.12.2009
comment
дает мне ошибку компилятора должен вернуть результат типа ObjectName - будет ли простым решением иметь return null в блоке catch? Но потом немного странно отлаживать - person Don Cheadle; 13.11.2014
comment
Я думаю, вы имеете в виду пункт 59: Избегайте ненужного использования проверенных исключений (Эффективная Java, 2-е издание). В этом пункте Блох советует автору кода, выдающего исключение, подумать, «могут ли его клиенты предпринять какое-либо полезное действие, столкнувшись с исключением». Это отличается от этого случая, когда вопрос заключается не в легитимности выброшенного исключения, а в том, как лучше всего обработать исключение. Глядя на документацию по java.lang.Error, я понял, что выдавать ошибку здесь не лучший вариант. - person nullstellensatz; 19.09.2015
comment
Errors следует использовать для «аномальных условий», указывающих на «серьезные проблемы» с программой. В примерах, которые дает Блох, AssertionError выбрасываются только в коде, который никогда не должен запускаться, например. в разделе default блока switch или в приватном конструкторе класса без создания экземпляров. ИМХО, учитывая тот факт, что исключительное состояние в данном случае не является невероятным, выбрасывание RuntimeException более уместно, чем выбрасывание Error. - person nullstellensatz; 19.09.2015
comment
@nullstellensatz Это шесть лет назад! Я имел в виду совет Блоха (возможно, он изменился за последнее десятилетие) о создании статических методов для построения вместо инициализаторов экземпляров. Поиск по 2-му изд. книги «Эффективная Java на Kindle» на самом деле не появляется в этой книге. / Целью исключения thrown является сигнал о том, что класс сломан и должен умереть. Это ошибка. (Будет завернут в java.lang.ExceptionInInitializerError.) Error также намного читабельнее, чем бессмыслица RuntimeException. - person Tom Hawtin - tackline; 19.09.2015

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

person BalusC    schedule 08.12.2009
comment
Это очень важный момент (поэтому я проголосовал за него, несмотря на то, что не принял его), и GPP также лучше всего сформулирован. Я не буду использовать этот метод, потому что, как вы говорите, это сложно понять/прочитать только новичкам... И я не могу гарантировать, что люди, которые будут поддерживать его после меня, будут опытными :). - person Romain; 08.12.2009
comment
Я не уверен, что предпочел бы это. Преобразовав его в метод private static, вы рискуете потерять надзор. Обычная практика заключается в том, что такие методы (вспомогательные методы) размещаются во всей нижней части класса. Но хорошо, в настоящее время у вас есть IDE, так что вы можете просто щелкнуть вперед. - person BalusC; 08.12.2009

Блоки static читать несложно. Так что я бы порекомендовал это решение. Однако вы можете обернуть свой объект в другой объект, например ObjectNameWrapper, который разделяет interface с вашим ObjectName, и чей конструктор вызывает ваш конструктор ObjectName, скрывая все возникающие проверенные исключения. Но опять же, я бы выбрал статический вариант.

person Bozho    schedule 08.12.2009
comment
Введение другого объекта кажется бестолковым. - person Tom Hawtin - tackline; 08.12.2009
comment
Я, конечно, согласен с вами. Ваше предложение статического метода намного лучше. - person Bozho; 08.12.2009

Вы можете использовать метод, аннотированный @SneakyThrows Ломбока.

public static final ObjectName OBJECT_NAME = createObjectName();

@SneakyThrows(SomeException.class)
private static ObjectName createObjectName() {
    return new ObjectName("foo:type=bar");
}

Эта аннотация заставляет проверенное исключение вести себя как непроверенное.

person mturina    schedule 12.09.2020