В чем преимущество цепочечных исключений - PullRequest
12 голосов
/ 16 февраля 2011

Я не понимаю преимуществ наличия связанного исключения в коде.

Учитывая пример ResourceLoader из мира java , если программисту известна возможность встретить ResourceLoadException, почему бы не перехватить то же исключение вместо SQLException? Иначе, программист может поймать оба исключения в одном и том же коде, чем бросать новый экземпляр Throwable?

Ответы [ 7 ]

16 голосов
/ 12 декабря 2014

Почему исключение цепи?

Нам нужно объединить исключения, чтобы сделать журналы читабельными.

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

Создать следующие исключения

    class NoLeaveGrantedException extends Exception {

        public NoLeaveGrantedException(String message, Throwable cause) {
            super(message, cause);
        }

        public NoLeaveGrantedException(String message) {
            super(message);
        }
    }

    class TeamLeadUpsetException extends Exception {

        public TeamLeadUpsetException(String message, Throwable cause) {
            super(message, cause);
        }

        public TeamLeadUpsetException(String message) {
            super(message);
        }
    }

    class ManagerUpsetException extends Exception {

        public ManagerUpsetException(String message, Throwable cause) {
            super(message, cause);
        }

        public ManagerUpsetException(String message) {
            super(message);
        }
    }

    class GirlFriendOfManagerUpsetException extends Exception {

        public GirlFriendOfManagerUpsetException(String message, Throwable cause) {
            super(message, cause);
        }

        public GirlFriendOfManagerUpsetException(String message) {
            super(message);
        }
    }

Теперь используйте их

1. Без цепочки

    public class MainClass {

        public static void main(String[] args) throws Exception {
            getLeave();
        }

        static void getLeave() throws NoLeaveGrantedException {
            try {
                howIsTeamLead();
            } catch (TeamLeadUpsetException e) {
                e.printStackTrace();
                throw new NoLeaveGrantedException("Leave not sanctioned.");
            }
        }

        static void howIsTeamLead() throws TeamLeadUpsetException {
            try {
                howIsManager();
            } catch (ManagerUpsetException e) {
                e.printStackTrace();
                throw new TeamLeadUpsetException(
                            "Team lead is not in good mood");
            }
        }

        static void howIsManager() throws ManagerUpsetException {
            try {
                howIsGirlFriendOfManager();
            } catch (GirlFriendOfManagerUpsetException e) {
                e.printStackTrace();
                throw new ManagerUpsetException("Manager is in bad mood");
            }

        }

        static void howIsGirlFriendOfManager() 
             throws GirlFriendOfManagerUpsetException {
            throw new GirlFriendOfManagerUpsetException(
             "Girl friend of manager is in bad mood");
        }
    }

2. Цепной

    public class MainClass {

        public static void main(String[] args) throws Exception {
            getLeave();
        }

        static void getLeave() throws NoLeaveGrantedException {
            try {
                howIsTeamLead();
            } catch (TeamLeadUpsetException e) {
                throw new NoLeaveGrantedException("Leave not sanctioned.", e);
            }
        }

        static void howIsTeamLead() throws TeamLeadUpsetException {
            try {
                howIsManager();
            } catch (ManagerUpsetException e) {
                throw new TeamLeadUpsetException(
                           "Team lead is not in good mood", e);
            }
        }

        static void howIsManager() throws ManagerUpsetException {
            try {
                howIsGirlFriendOfManager();
            } catch (GirlFriendOfManagerUpsetException e) {
                throw new ManagerUpsetException("Manager is in bad mood", e);
            }

        }

        static void howIsGirlFriendOfManager() 
           throws GirlFriendOfManagerUpsetException {
            throw new GirlFriendOfManagerUpsetException(
              "Girl friend of manager is in bad mood");
        }
    }

Теперь сравните журналы

1. Без цепочки

    com.bskyb.svod.autoingest.GirlFriendOfManagerUpsetException: Girl friend of manager is in bad mood
        at com.bskyb.svod.autoingest.MainClass.howIsGirlFriendOfManager(MainClass.java:61)
        at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:52)
        at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:43)
        at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
        at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
    com.bskyb.svod.autoingest.ManagerUpsetException: Manager is in bad mood
        at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:55)
        at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:43)
        at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
        at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
    com.bskyb.svod.autoingest.TeamLeadUpsetException: Team lead is not in good mood
        at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:46)
        at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
        at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
    Exception in thread "main" com.bskyb.svod.autoingest.NoLeaveGrantedException: Leave not sanctioned.
        at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:37)
        at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)

2. Цепной

    Exception in thread "main" com.bskyb.svod.autoingest.NoLeaveGrantedException: Leave not sanctioned.
        at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:36)
        at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
    Caused by: com.bskyb.svod.autoingest.TeamLeadUpsetException: Team lead is not in good mood
        at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:44)
        at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
        ... 1 more
    Caused by: com.bskyb.svod.autoingest.ManagerUpsetException: Manager is in bad mood
        at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:52)
        at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:42)
        ... 2 more
    Caused by: com.bskyb.svod.autoingest.GirlFriendOfManagerUpsetException: Girl friend of manager is in bad mood
        at com.bskyb.svod.autoingest.MainClass.howIsGirlFriendOfManager(MainClass.java:58)
        at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:50)
        ... 3 more
15 голосов
/ 16 февраля 2011

Может ли кто-нибудь предоставить информацию о необходимости цепных исключений?

В статье это хорошо сказано:

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

То есть, если у вас есть метод, который загружает какой-либо объект из базы данных, вы, скорее всего, захотите немного ResourceLoadException (ближе к уровню абстракции методов) вместо низкоуровневого SQLException, даже если это был Первоначальный источник проблемы. Однако, если вы просто поймаете SQLException и бросите вместо него ResourceLoadException, вы можете потерять важную отладочную информацию.

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

Иначе, программист может поймать оба исключения в одном и том же коде, чем необходимость создания нового экземпляра Throwable?

Я не совсем понимаю твои рассуждения здесь. Дело в том, что ему не нужно беспокоиться о SQLException на этом уровне абстракции.

5 голосов
/ 16 февраля 2011

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

Все, что вам нужно учитывать при вызове loadResource, это то, что он может вызвать исключение ResourceLoadException,Не то, чтобы детали реализации не сработали из-за SQLException - это тоже может со временем измениться, позже кто-то может решить загрузить ресурсы из другого места, что тоже может дать сбой.

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

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

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

5 голосов
/ 16 февраля 2011

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

2 голосов
/ 16 февраля 2011

Первое преимущество - инкапсуляция. ResourceLoader может быть интерфейсом с несколькими реализациями (например, одна загружает ресурсы из базы данных, а другая загружает их из файловой системы), где используемая реализация выбирается во время выполнения. Тогда вызывающая сторона должна быть независима от основной причины, по которой загрузка ресурса не удалась, но все же может захотеть реагировать на сбои загрузки ресурса. Это особенно полезно, если интерфейс объявляет два разных исключения, на которые может вызвать вызывающая сторона по-разному реагировать (например, TransientResourceLoadFailureException, где повторная попытка может быть успешной, и PermanentResourceLoadFailureException, где повторная попытка, как известно, не будет успешной).

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

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

1 голос
/ 16 февраля 2011

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

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

0 голосов
/ 29 августа 2018

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

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