Проверено и отменено Исключение в Java
У меня возникают некоторые проблемы с пониманием различий между исключениями checked
и unchecked
в Java.
- Во-первых, исключения
checked
предполагают поиск аномалий во время компиляции. Примеры, представленные в разных источниках, ссылаются на подключение к базам данных, обработку файлов как некоторые из них, в то время как исключения unchecked
должны искать ошибки в части программиста, такие как индексирование за пределами диапазона массива и т.д.
Разве это не должно быть наоборот? Я имею в виду, что подключение к базам данных выполняется во время выполнения, правильно? То же самое касается обработки файлов. Во время компиляции вы не открываете файл-дескриптор, поэтому почему во время компиляции возникает ошибка? С другой стороны, индексирование массива за пределами его диапазона уже выполняется в программе, которое может быть проверено во время компиляции (если аномальный индекс предоставляется пользователем во время выполнения, тогда это нормально, чтобы он был временем выполнения проблема). Что мне здесь не хватает?
2 Во-вторых, как RunTimeException
, сам являющийся unchecked
, подкласс Exception
, который checked
? Что это означает?
Я нашел пример в книге Герберта Шильдта, объясняющей использование исключений checked
:
class ThrowsDemo {
public static char prompt(String str)
throws java.io.IOException {
System.out.print(str + ": ");
return (char) System.in.read();
}
public static void main(String args[]) {
char ch;
try {
ch = prompt("Enter a letter");
}
catch(java.io.IOException exc) {
System.out.println("I/O exception occurred.");
ch = 'X';
}
System.out.println("You pressed " + ch);
}
}
Требуется ли здесь предложение throws
? Почему я не могу это сделать обычно с инструкцией try-catch
вроде этого (извините, я не знаю, как имитировать IO Exception
, так что не мог проверить это сам!):
class ThrowsDemo {
public static char prompt(String str) {
System.out.print(str + ": ");
return (char) System.in.read();
}
public static void main(String args[]) {
char ch;
try {
ch = prompt("Enter a letter");
}
catch(java.io.IOException exc) {
System.out.println("I/O exception occurred.");
ch = 'X';
}
System.out.println("You pressed " + ch);
}
}
Ответы
Ответ 1
CheckedException должно обрабатываться вызывающим, исключение исключено.
Итак, при разработке своего приложения вы должны учитывать, какую исключительную ситуацию вы управляете.
Например, если вы создаете метод проверки, который проверяет достоверность ввода какого-либо пользователя, то вы знаете, что вызывающий должен проверить исключение проверки и отобразить ошибки пользователю удобным образом. Это должно быть проверенное исключение.
Или для тех исключительных условий, которые можно восстановить: представьте, что у вас есть балансировщик нагрузки, и вы хотите уведомить вызывающего абонента о том, что один из "n" серверов выключен, поэтому вызывающий должен восстановить инцидент, перенаправляющий сообщение другой сервер; это должно быть проверенное исключение, потому что очень важно, чтобы вызывающий (клиент) пытался восстановить ошибку и не просто позволял ошибке прерывать поток программы.
Вместо этого существует множество условий, которые не должны выполняться, и/или должны прерывать программу. Например, ошибка программирования (например, деление на ноль, исключение нулевого указателя), неправильное использование API (IllegalStateException, OperationNotSupportedException), аппаратный сбой или просто незначительная ситуация, которая не восстанавливается (потерянное соединение с сервером), или конец света:-); в таких случаях нормальная обработка заключается в том, чтобы исключение попадало в самый внешний блок вашего кода, который отображает пользователю, что произошла непредсказуемая ошибка, и приложение не может ничего сделать для продолжения. Это фатальное условие, поэтому единственное, что вы можете сделать, это распечатать его в журналах или показать его пользователю в пользовательском интерфейсе. В этих случаях устранение исключения является неправильным, поскольку после обнаружения исключения вам необходимо вручную остановить программу, чтобы избежать дальнейших повреждений; поэтому лучше было бы позволить какое-то исключение "поразить вентилятор":)
По этим причинам есть некоторые исключения, которые не отмечены также в JRE: OutOfMemoryError (unrecoverable), NullPointerException (это ошибка, которая должна быть исправлена), ArrayIndexOutOfBoundsException (еще один пример ошибки) и т.д.
Я лично считаю, что SQLException не должен быть отмечен, так как он обозначает ошибку в программе или проблему подключения к базе данных. Но есть много примеров, когда вы получаете исключение, в котором вы действительно не знаете, как управлять (RemoteException).
Лучший способ справиться с исключениями: если вы можете восстановить или управлять исключением, обработайте его. В противном случае исключение исключается; кому-то еще нужно будет справиться. Если вы последний "кто-то еще", и вы не знаете, как обрабатывать исключение, просто отобразите его (журнал или отображение в пользовательском интерфейсе).
Ответ 2
- вам не нужно объявлять непроверенные исключения в предложении
throws
; но вы должны объявить проверенные исключения;
-
RuntimeException
и Error
, и все их подклассы (IllegalArgumentException
, StackOverflowError
и т.д.) являются исключенными исключениями; тот факт, что RuntimeException
не отмечен, в отличие от других подклассов Throwable
, по дизайну,
- нет такой вещи, как "исключение времени компиляции".
В более общем плане считается, что исключенные исключения исключаются в случае ошибок JVM или ошибок программиста. Одним из известных таких исключений является NullPointerException
, часто сокращенный как NPE, который является подклассом RuntimeException
и поэтому не отмечен.
Еще одно очень важное различие между исключенными исключениями и проверенными исключениями заключается в том, что в блоке try-catch, если вы хотите поймать непроверенные исключения, вы должны явно их поймать.
Заключительное примечание: если у вас есть классы исключений E1
и E2
и E2
extends E1
, то ловить и/или бросать E1
также ловит/бросает E2
. Это означает как проверенные, так и непроверенные исключения. Это подразумевается в блоках catch
: если вы делаете различие между улавливанием E2
и E1
, вы должны сначала поймать E2
.
Например:
// IllegalArgumentException is unchecked, no need to declare it
public void illegal()
{
throw new IllegalArgumentException("meh");
}
// IOException is a checked exception, it must be declared
public void ioerror()
throws IOException
{
throw new IOException("meh");
}
// Sample code using illegal(): if you want to catch IllegalArgumentException,
// you must do so explicitly. Not catching it is not considered an error
public void f()
{
try {
illegal();
} catch (IllegalArgumentException e) { // Explicit catch!
doSomething();
}
}
Надеюсь, это упростит ситуацию...
Ответ 3
-
Нет. Все исключения происходят во время выполнения. Исключенные исключения - это исключения, которые заставляют вызывающего абонента обрабатывать их или объявлять их. Они, как правило, предназначены для уведомления об устраняемых ошибках, которые не вызваны ошибкой программиста (например, отсутствующим файлом или проблемой сетевого подключения). Исключения, связанные с исполнением, обычно предназначены для сигнализации ошибок, которые не могут быть восстановлены. Они не заставляют вызывающего абонента обрабатывать или объявлять их. И многие из них действительно сигнализируют ошибки программирования (например, NullPointerException).
-
Так как JLS определяет неконтролируемое исключение: исключение, которое является или расширяет RuntimeException, которое само расширяет Exception. Использование одного корня для наследования позволяет исключить любое возможное исключение из одного предложения catch.
Что касается вашего примера: да, предложение throws является обязательным, так как IOException является проверенным исключением и что код внутри метода восприимчив к его выбросу.
Ответ 4
Компилятор только гарантирует, что метод не может выставить проверенное исключение, если оно не объявило его. Общим убеждением является то, что такая проверка компилятором должна выполняться для исключений, появление которых находится вне контроля программиста, таких как примеры, которые вы приводите (подключение к базе данных, отсутствие файлов и т.д.). Неконтролируемые исключения "не должны произойти", поэтому компилятор не заставляет вас объявлять их.
Что касается моделирования IOException
или любого другого, это тривиально:
throw new IOException();
В вашем примере метод prompt
может вызывать IOException
, поэтому его нужно объявить. Это не имеет никакого отношения к тому, как вы обрабатываете исключение в момент, когда вы вызываете метод.
RuntimeException
является подклассом Exception
, чтобы было удобно улавливать все исключения одним предложением catch Exception
. Это могло быть спроектировано по-разному; Иерархия классов исключений Java - это беспорядок.
Ответ 5
Пять примеров проверенных исключений и исключенного исключения.
Unchecked Exception
-- NullPointerException
-- ArrayIndexOutofBound
-- IllegalArgument Exception
-- ClassCastException
-- IllegalStateException
-- ConcurrentModificationException
Checked Exception Five Example
-- FileNotFoundException
-- ParseException
-- ClassNotFoundException
-- CloneNotSupportException
-- SQLException
Ответ 6
Если вы не помещаете предложение throws здесь, то эта ошибка произойдет
ThrowsDemo.java:5: незарегистрированное исключение java.io.IOException; должен быть пойман или d
выливаться return (char) System.in.read();
поэтому бросает предложение в случае необходимости.
Ответ 7
Проверенные и непроверенные исключения
Существует два типа исключений: проверенные исключения и исключенные исключения.
Основное различие между проверенным и неконтролируемым исключением заключается в том, что проверенные исключения проверяются во время компиляции, в то время как исключенные исключения проверяются во время выполнения.
Прочтите эту статью статью, чтобы получить четкое представление.
Ответ 8
Подробнее
Использовать проверенные исключения, когда код клиента может принять какое-то полезное действие восстановления на основе информации в исключении. Используйте исключение, если клиентский код ничего не может сделать. Например, преобразуйте SQLException в другое проверенное исключение, если код клиента может восстановить его и преобразовать ваше SQLException в исключение (исключение RuntimeException), если код клиента ничего не может с этим поделать.