попытка / поймать против исключения исключения

117

Эквивалентны ли эти операторы кода? Есть ли между ними разница?

private void calculateArea() throws Exception {
    ....do something
}

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}
карлос
источник
3
Не совсем ответ, но вам может быть интересна статья Неда Батчелдера « Исключения в тропическом лесу» , которая помогает объяснить общие случаи, когда предпочтение отдается тому или иному стилю.
Дэниел Прайден,
1
спрашивали ли вы, вместо того, чтобы иметь в улове «showException (e)», есть ли у вас «throws e» в уловке (или вообще не использовать try / catch)?
MacGyver

Ответы:

146

Да, есть огромная разница - последний проглатывает исключение (правда, показывая его), тогда как первый разрешает ему распространяться. (Я предполагаю, что showExceptionэто не изменит его.)

Таким образом, если вы вызываете первый метод и «сделать что-то» не удается, то вызывающий должен будет обработать исключение. Если вы вызываете второй метод и «сделать что-то» не удается, то вызывающий вообще не увидит исключения ... что, как правило, плохо, если только showExceptionон действительно не обработал исключение, не исправил все, что было неправильно, и, как правило, убедился, что который calculateAreaдостиг своей цели.

Вы будете в состоянии сказать это, потому что вы не можете назвать первым способом без либо ловить Exceptionсебя или объявить , что ваш метод может бросить его тоже.

Джон Скит
источник
12
Когда вы упоминаете, что «Если исключение действительно не обрабатывается», это замечательно. Я просто подумал, что добавлю, что перехват «исключения» сам по себе редко приводит к интеллектуальной «обработке» фактического исключения, поэтому люди рекомендуют перехватить наиболее конкретное возможное исключение.
Bill K,
17
+1. Потому что Джону Скиту нужно больше репутации. Да, и ответ тоже был хорош.
Джонатан Спиллер
20

Первый throws Exception, поэтому вызывающий должен обрабатывать Exception. Второй улавливает и обрабатывает Exceptionвнутренне, поэтому вызывающему абоненту не нужно выполнять какую-либо обработку исключений.

samitgaur
источник
Короче говоря, я всегда должен использовать второй. Я прав? Первый - это фактически метод, который используется в разных частях программы. Вот почему я решил собрать вместе инструкции для дальнейшего использования, но, сделав это, я теперь понимаю, что Т. совершал большую ошибку ..
Карлос
9
Нет, нужны оба шаблона. Если ваш метод может обрабатывать исключение, используйте второй шаблон, если нет, используйте первый, чтобы уведомить вызывающего.
Андреас Долк
Какую версию вы используете, зависит от ваших требований - в основном, на каком уровне вам нужно обрабатывать это исключение. Вызывающий абонент должен быть соответствующим образом закодирован. Если вызывающий абонент вызывал первую версию, а вы заменяете определение метода второй версией, ваш код вызывающего абонента будет вынужден обрабатывать исключение, поскольку это проверенное исключение.
samitgaur
16

Да. Версия, которая объявляет throws Exception, потребует, чтобы вызывающий код обрабатывал исключение, а версия, которая явно обрабатывает это, не будет.

т.е. просто:

performCalculation();

по сравнению с переносом бремени обработки исключения на вызывающего:

try {
    performCalculation();
catch (Exception e) {
    // handle exception
}
Lyle
источник
6

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

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

Крис Томпсон
источник
3

Есть один конкретный сценарий, в котором мы не можем использовать броски, мы должны использовать try-catch. Существует правило «Переопределенный метод не может генерировать никаких дополнительных исключений, кроме тех, которые выбрасывает его родительский класс». Если есть какое-либо дополнительное исключение, которое следует обработать с помощью try-catch. Рассмотрим этот фрагмент кода. Есть простой базовый класс

package trycatchvsthrows;

public class Base {
    public void show()
    {
        System.out.println("hello from base");
    }
}

и его производный класс:

package trycatchvsthrows;

public class Derived extends Base {

    @Override
    public void show()   {
        // TODO Auto-generated method stub
        super.show();

        Thread thread= new Thread();
        thread.start();
        try {
            thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // thread.sleep(10);
        // here we can not use public void show() throws InterruptedException 
        // not allowed
    }
}

Когда нам нужно вызвать thread.sleep (), мы вынуждены использовать try-catch, здесь мы не можем использовать:

 public void show() throws InterruptedException

потому что переопределенный метод не может генерировать дополнительные исключения.

Арджун Тхакур
источник
Я считаю, что не все знают об этой оговорке. Хорошо заостренный.
ivanleoncz
1

Я предполагаю, что под «идентичным» вы имеете в виду поведение.

Поведение функции можно определить по:

1) Возвращаемое значение

2) Выброшенные исключения

3) Побочные эффекты (например, изменения в куче, файловой системе и т. Д.)

В этом случае первый метод распространяет любое исключение, в то время как второй не генерирует проверенное исключение, а также проглатывает большинство непроверенных исключений, поэтому поведение ИНАЧЕ.

Однако, если вы гарантируете, что «сделать что-то» никогда не вызовет исключения, то поведение будет идентичным (хотя в первой версии компилятор потребует, чтобы вызывающий обработал исключение)

--редактировать--

С точки зрения дизайна API, методы совершенно разные по своему контракту. Также не рекомендуется выбрасывать исключение класса. Попробуйте создать что-то более конкретное, чтобы вызывающий абонент мог лучше обработать исключение.

Эяль Шнайдер
источник
1

Если вы создали исключение, дочерний метод (который отменяет это) должен обработать исключение.

пример:

class A{
public void myMethod() throws Exception{
 //do something
}
}

A a=new A();
try{
a.myMethod();
}catch Exception(e){
//handle the exception
}
Шериф Эльдиб
источник
0

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

isaace
источник
0

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

private void calculateArea() throws Exception {
    // Do something
}

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

private void calculateArea() {
    try {
        // Do something

    } catch (Exception e) {
        showException(e);
    }
}
JSON C11
источник
0
private void calculateArea() throws Exception {
    ....do something
}

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

А во втором случае:

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

Здесь исключение обрабатывается вызываемым пользователем, поэтому вероятность аварийного завершения программы отсутствует.

Попробуй поймать - рекомендуемый подход.

ИМО,

  • Ключевое слово Throws в основном используется с проверенными исключениями, чтобы убедить компилятор, но не гарантирует нормального завершения программы.

  • Ключевое слово Throws делегирует ответственность за обработку исключений
    вызывающей стороне (JVM или другой метод).

  • Ключевое слово Throws требуется только для проверенных исключений, для непроверенных исключений ключевое слово throws не используется.

Нитин Павар
источник