Понимание проверенных и непроверенных исключений в Java - PullRequest
658 голосов
/ 24 мая 2011

Джошуа Блох в « Effective Java » сказал, что

Используйте проверенные исключения для восстанавливаемых условий и исключения времени выполнения для ошибок программирования (Элемент 58 во 2-й редакции)

Посмотрим, правильно ли я понимаю.

Вот мое понимание проверенного исключения:

try{
    String userInput = //read in user input
    Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
    id = 0; //recover the situation by setting the id to 0
}

1.Вышеуказанное рассматривает проверенное исключение?

2.Является ли RuntimeException непроверенным исключением?

Вот мое понимание непроверенного исключения:

try{
    File file = new File("my/file/path");
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){

//3. What should I do here?
    //Should I "throw new FileNotFoundException("File not found");"?
    //Should I log?
    //Or should I System.exit(0);?
}

4.Не может ли приведенный выше код быть проверенным исключением?Я могу попытаться восстановить ситуацию, как это?Могу я? (Примечание: мой третий вопрос находится внутри catch выше)

try{
    String filePath = //read in from user input file path
    File file = new File(filePath);
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){
    //Kindly prompt the user an error message
    //Somehow ask the user to re-enter the file path.
}

5.Почему люди делают это?

public void someMethod throws Exception{

}

Почему они позволяют всплыть исключению?Разве обработка ошибок не быстрее, лучше?Зачем пузыриться?

6.Должен ли я вспомнить точное исключение или замаскировать его с помощью исключения?

Ниже приведены мои показания

В Java, когда мне следует создать проверенныйисключение, и когда это должно быть исключение времени выполнения?

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

Ответы [ 21 ]

439 голосов
/ 24 мая 2011

Многие люди говорят, что проверенные исключения (то есть те, которые вы должны явно перехватить или перебросить) не должны использоваться вообще.Например, они были устранены в C #, и большинство языков не имеют их.Таким образом, вы всегда можете выбросить подкласс RuntimeException (непроверенное исключение)

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

Вот мой расширенный взгляд на тему .

Что касается конкретных вопросов:

  1. Учитывает ли NumberFormatException проверенное исключение?
    Нет. NumberFormatException не проверено (= является подклассом RuntimeException).Зачем?Я не знаю.(но должен был быть метод isValidInteger(..))

  2. Является ли RuntimeException непроверенным исключением?
    Да, точно.

  3. Что мне здесь делать?
    Это зависит от того, где находится этот код и что вы хотите, чтобы произошло.Если он находится на уровне пользовательского интерфейса - поймайте его и покажите предупреждение;если он находится в слое обслуживания - вообще не улавливайте - пусть он пузырится.Только не глотайте исключение.Если в большинстве случаев возникает исключение, вы должны выбрать один из них:

    • зарегистрировать его и вернуть
    • повторно выбросить его (объявить, что оно было выброшено методом)
    • создать новое исключение, передав текущее в конструкторе
  4. Теперь, не может ли приведенный выше код также быть проверенным исключением?Я могу попытаться восстановить ситуацию, как это?Могу я?
    Это могло бы быть.Но ничто не мешает вам поймать и непроверенное исключение

  5. Почему люди добавляют класс Exception в предложении throws?
    Чаще всего, потому что людилень обдумывать что ловить и что отбрасывать.Бросать Exception - это плохая практика, и ее следует избегать.

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

223 голосов
/ 24 мая 2011

То, что является «проверенным исключением», не имеет никакого отношения к тому, поймали ли вы это или что вы делаете в блоке catch.Это свойство классов исключений.Все, что является подклассом Exception , за исключением для RuntimeException и его подклассов, является проверенным исключением.

Компилятор Java заставляет вас либо перехватывать проверенные исключения, либо объявлять их в методеподпись.Предполагалось, что это повысит безопасность программ, но большинство считает, что оно не стоит тех проблем проектирования, которые оно создает.

Почему они допускают возникновение исключения?Разве не справиться с ошибкой, чем раньше, тем лучше?Зачем пузыриться?

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

65 голосов
/ 24 мая 2011
  1. Считается ли вышеизложенное проверенным исключением? нет Тот факт, что вы обрабатываете исключение, не делает его Checked Exception, если оно RuntimeException.

  2. Является ли RuntimeException unchecked exception? Да

