Разница между метками в сигнатуре метода и операторами Throw в Java
Я пытаюсь прояснить разницу между бросает подпись метода и Бросок Заявления в Java. Бросает подпись метода следующим образом:
public void aMethod() throws IOException{
FileReader f = new FileReader("notExist.txt");
}
Throw заявления выглядит следующим образом:
public void bMethod() {
throw new IOException();
}
из моего понимания, a throws
в сигнатуре метода есть уведомление о том, что метод может выдать такое исключение. throw
утверждение-это то, что фактически бросает созданный объект при соответствующих обстоятельствах.
В этом смысле закидываем в сигнатуре метода всегда должно появляться, если существует бросить оператор в методе.
однако следующий код, похоже, этого не делает. Код из библиотеки. Мой вопрос в том, почему это происходит? Я неправильно понимаю концепции?
этот фрагмент кода является копией с java.утиль.LinkedList не. @Автор Джош блох
/**
* 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;
}
обновление ответа:
обновление 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;
}
обновление 2: для проверенного исключения. Нужно ли мне иметь "Броски" в подписи? Да.
// has to throw checked exception otherwise compile error
public String abc() throws IOException{
throw new IOException();
}
4 ответов
вы в значительной степени правы. За исключением одной вещи, которую я упомяну чуть позже.
закидываем является такой же частью API метода, как имя и параметры. Клиенты знают, что если они вызывают этот метод, им нужно обработать это исключение-просто бросив его также или поймав его и обработав (что может фактически повлечь за собой бросание другого исключения, обертывающего оригинал). закидываем при компиляции время.
бросить это фактический акт, позволяющий среде выполнения знать, что что-то плохое произошло-что исключительное состояние, о котором мы беспокоились, на самом деле произошло. Поэтому с этим нужно разобраться во время выполнения.
но вы были не совсем правы, когда сказали: "подпись метода должна всегда появляться, если в методе существует оператор throw.- Это часто так, но не всегда. Я также могу вызвать другой метод, который создает исключение в моем метод, и если я не поймаю его, мой метод должен бросить его. В этом случае нет явного броска того же исключения мной.
последний момент заключается в том, что вам нужно только объявить исключение в закидываем когда исключением является проверил exception -- означает, что он находится с другой стороны иерархии классов исключений из RuntimeException. Общими проверенными исключениями являются IOException и SQLException. Проверенные исключения должны быть перечислены в части бросков подписи метода, если вы не обрабатываете их самостоятельно. Все подклассы RuntimeException-например, NoSuchElementException в вашем примере, а также ненавистное исключение NullPointerException-являются непроверенным исключением и не должны быть пойманы или брошены или что-то еще.
обычно вы используете проверенные исключения для восстанавливаемых проблем (где клиент знает, что может произойти, и может изящно справиться с проблемой и двигаться дальше) и непроверенные исключения для катастрофических проблем (например, не может подключение к базе данных).
Если вы можете пройти все AOP вещи,этой большое обсуждение того, как вы используете проверенные и непроверенные исключения эффективно.
Vidya предоставил отличный ответ на ваши вопросы.
самые важные слова "последний момент заключается в том, что вам нужно только объявить исключение в бросках, когда исключение является проверенным исключением"
просто, чтобы показать вам пример кода, что это значит. Представьте, что мы хотели бы использовать 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
...
}
}
теперь представьте, если бы вы не предоставили бросает IOException и что - то плохое происходит внутри оператора finally {} - это вызовет ошибку.
RuntimeException
s не должны обрабатываться в блоке try-catch, поэтому их не нужно объявлять как брошенные и NoSuchElementException is RuntimeException
потому что это расширяет его.
throw
атрибут в сигнатуре метода, как вы правильно догадались, является намеком компилятору, что метод вызывает исключение, которое должно быть поймано вызывающим. Такого рода исключение, а именно называется проверенное исключение это то, что абонент должны всегда поймать или отправить его вызывающему абоненту снова. Это что-то на уровне компилятора, подпись указывает, какое исключение метод может бросить: это обеспечивает try-catch
или повторная отправка в вызывающий и оператор throw где-то внутри метода-это ограничение, которое разработчик помещает, чтобы указать что-то о поведении метода.
С другой стороны другие исключения, а именно unchecked или исключения на этапе выполнения, (NoSucheElementException
является одним из примеров) являются исключениями, которые вы не обязаны указывать, потому что они возникают из разных ситуаций.
концептуальная разница заключается в том, что проверенное исключение обычно используется для предупреждения исключительная ситуация, с которой нужно как-то справиться (подумайте о IOException
) разработчиком, в то время как непроверенные реальные ошибки (например,NullPointerException
или как в вашем примере NoSuchElementException
)