В чем разница между throw e и throw new Exception (e)? - PullRequest
0 голосов
/ 04 марта 2019

Рассмотрим:

try  {
    // Some code here
} catch (IOException e) {
    throw e;
} catch (Exception e) {
    throw e;
}

В чем разница между throw e и throw new Exception(e)?

try  {
   // Some code here
} catch (IOException e) {
   throw new IOException(e);
} catch (Exception e) {
   throw new Exception(e);
}

Ответы [ 6 ]

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

Сначала нам нужно понять, зачем вам создавать новый тип исключения для инкапсуляции исключения.

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

Например:

try {
  // read file
} catch (IOException e) {
  throw new MyAppFailedToReadFile(e);
}

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

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

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

throw e объявляет экземпляр IOException (назначает пространство памятина устройстве без сохранения данных), поэтому вы перебрасываете его в блок catch, когда объявляете заранее сделанное исключение.

throw new IOException e инициализирует новый экземпляр IOException, поэтому вы создаете новое исключение в блоке catch, поскольку оно не ссылается на другое исключение.

Однако

Обычно вы не генерируете исключения в блоке catch.В большинстве случаев вы должны:

  1. Предупредить компилятор, что вы собираетесь сгенерировать исключение для метода (throws IOException после объявления параметра)
  2. Бросить исключение (throw new IOException("Warning text") в теле метода) всякий раз, когда вводимые данные не могут быть проверены в любом случае.
  3. В блоках try / catch поместите вызов или вызов метода в блок try;в блоке catch поместите сообщение об ошибке.

Пример кода будет выглядеть следующим образом:

public static void myMethod() throws IOException{
int prueba=0;
if(prueba>9 //some condition){
    //do a thing
}else
    throw new IOException("This number is not correct");
}//end of method
try{
    myClass.myMethod();
}catch{
    System.out.println("An error has occurred");
}//end of try/catch

Это то, как я учился делатьисключения правильно, но я надеюсь, что я ответил на ваш вопрос.

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

Ну, в принципе, throw e будет "перебрасывать" все исходные значения - также некоторый поток кода, который должен быть скрыт, например, например, из соображений безопасности.Если вы воссоздадите исключение, вы получите - или можете получить - еще одну трассировку стека на месте.

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

Давайте немного проверим следующее:

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

Генератор исключений

public class ExceptionsThrow {
    public static void throwNewException() throws Exception {
        throw new Exception("originally thrown message");
    }
}

Класс для перебрасывания / воссоздания исключений

  public class Exceptions {

        public static void reThrowException() throws Exception {
            try {
                ExceptionsThrow.throwNewException();
            } catch (Exception e) {
                throw e;
            }
        }

        public static void reCreateNewException() throws Exception {
            try {
                ExceptionsThrow.throwNewException();
            } catch (Exception e) {
                throw new Exception(e);
            }
        }
    }

Пример кода тестирования:

try {
     Exceptions.reThrowException();
} catch (Exception e) {
    System.out.println("1st RETHROW");
    e.printStackTrace();
    System.out.println("===========");
}

try {
    Exceptions.reCreateNewException();
} catch (Exception e) {
    System.out.println("2nd RECREATE");
    e.printStackTrace();
    System.out.println("===========");
}

И наконец вывод:

1st RETHROW
java.lang.Exception: originally thrown message
    at test.main.stackoverflow.ExceptionsThrow.throwNewException(ExceptionsThrow.java:5)
    at test.main.stackoverflow.Exceptions.reThrowException(Exceptions.java:7)
    at test.main.MainTest.main(MainTest.java:110)
java.lang.Exception: java.lang.Exception: originally thrown message===========
2nd RECREATE

    at test.main.stackoverflow.Exceptions.reCreateNewException(Exceptions.java:17)
    at test.main.MainTest.main(MainTest.java:118)
Caused by: java.lang.Exception: originally thrown message
    at test.main.stackoverflow.ExceptionsThrow.throwNewException(ExceptionsThrow.java:5)
    at test.main.stackoverflow.Exceptions.reCreateNewException(Exceptions.java:15)
    ... 1 more
===========

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

  • Я возьму только причину из исходного исключения, но она переопределитданные
  • , как вы можете видеть, вновь созданное исключение не содержит полную трассировку стека, как источник

Итак:

public static void maskException() throws Exception {
    try {
        ExceptionsThrow.throwNewException();
    } catch (Exception e) {
        throw new Exception("I will dont tell you",e.getCause());
    }
}

Ирезультат:

===========
3rd mask
java.lang.Exception: I will don't tell you
    at test.main.stackoverflow.Exceptions.maskException(Exceptions.java:25)
    at test.main.MainTest.main(MainTest.java:126)
===========

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

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

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

Этот пример не имеет особого смысла в этом контексте, потому что вы выкидываете то же исключение и больше ничего не делаете.Регистрация по крайней мере будет иметь больше смысла.Вы ловите исключение для обработки или регистрации.Если вы не можете справиться с этим, перебросьте его (случай 1) или перенесите на что-нибудь другое (случай 2).

Случай 1:

public class Main {

    // forced to handle or rethrow again
    public static void main(String[] args) throws IOException {
        read();
    }

