Почему компилятор разрешает броски, когда метод никогда не выдаст исключение - PullRequest
18 голосов
/ 25 марта 2019

Мне интересно, почему компилятор java допускает выбросы в объявлении метода, когда метод никогда не вызовет исключение.Потому что "throws" - это способ обработки исключения (указание вызывающей стороне обработать его).

Поскольку существует два способа обработки исключения (throws & try / catch).В try / catch он не позволяет перехватывать исключение, которое не было сгенерировано в блоке try, но допускает генерирование метода, который не может вызвать исключение.

private static void methodA() {
    try {
        // Do something
        // No IO operation here
    } catch (IOException ex) {  //This line does not compile because
                              //exception is never thrown from try
        // Handle   
    }
}

private static void methodB() throws IOException { //Why does this //compile when excetion is never thrown in function body
    //Do Something 
    //No IO operation
}

Ответы [ 4 ]

25 голосов
/ 25 марта 2019

Предложение throws является частью контракта метода.Он требует, чтобы вызывающий метод вел себя так, как будто указанное исключение может быть вызвано методом (т. Е. Либо перехватить исключение, либо объявить свое собственное предложение throws).

Возможно, что первоначальная версияМетод не генерирует исключение, указанное в предложении throws, но будущая версия может генерировать его, не нарушая API (т. е. любой существующий код, вызывающий метод, все равно будет проходить компиляцию).

Это также противоположно этомувозможный.Если метод, использованный для генерации исключения, указанного в предложении throws, но будущая версия его больше не генерирует, следует сохранить предложение throws, чтобы не нарушать существующий код, использующий ваш метод.

Первый пример:

Предположим, у вас есть этот код, который использует methodB:

private static void methodA() {
    methodB(); // doesn't have throws IOException clause yet
}

Если позже вы захотите изменить methodB на бросок IOException, methodA остановит прохождение компиляции.

Второй пример:

Предположим, у вас есть этот код, который использует methodB:

private static void methodA() {
    try {
        methodB(); // throws IOException
    }
    catch (IOException ex) {

    }
}

Если вы удалите предложение throwsиз будущей версии methodB, methodA больше не будет проходить компиляцию.

Этот пример не очень интересен, когда methodA равен private, потому что он может использоваться только локально (в пределахтот же класс, где легко изменить все методы, которые его вызывают).

Однако, если он становится public, вы не знаете, кто использует (или будет использовать) ваш метод, поэтому у вас нетконтроль всего кода, который может сломаться в результате добавления или удаления throws предложение.

И если это метод экземпляра, есть еще одна причина для разрешения предложения throws, даже если вы не выбрасываете исключение - метод может быть переопределен, а переопределяющий метод может выброситьисключение, даже если реализация базового класса этого не делает.

8 голосов
/ 25 марта 2019

Потому что подпись определяет контракт метода. Даже если метод не генерирует IOException сейчас, возможно, это произойдет в будущем, и вы хотите подготовиться к такой возможности.

Предположим, что вы просто пока предоставляете фиктивную реализацию для метода, но вы знаете, что позже фактическая реализация потенциально вызовет IOException. Если компилятор помешает вам добавить это предложение throws, вы будете вынуждены повторно обработать все вызовы (рекурсивно) для этого метода, как только вы предоставите фактическую реализацию метода.

0 голосов
/ 25 марта 2019
  1. methodB генерирует IOException, поэтому метод, вызывающий methodB, отвечает за перехват исключения, которое будет сгенерировано methodB. Попробуйте вызвать methodB из других методов, он попросит вас перехватить его или повторно выдать IOException. Где-то вам придется перехватывать IOException в цепочке (в блоке try / catch). Так что вы не получите ошибку времени компиляции .

    private void sampleMethod () { пытаться { methodB (); } catch (IOException e) { // TODO автоматически сгенерированный блок catch e.printStackTrace (); } }

  2. try / catch в methodA по общему признанию проглатывает исключение, это означает, что methodA отвечает за перехват исключения в блоке try / catch. « Каждый оператор в любой Java-программе должен быть достижимым, т.е. каждый оператор должен быть выполним как минимум один раз » Таким образом, вы получите ошибку компилятора, так как в вашем блоке try нет кода, вызывающего IOException.

0 голосов
/ 25 марта 2019

Метание ключевых слов сообщает программисту, что в методе может возникнуть исключение IOException. Теперь, если вы не указали try / catch, это означает, что когда выброшено исключение, программа перестанет работать, в то время как в try / catch вы обрабатываете это, делая что-то еще, если выдается исключение.

Используйте throws для удобства чтения и указания возможности исключения и используйте try / catch, чтобы указать программе, что делать в случае исключения.

...