В Java, в чем разница между catch общим исключением и конкретным исключением (например. Исключение IOException?)

#java #exception

#java #исключение

Вопрос:

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

Ответ №1:

Разница между выполнением общего оператора try / catch и перехватом конкретного исключения (например, FileNotFoundException) обычно зависит от того, какие ошибки вам нужно обработать, а о каких ошибках вам не нужно беспокоиться. Например:

 catch (Exception e) {    //A (too) general exception handler
...
}
  

Приведенный выше код будет перехватывать КАЖДОЕ исключение, которое генерируется внутри инструкции try. Но, возможно, вы не хотите обрабатывать каждую ошибку. Что вы можете сделать с исключением «OutOfMemory»?

Лучшим методом обработки ошибок было бы выполнить какое-либо действие по умолчанию, если ошибка неизвестна или с чем-то, с чем вы ничего не можете поделать, и выполнить другое действие, если вы обнаружите, что можете выполнить «План Б», если поймаете.

Например, предположим, что вы пытаетесь открыть файл, но файл не существует. Вы можете перехватить исключение FileNotFoundException и создать новый пустой файл, как показано ниже:

 catch (FileNotFoundException e) {    //A specific exception handler
    //create a new file and proceed, instead of throwing the error to the user
}catch (Exception e) {    //For all other errors, alert the user
    ...
}
  

Это был самый эффективный и удобный для пользователя метод проверки ошибок, который я использовал в прошлом.

Комментарии:

1. конструктивный ответ на вопрос, который я искал. Я не вижу преимуществ в использовании общего исключения, отличного от предоставленного вами.

2. «OutOfMemory» является ошибкой и попадает под throwable, а не под Exception !

Ответ №2:

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

На логическом уровне серия блоков catch — это то же самое, что иметь один блок catch, а затем писать свою собственную условную логику внутри одного блока catch. Обратите внимание, что условная логика также должна была бы привести исключение к определенным подтипам, если вы хотите получить доступ к подробной информации, объявленной в пределах подтипа.

Несколько недостатков перехвата каждого исключения по отдельности включают в себя то, что вся структура try — catch становится очень большой и усложняет логику содержащего метода, а также необходимость повторять код во многих или всех отдельных блоках catch (например, протоколирование исключения).

В определенных случаях сложность некоторого базового API требует как обработки всех различных исключений, так и извлечения структуры try-catch в служебный метод. Например, вызов метода через отражение, по-видимому, регулярно требует наличия интерфейсных API.

На уровне разработки API всегда существует баланс между

  • Очень богатая (общедоступная) иерархия исключений
  • Включение кодов ошибок как части информации, содержащейся в некотором базовом исключении, и
  • Общедоступный набор интерфейсов маркеров и использование частных подтипов исключений

Ответ №3:

Хороший пример, который показывает способность обрабатывать проблемы в зависимости от типа возникшей проблемы:

 try {
  // open a file based on its file name
} catch (FileNotFoundException e) {
  // indicate that the user specified a file that doesn't exist.
  // reopen file selection dialog box.
} catch (IOException e) {
  // indicate that the file cannot be opened.
}
  

в то время как соответствующий:

 try {
  // open a file based on its file name.
} catch (Exception e) {
  // indicate that something was wrong
  // display the exception's "reason" string.
}
  

Последний пример не предоставляет средств для обработки исключения на основе того, какая проблема возникла. Все проблемы обрабатываются одинаково.

Ответ №4:

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

Ответ №5:

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

Ответ №6:

Возьмем этот пример:

 try {
 StringBuffer fileData = new StringBuffer(1000);
 BufferedReader reader = new BufferedReader(
   new FileReader(filePath));
 char[] buf = new char[1024];
 int numRead=0;
 while((numRead=reader.read(buf)) != -1){
   fileData.append(buf, 0, numRead);
 }
 reader.close();
 return fileData.toString();
} catch (Exception e) {
 //do something generic - maybe log it
}
  

В нынешнем виде это работает … обычно. Однако из-за неопределенного перехвата ошибки я ничего не могу сделать, кроме как предупредить пользователя. Если я перехвачу FileNotFoundException конкретно, я мог бы попробовать другой файл. Если бы я перехватил IOException конкретно, я мог бы предупредить о чем-то другом. Этот пример немного слабоват, но он может дать вам некоторое представление.

Ответ №7:

Проблема с перехватом общих исключений заключается в том, что вы в конечном итоге перехватываете (и часто неправильно обрабатываете) неожиданное исключение. Например:

     public String readFile(File file) {
        try {
            Reader r = new FileReader(file);
            // read file
            return ...;  // the file contents
        } catch (Exception ex) {
            // file not found ...
            return "";
        }
    }
  

Как вы можете видеть, вышесказанное написано исходя из предположения, что единственный способ, которым может произойти сбой кода внутри try , — это если файл отсутствует или не может быть открыт по какой-либо причине. На самом деле, если метод вызывается с null файлом, или если есть какая-то ошибка в коде, который считывает файл, возможны NPE и другие непроверенные исключения. Таким образом, код будет скрывать ошибки путем перехвата Exception .

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