Checked Exceptions являются subclasses из java.lang.Exception Unchecked Exceptions являются subclasses из java.lang.RuntimeException

Вызовы, выбрасывающие проверенные исключения, должны быть заключены в блок try {} или обработаны на уровне выше в вызывающей стороне метода. В этом случае текущий метод должен объявить, что он вызывает указанные исключения, чтобы вызывающие могли принять соответствующие меры для обработки исключения.

Надеюсь, это поможет.

Q: я должен всплыть точно исключение или замаскировать его с помощью исключения?

A: Да, это очень хороший вопрос и важное соображение дизайна. Класс Exception является очень общим классом исключений и может использоваться для переноса внутренних исключений низкого уровня. Вам лучше создать собственное исключение и обернуть его внутри. Но, и главное: никогда не скрывать первопричину первопричины. Например, Don't ever выполните следующие действия -

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException("Cannot login!!"); //<-- Eat away original root cause, thus obscuring underlying problem.
}

Вместо этого сделайте следующее:

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
}

Уничтожение первоначальной первопричины скрывает фактическую причину, выходящую за рамки восстановления, - это кошмар для рабочих групп поддержки, к которым у них есть доступ только к журналам приложений и сообщениям об ошибках. Хотя последний вариант лучше, но многие люди не используют его часто, потому что разработчики просто не могут передать исходное сообщение вызывающей стороне. Поэтому сделайте твёрдое замечание: Always pass on the actual exception верните, завернуто или нет в какое-либо исключение для конкретного приложения.

При попытке поймать RuntimeExceptions

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

try {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welcome to my site!);
} catch (NullPointerException npe) {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Это плохая практика программирования. Вместо этого следует выполнить нулевую проверку, как -

if (userObject != null) {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} else {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Но бывают случаи, когда такая проверка ошибок стоит дорого, например, при форматировании чисел, учтите это -

try {
    String userAge = (String)request.getParameter("age");
    userObject.setAge(Integer.parseInt(strUserAge));
} catch (NumberFormatException npe) {
   sendError("Sorry, Age is supposed to be an Integer. Please try again.");
}

Здесь проверка ошибок перед вызовом не стоит усилий, потому что по сути это означает дублирование всего кода преобразования строки в целое в методе parseInt () - и подвержена ошибкам, если реализована разработчиком. Так что лучше просто покончить с try-catch.

Так что NullPointerException и NumberFormatException оба RuntimeExceptions, перехват NullPointerException должен быть заменен изящной нулевой проверкой, в то время как я рекомендую явно перехватывать NumberFormatException, чтобы избежать возможного введения подверженного ошибкам кода.

18 голосов
/ 25 мая 2011

1.Если вы не уверены в исключении, проверьте API:

 java.lang.Object
 extended by java.lang.Throwable
  extended by java.lang.Exception
   extended by java.lang.RuntimeException  //<-NumberFormatException is a RuntimeException  
    extended by java.lang.IllegalArgumentException
     extended by java.lang.NumberFormatException

2.Да, и все исключения, которые его расширяют.

3.Нет необходимости ловить и бросать одно и то же исключение.В этом случае вы можете отобразить новый диалог файлов.

4.FileNotFoundException является уже проверенным исключением.

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

Хорошим чтением является сам документ Oracle: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

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

Следующий вопрос может быть следующим: «Если так хорошо документировать API метода, включая исключения, которые он может генерировать, почемуне указывать исключения во время выполнения? "Исключения во время выполнения представляют проблемы, которые являются результатом программной проблемы, и поэтому нельзя ожидать, что клиентский код API будет восстанавливаться после них или обрабатывать их каким-либо образом.Такие проблемы включают арифметические исключения, такие как деление на ноль;исключения указателя, такие как попытка доступа к объекту через нулевую ссылку;и индексация исключений, таких как попытка доступа к элементу массива через индекс, который слишком велик или слишком мал.

В спецификации языка Java также содержится важная информация :

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

Суть в том, что вы можете поймать любого RuntimeException, но вы не обязаны и, фактически, реализация не обязана поддерживать те же самые непроверенные исключения, которые не являются частью контракта.

9 голосов
/ 24 мая 2011

1) Нет, NumberFormatException является непроверенным исключением. Даже если вы поймали это (вы не обязаны), потому что это не проверено. Это потому, что это подкласс IllegalArgumentException, который является подклассом RuntimeException.

2) RuntimeException является корнем всех непроверенных исключений. Каждый подкласс RuntimeException не проверяется. Все остальные исключения и Throwable проверяются, кроме ошибок (которые подпадают под Throwable).

