Разница между Throws в сигнатуре метода и Throw Statement в Java
Я пытаюсь очистить разницу между Throws в сигнатуре метода и Throw Statement в Java.
Выдает подпись метода следующим образом:
public void aMethod() throws IOException{
FileReader f = new FileReader("notExist.txt");
}
Throw Statement выглядит следующим образом:
public void bMethod() {
throw new IOException();
}
По моему мнению, throws
в сигнатуре метода является уведомлением о том, что метод может вызывать такое исключение. throw
- это то, что на самом деле бросает созданный объект в соответствии с обстоятельствами.
В этом смысле throws в сигнатуре метода должен всегда отображаться, если в методе существует оператор throw.
Однако следующий код, похоже, не делает этого. Код из библиотеки. Мой вопрос, почему это происходит? Я понимаю понятия неправильно?
Этот фрагмент кода является копией из java.util.linkedList. @author Джош Блох
/**
* Returns the first element in this list.
*
* @return the first element in this list
* @throws NoSuchElementException if this list is empty
*/
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
Обновление ответа:
update 1: находится выше кода так же, как и следующее:
// as far as I know, it is the same as without throws
public E getFirst() throws NoSuchElementException {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
update 2: для проверенного исключения. Нужно ли иметь "броски" в подписи? Да.
// has to throw checked exception otherwise compile error
public String abc() throws IOException{
throw new IOException();
}
Ответы
Ответ 1
Ты в порядке. За исключением того, что я расскажу немного.
throws является такой же частью API-интерфейса метода, как имя и параметры. Клиенты знают, ссылаются ли они на этот метод, им нужно обработать это исключение - просто бросив его, а также поймав его и обработать (что фактически может привести к выбросу другого исключения, обертывающего оригинал). throws адресуется во время компиляции.
throw - это фактический акт, позволяющий среде выполнения знать, что случилось что-то плохое - что исключительное условие, в котором мы волновались, фактически имело место. Поэтому его нужно решать во время выполнения.
Но вы были не совсем правы, когда вы сказали: "Броски в методе должны всегда появляться, если в методе есть выражение throw". Это часто верно, но не всегда. Я мог бы также вызвать другой метод, который генерирует исключение в моем методе, и если я его не поймаю, мой метод должен его бросить. В этом случае явное явное исключение не имеет.
Конечным моментом является то, что вам нужно только объявить исключение в throws, когда исключение является исключенным исключением - это означает, что это с другой стороны иерархии классов Exception из RuntimeException. Общими проверенными исключениями являются IOException и SQLException. Проверенные исключения должны быть указаны в части броска метода, если вы не обрабатываете их самостоятельно. Любое подклассическое RuntimeException - как исключение NoSuchElementException в вашем примере, а также ненавистное исключение NullPointerException - это неконтролируемое исключение и его не нужно поймать или выбросить или что-то еще.
Как правило, вы используете проверенные исключения для восстанавливаемых проблем (когда клиент знает, что может произойти, и может изящно справиться с этой проблемой и двигаться дальше) и исключенных исключений для катастрофических проблем (например, невозможно подключиться к базе данных).
Если вы можете обойти все материалы АОП, , это отличное обсуждение того, как эффективно использовать проверенные и непроверенные исключения.
Ответ 2
RuntimeException
не нужно обрабатывать в блоке try-catch, поэтому они не должны быть объявлены как брошенные и NoSuchElementException RuntimeException
, потому что он расширяет его.
Ответ 3
throw
атрибут в сигнатуре метода, как вы правильно догадались, является подсказкой для компилятора о том, что метод вызывает исключение, которое должно быть уловлено вызывающим. Такое исключение, а именно: проверенное исключение - это то, что вызывающий ДОЛЖЕН всегда ловить или отправлять его вызывающему абоненту. Это что-то на уровне компилятора, подпись указывает, какое исключение может использовать метод: это обеспечивает try-catch
или повторную отправку в вызывающем абоненте, а оператор throw внутри метода - это ограничение, которое разработчик указывает, чтобы указать что-то о поведении метода.
С другой стороны, другие исключения, а именно исключения или исключения во время выполнения (NoSucheElementException
- один пример), являются исключениями, которые вы не обязаны указывать, потому что они возникают из разных ситуаций.
Концептуальная разница заключается в том, что проверенное исключение обычно используется для предупреждения об исключительной ситуации, которую разработчик должен каким-либо образом обрабатывать (думать о IOException
), а unchecked - это реальные ошибки (например, NullPointerException
или как в вашем примере NoSuchElementException
)
Ответ 4
Видья дал отличный ответ на ваши вопросы.
Наиболее важными словами являются: "Конечным моментом является то, что вам нужно только объявить исключение в бросках, когда исключение является проверенным исключением"
Просто, чтобы показать вам пример кода, что это значит. Представьте, что мы хотели бы использовать FileOutputStream для передачи некоторых данных. Функция будет выглядеть так:
public void saveSomeData() throws IOException {
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("input.txt");
out = new FileOutputStream("output.txt");
int c;
while ((c = out.read() != -1) {
in.write(c);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// Close in
if (in != null) {
in.close(); // <-- If something bad happens here it will cause runtime error!
}
// Close out
...
}
}
Теперь представьте, если бы вы не предоставили throws IOException, и что-то не так происходит внутри finally {} statement - это вызовет ошибку.