Является ли хорошей практикой перехват множества конкретных исключений вместе с одним общим универсальным исключением?

Общая проблема

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

Например, может быть полезно скрыть подробности сбоя в классе DAO, выбрасывая общий DaoException. Таким образом, клиентам не нужно знать, читаете ли вы из файла, веб-службы или реляционной базы данных. Но предположим, что вы проверяете вводимые пользователем данные, и есть по крайней мере четыре вещи, которые могут пойти не так с вводом пользователя. Разве в последнем случае не разумнее выбросить четыре разных исключения, по одному на каждую ошибку, которая пошла не так с проверкой?

Моя конкретная проблема

В моем текущем проекте я работаю над методом обслуживания, который сохраняет древовидную структуру в реляционной базе данных. Он должен проверить дерево, и есть по крайней мере четыре вещи, которые могут быть неправильными с деревом. Может быть дублирующийся узел или в узле могут отсутствовать обязательные поля X, Y, Z. Таким образом, для метода обслуживания имеет смысл генерировать четыре разных исключения: DuplicateNodeException, MissingXException, MissingYException, MissingZException.

Но служебный метод также использует класс DAO, который генерирует DataAccessException через JdbcTemplate. Хотелось бы узнать, как обращаться с этим DataAccessException. Имеет ли смысл обернуть его как ManagerException, а затем снова как ServiceException и обрабатывать как ServiceException? Тогда я бы смешал оба подхода: (а) выбрасывать конкретные описательные исключения и (б) генерировать общие исключения оболочки. Хорошая идея - смешать здесь эти подходы?

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

Возможное решение (согласно ответу Андреаса)

Имеет ли смысл обрабатывать подобные исключения в моем классе Service? Ниже приведен псевдокод, представляющий возможное решение. Таким образом, я не создаю бесполезное, проверенное, невзрачное исключение ServiceException, но у меня есть универсальное средство для непроверенных исключений (путем перехвата исключения в конце). Что вы думаете об этом решении?

class HttpService {

    private Service service;

    // ...

    public HttpServiceResponse saveTree(Node root) {
        try {
            service.saveTree(root);  
        } catch (DuplicateNodeException e) {
            return HttpServiceResponse.failure(DUPLICATE_NODE_EXCEPTION);
        } catch (MissingXException e) {
            return HttpServiceResponse.failure(MISSING_X_EXCEPTION);
        } catch (MissingYException e) {
            return HttpServiceResponse.failure(MISSING_Y_EXCEPTION);
        } catch (MissingZException e) {
            return HttpServiceResponse.failure(MISSING_Z_EXCEPTION);
        } catch (Exception e) {
            return HttpServiceResponse.failure(INTERNAL_SERVER_ERROR);
        }
    }
}

Совет Эффективная Java - генерировать исключения, соответствующие абстракции.

Andy Turner 29.10.2018 18:19

@AndyTurner Спасибо, это хороший совет. Вы проголосовали против? Если да, то почему?

ktm5124 29.10.2018 18:20

Я не голосовал против.

Andy Turner 29.10.2018 18:21

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

tsolakp 29.10.2018 18:24

@tsolakp Да, есть. Но исключение, которое я пытаюсь обработать надлежащим образом, - это исключение DataAccessException (не отмеченное), созданное JdbcTemplate в моем классе DAO. Теперь, если оба уровня диспетчера и службы генерируют исключение DataAccessException, это не соответствует абстракции, согласно совету Энди Тернера. И если бы класс DAO переключился на файл или веб-службу, то внезапно мне пришлось бы перехватывать исключение IOException или RemoteException на уровнях диспетчера и службы. Вот почему я решил абстрагироваться от него как ManagerException на уровне менеджера и ServiceException на уровне сервиса.

ktm5124 29.10.2018 18:28

В то время как JDBC API выдает проверилSQLException, JdbcTemplate обертывает их с помощью не отмеченDataAccessException, поэтому вызывающим абонентам не нужно специально объявлять и обрабатывать их. Нет необходимости оборачивать DataAccessExceptionServiceException. Если служба выполняет другие действия, которые вызывают исключения проверил, они должны быть аналогичным образом обернуты конкретными исключениями, а не общим ServiceException. Вызывающий не заботится об этих исключениях, потому что вызывающий ничего не может с ними поделать, но не просто переносите все исключения в общий ServiceException.

Andreas 29.10.2018 18:35

@Andreas Для меня это имеет смысл. Я обновил свой вопрос, указав возможное решение. Что вы думаете об этом решении? Это согласуется с тем, что вы говорите?

ktm5124 29.10.2018 18:48

@ ktm5124 Не отмечено ли исключение DuplicateNodeException или MissingXException? Если да, то зачем обрабатывать и оборачивать их HttpServiceResponse.failure?

tsolakp 29.10.2018 18:51

@tsolakp DuplicateNodeException и MissingXException - отмеченные исключения. Я оборачиваю их HttpServiceResponse.failure, чтобы я мог вернуть интеллектуальное сообщение об ошибке в вызов AJAX, который вызывает мою службу.

ktm5124 29.10.2018 18:53

@ ktm5124 Я бы объявил их отключенными, если вы не можете изменить их исходный код. Обычно вы редко определяете пользовательские проверенные исключения.

tsolakp 29.10.2018 18:55

@tsolakp Но я хочу, чтобы вызывающая сторона действовала в соответствии с ними, поскольку это восстанавливаемые исключения, поэтому имеет смысл объявить их как отмеченные, не так ли? См. Десять советов в конце этой статьи: blog.takipi.com/….

ktm5124 29.10.2018 19:14

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

VGR 29.10.2018 20:08
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
12
51
1

Ответы 1

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

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

Другие вопросы по теме