3/4) Вы можете предупредить пользователя, что он выбрал несуществующий файл, и попросить новый. Или просто прекратите информировать пользователя о том, что он ввел что-то недопустимое.

5) Бросать и ловить 'Exception' - плохая практика. Но в более общем случае вы можете выдать другие исключения, чтобы вызывающий мог решить, как с этим справиться. Например, если вы написали библиотеку для обработки чтения какого-либо файла и ваш метод был передан несуществующему файлу, вы не знаете, как с этим справиться. Звонящий хочет спросить снова или выйти? Таким образом, вы бросаете Исключение вверх по цепочке к вызывающей стороне.

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

7 голосов
/ 24 июля 2015

Проверено - Скорее всего. Проверено во время компиляции.

Например. FileOperations

UnChecked - из-за неверных данных. Проверено во время выполнения.

Например.

String s = "abc";
Object o = s;
Integer i = (Integer) o;

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Sample.main(Sample.java:9)

Здесь исключение происходит из-за неверных данных и никак не может быть определено во время компиляции.

5 голосов
/ 13 июля 2015

Проверенные исключения проверяются во время компиляции JVM и связаны с ресурсами (файлы / db / stream / socket и т. Д.). Мотив проверенного исключения состоит в том, что во время компиляции, если ресурсы недоступны, приложение должно определить альтернативное поведение для обработки этого в блоке catch / finally.

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

Объяснение взято из http://coder2design.com/java-interview-questions/

3 голосов
/ 09 сентября 2015

Мой абсолютный фаворит описание различий между непроверенными и отмеченными исключениями приведено в статье из учебника по Java " Непроверенные исключения - спор " этот пост - но, эй, основы иногда лучшие):

Вот основная рекомендация: если клиент может быть разумно ожидается восстановление после исключения, сделайте его проверенным исключением. Если клиент не может ничего сделать для восстановления после исключения, сделать его непроверенное исключение

Суть "какого типа исключения генерировать" является семантической (до некоторой степени), и приведенная выше цитата обеспечивает превосходное руководство (следовательно, я все еще поражаюсь представлению, что C # избавился от проверенных исключений - особенно Лисков доказывает свою полезность).

Остальное становится логичным: на какие исключения компилятор ожидает от меня явного ответа? Те, от которых вы ожидаете, что клиент восстановится.

3 голосов
/ 02 октября 2012

Чтобы ответить на последний вопрос (другие, кажется, полностью ответили выше): «Должен ли я выдать точное исключение или замаскировать его с помощью исключения?»

Я предполагаю, что вы имеете в виду что-то вроде этого:

public void myMethod() throws Exception {
    // ... something that throws FileNotFoundException ...
}

Нет, всегда объявляйте наиболее точное возможное исключение или список таких.Исключения, которые вы объявляете своим методом как способный к выбросу, являются частью контракта между вашим методом и вызывающей стороной.Бросок "FileNotFoundException" означает, что возможно, имя файла неверно и файл не будет найден;звонящий должен будет разобраться с этим разумно.Бросок Exception означает «Эй, дерьмо случается. Сделка».Что очень плохо API.

В комментариях к первой статье есть несколько примеров, где "throws Exception" является допустимым и разумным объявлением, но для большинства это не так "normal "код, который вы когда-либо будете писать.

3 голосов
/ 03 декабря 2016

Исключения во время выполнения Исключения во время выполнения называются исключениями без проверки. Все остальные исключения проверяются исключения, и они не являются производными от java.lang.RuntimeException.

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

Ряд методов в Java API генерируют проверенные исключения, поэтому вы часто будете писать обработчики исключений, чтобы справляться с исключениями, созданными методами, которые вы не писали.

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