Подтвердить что ты не робот

Разница между 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();
}
4b9b3361

Ответ 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 - это вызовет ошибку.