    public static void read() throws IOException {
        try {
            readInternal();
        } catch (IOException e) {
            throw e;
        }
    }

    private static void readInternal() throws IOException {
        throw new IOException("Output error");
    }
}

В выходных данныхВы увидите что-то вроде:

Exception in thread "main" java.io.IOException: Output error
    at com.alex.java.Main.readInternal(Main.java:26)
    at com.alex.java.Main.read(Main.java:19)
    at com.alex.java.Main.main(Main.java:14)
**Case 2:**

Шаблон ниже позволяет вам изменить тип исключения и также сохранить исходные детали исключения:

try {
   // Some code here
} catch (IOException e) {
    throw new IllegalStateException(e);
}

Этот случай часто происходит, когдаВы хотели бы заменить Checked Exception на Unchecked exception, сохраняя происхождение проблемы, и сохранить всю информацию (что называется цепочкой исключений).

Обычные сценарии использования:

  • Вы не можете обработать Checked Exception и не хотите возвращать его вызывающей стороне.Повторное отбрасывание проверенных исключений заставит вызывающего обработать его.Это не то, что вы хотите сделать, если нет регулярных случаев восстановления.
  • Исключения, такие как IOException, редко бывают полезны для клиента.Вам необходимо отправить что-то более конкретное и понятное в области вашего бизнеса.

IOException, завернутый в Unchecked Exception, как DocumentReadException, проливает свет на реальную ситуацию и не заставляетвызывающие для обработки:

public class Main {

    public static void main(String[] args) {
        read();
    }

    public static void read() {
        try {
            readInternal();
        } catch (IOException e) {
            // log and wrap the exception to a specific business exception
            logger.error("Error reading the document", e);
            throw new DocumentReadException(e);
        }
    }

    private static void readInternal() throws IOException {
        throw new IOException("Output error");
    }
}

Вывод будет похож на:

Exception in thread "main" java.lang.IllegalArgumentException: Error reading the document
    at com.alex.java.Main.read(Main.java:21)
    at com.alex.java.Main.main(Main.java:14)
Caused by: java.io.IOException: Output error
    at com.alex.java.Main.readInternal(Main.java:26)
    at com.alex.java.Main.read(Main.java:19)
    ... 1 more

Как видно из трассировки стека, основной причиной был регистратор, который поможет вам выяснить,исходная проблема и исключение бизнес-домена были отправлены пользователю.

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

Если вам не нужно настраивать тип исключения, вы перебрасываете (выбрасываете дальше) тот же экземпляр без каких-либо изменений:

catch (IOException e) {
    throw e;
}

Если вам нужно настроитьтип исключения, вы переносите e (как причину) в новое исключение требуемого типа.

catch (IOException e) {
    throw new IllegalArgumentException(e);
}

Я считаю все другие сценарии кодомзапах.Ваш второй фрагмент является хорошим примером этого.


Вот ответы на вопросы, которые могут появиться.

Зачем мне это нужно?сбросить исключение?

Вы можете отпустить это.Но если это произойдет, вы не сможете ничего сделать на этом уровне.

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

Почему я хочу настроить исключение?

Как правило,

Более высокие уровни должны улавливать исключения более низкого уровня и, вместо них, генерировать исключения, которые можно объяснить в терминах более высокого уровня.уровень абстракции.

Эффективная Java - 2-е издание - Элемент 61: Бросьте исключения, соответствующие абстракции

Другими словами, в какой-то момент неизвестность IOException должно быть преобразовано в заметное MySpecificBusinessRuleException.

Я назвал это "настройка типа исключения" , умные парни называют это преобразование исключения (в частности создание цепочки исключений ).


Чтобы прояснить ситуацию, давайте приведем несколько глупых примеров.

class StupidExample1 {
    public static void main(String[] args) throws IOException {
        try {
            throw new IOException();
        } catch (IOException e) {
            throw new IOException(new IOException(e));
        }
    }
}

приводит к многословной трассировке стека, например

Exception in thread "main" java.io.IOException: java.io.IOException: java.io.IOException
    at StupidExample1.main(XXX.java:XX)
Caused by: java.io.IOException: java.io.IOException
    ... 1 more
Caused by: java.io.IOException
    at StupidExample1.main(XXX.java:XX)

, котораяможет (и должен) быть эффективно уменьшен до

Exception in thread "main" java.io.IOException
    at StupidExample1.main(XXX.java:XX)

Еще один:

class StupidExample2 {
    public static void main(String[] args) {
        takeString(new String(new String("myString")));
    }

    static void takeString(String s) { }
}

Очевидно, что new String(new String("myString")) является многословной версией "myString" и должна быть реорганизована впоследний.

0 голосов
/ 04 марта 2019
catch (IOException e) {
    throw e;
}

Вы увидите оригинальное исключение только с оригинальной трассировкой стека.Вы не увидите эту строку «rethrow» в трассировке стека, поэтому она вроде прозрачна.

catch (IOException e) {
    throw new IllegalStateException(e);
}

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

catch (IOException e) {
     throw new IOException();
}

Вы увидите только текущую трассировку стека создания IOException,причина не добавлена.

...