Может ли генерирование Exception быть хорошим способом обработки всех исключений, которые выбрасываются в API рефлексии Java? - PullRequest
2 голосов
/ 19 августа 2010

Я обнаружил, что API отражения Java является подробным исключением, и я часто хочу отлавливать каждое конкретное исключение, но просто генерировать исключение. Это плохая практика, или вы действительно бросаете все эти исключения в сигнатуру метода? Каждый метод, который вызывает этот метод, должен каким-то образом иметь дело с каждым из этих конкретных исключений. Вместо этого я думаю сделать это:

public void someMethod()
        throws Exception {

    try {

        // do a bunch of reflection...

    } catch(ClassCastException classCastException) {

        throw new Exception("Some specific message.", classCastException);

    } catch(InvocationTargetException invocationTargetException) {

        throw new Exception("Some specific message.", invocationTargetException);

    }
}

Это плохая практика?

Ответы [ 7 ]

9 голосов
/ 19 августа 2010

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

Использование java.lang.Exception специально для этого является плохой идеей, потому что это слишком неопределенно.

Вы можете перебрасывать каждое отдельное исключение как какой-то пользовательский MyException или что-то в этом роде. Иногда это разумный подход, когда вас не интересует, почему someMethod не удалось.

5 голосов
/ 19 августа 2010

Краткий ответ

  • Отражение многословно по замыслу
  • Перевод исключений идиоматичен (перехватывает исключение нижнего уровня и абстрагирует его до более высокого уровня)
    • ... но не злоупотребляйте!
  • Предпочитать пользовательские исключения для java.lang.Exception; это вероятно слишком максимум абстракции

Точка 1: избегать отражения, если это вообще возможно

Вот цитата из Effective Java 2nd Edition, Item 53: Предпочитают интерфейсы для отражения :

[Сила отражения], однако, имеет цену:

  • Вы теряете все преимущества проверки времени компиляции, включая проверку исключений.
  • Код, необходимый для выполнения отражательного доступа, является неуклюжим и многословным. Это утомительно писать и трудно читать.
  • Производительность страдает. Рефлексивный вызов метода намного медленнее, чем обычный вызов метода.

[...] Как правило, объекты не должны отражаться в обычном приложении во время выполнения. Есть несколько сложных приложений, которые требуют отражения. Примеры включают в себя [опущено специально]. Если у вас есть какие-либо сомнения относительно того, попадает ли ваше приложение в одну из этих категорий, оно, вероятно, не соответствует.


Пункт 2: Перевод исключений может быть полезен, но не злоупотребляйте

Вот цитата из Effective Java 2nd Edition, Item 61: Бросьте исключения, соответствующие абстракции .

Это сбивает с толку, когда метод генерирует исключение, которое не имеет видимой связи с задачей, которую он выполняет. Это часто происходит, когда метод распространяет исключение, генерируемое абстракцией более низкого уровня. [...]

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

[...] Хотя трансляция исключений превосходит бессмысленное распространение исключений из нижних уровней, ее не следует злоупотреблять. Там, где это возможно, лучший способ справиться с исключениями из нижних уровней - это избегать их, обеспечивая успешное выполнение методов более низкого уровня. [...]

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


Точка 3: java.lang.Exception является слишком общим

Глядя на документацию , можно увидеть длинный список прямых известных подклассов, с широкими темами из Reflection, RMI, синтаксического анализа XML, ввода-вывода, графического интерфейса пользователя, криптографии и т. Д.

Заявление о том, что метод throws Exception, вероятно, является плохим решением для разработки API, поскольку он не сразу сообщает пользователю что-либо полезное о том, какие категории могут быть исключениями или при каких обстоятельствах они могут быть выброшены. , Сравните это с гипотетическим ReflectionException; это намного более информативно, и также позволяет пользователю поймать конкретно ReflectionException, а не, скажем, IOException, который каким-то образом проскользнул.


Похожие вопросы

2 голосов
/ 19 августа 2010

Я согласен с вашим подходом, за исключением того, что я думаю, что выбрасывать Exception не очень хорошо, в конце концов каждое объявление метода в вашем приложении будет заканчиваться "throws Exception".В таких случаях, когда исключение возникает только в том случае, если вы допустили ошибку, лучше сделать исключение обертки непроверенным исключением.

Если исключение, сгенерированное методом (содержащееся в InvocationTargetException), потенциально может быть вам интересно, вы можете сделать его оболочкой другого подкласса непроверенного исключения или создать для него определенный подкласс проверенных исключений,но оберните вещи вроде ClassCastException в непроверенные исключения.

1 голос
/ 19 августа 2010

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

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

Создайте исключение, которое относится к тому, что вы пытаетесь сделать, и к тому, почему он потерпел неудачу (если он потерпел неудачу из-за того, что данный аргумент неуместен, IllegalArgumentException будет одним) Также примите обоснованное решение о том, хотите ли вы выдать проверенное или непроверенное исключение (RuntimeException).

1 голос
/ 19 августа 2010

Использовать throws Exception всегда плохая идея. В вашем случае вы должны рассмотреть следующие вещи.

  1. Могу ли я восстановиться после ошибки на следующем промежуточном уровне? Если это так, используйте все разные исключения для ясности.
  2. Могу ли я восстановиться после ошибки на несколько уровней выше? Если это так, используйте исключение оболочки, поскольку это приведет к загрязнению всех методов на пути к техническим деталям для использования явных.
  3. Я не могу восстановиться после ошибки, или это происходит в совершенно другом месте / на много уровней выше. Если заключить каждое исключение в RuntimeException или в пользовательский ReflectionFailedRuntimeException, чтобы избежать утечки технических исключений во всем приложении.

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

0 голосов
/ 19 августа 2010

Это все еще приемлемая политика, если вы собираете все исключения и генерируете свое собственное исключение.

public void someMethod()
    throws MyCustomException {

try {

    // do a bunch of reflection...

} catch(ClassCastException classCastException) {
    MyCustomException ex1 = new MyCustomException("Some specific message.", classCastException);
// Logic to add more details to exception AND/OR handling current exception.
    throw ex1;

} catch(InvocationTargetException invocationTargetException) {

            MyCustomException ex1 = new MyCustomException("Some specific message.", classCastException);
// Logic to add more details to exception AND/OR handling current exception.
    throw ex1;

}
}

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

0 голосов
/ 19 августа 2010

Я бы в некоторых случаях.

Нормальный способ, которым я бы решил - посмотреть, какие методы, вызывающие someMethod (), ожидают или разумно ожидают знать. Так что если бы someMethod () делал что-то, связанное с IO, я бы выбросил IOException, если это было связано с библиотекой, которую я писал, я мог бы выбросить пользовательское исключение ..

Я бы выдавал отдельные исключения только в том случае, если бы разумно было ожидать, что вызывающие функции someMethod () будут знать, что для их реализации используется отражение.

Полагаю, ключевой вопрос: «Если бы someMethod () не использовал отражение, и что-то пошло не так, что бы он сделал? Это обычно даст вам ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...