Разница между метками в сигнатуре метода и операторами 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 {} - это вызовет ошибку.


RuntimeExceptions не должны обрабатываться в блоке try-catch, поэтому их не нужно объявлять как брошенные и NoSuchElementException is RuntimeException потому что это расширяет его.


throw атрибут в сигнатуре метода, как вы правильно догадались, является намеком компилятору, что метод вызывает исключение, которое должно быть поймано вызывающим. Такого рода исключение, а именно называется проверенное исключение это то, что абонент должны всегда поймать или отправить его вызывающему абоненту снова. Это что-то на уровне компилятора, подпись указывает, какое исключение метод может бросить: это обеспечивает try-catch или повторная отправка в вызывающий и оператор throw где-то внутри метода-это ограничение, которое разработчик помещает, чтобы указать что-то о поведении метода.

С другой стороны другие исключения, а именно unchecked или исключения на этапе выполнения, (NoSucheElementException является одним из примеров) являются исключениями, которые вы не обязаны указывать, потому что они возникают из разных ситуаций.

концептуальная разница заключается в том, что проверенное исключение обычно используется для предупреждения исключительная ситуация, с которой нужно как-то справиться (подумайте о IOException) разработчиком, в то время как непроверенные реальные ошибки (например,NullPointerException или как в вашем примере NoSuchElementException)