Я всегда сталкиваюсь с этим ... пытаясь найти правильный баланс между попыткой / отловом и кодом, который не превращается в этот непристойный беспорядок вкладок, скобок и исключений, которые отбрасываются обратно в стек вызовов, как горячий картофель. Например, у меня есть приложение, которое я сейчас разрабатываю и которое использует SQLite. У меня есть интерфейс базы данных, который абстрагирует вызовы SQLite, и модель, которая принимает входящие / исходящие данные из базы данных ... Поэтому, если / когда возникает исключение SQLite, оно должно быть передано в модель (которую он вызвал) ), который должен передать его тому, кто вызвал AddRecord / DeleteRecord / что угодно ...
Я являюсь поклонником исключений, а не возвращаю коды ошибок, потому что коды ошибок можно игнорировать, забыть и т. Д., В то время как Исключение, по сути, должно быть обработано (предоставлено, я мог бы поймать и двигаться дальше ...) уверен, что должен быть лучший способ, чем то, что у меня сейчас происходит.
Изменить: я должен был сформулировать это немного по-другому. Я понимаю, что перебрасывать как разные типы и тому подобное, я плохо сформулировал, и это моя вина. Мой вопрос ... как лучше всего поддерживать чистоту кода при этом? Это только начинает чувствовать себя чрезвычайно загроможденным для меня через некоторое время.
источник
Ответы:
Думайте об этом с точки зрения строгой типизации, даже если вы не используете строго типизированный язык - если ваш метод не может вернуть тип, который вы ожидали, он должен вызвать исключение.
Кроме того, вместо создания исключения SQLEx в модели (или, что еще хуже, в пользовательском интерфейсе), каждый слой должен перехватывать известные исключения и переносить / изменять / заменять их на исключения, подходящие для этого уровня:
Это должно помочь ограничить количество исключений, которые вы ищете в каждом слое, и помочь вам поддерживать организованную систему исключений.
источник
throws SQLException
метод, который не подразумевает, что SQL даже задействован. А что произойдет, если вы решите, что некоторые операции должны идти в хранилище файлов? Теперь вы должны заявитьthrows SQLException, IOException
и т.д. Это выйдет из-под контроля.Исключения позволяют писать более чистый код, потому что большая его часть заботится о нормальном случае, а исключительные случаи могут быть обработаны позже, даже в другом контексте.
Правило обработки (перехвата) исключений заключается в том, что это должно быть сделано в контексте, который действительно может что-то с этим сделать. Но у этого есть исключение:
Исключения должны быть перехвачены на границах модулей (особенно на границах слоев), и даже для того, чтобы ограничить их, возникает исключение более высокого уровня, которое имеет значение для вызывающей стороны. Каждый модуль и слой должны скрывать детали своей реализации даже в отношении исключений (модуль кучи может выдавать HeapFull, но не ArrayIndexOutOfBounds).
В вашем примере маловероятно, что верхние уровни могут что-либо делать с исключением SQLite (если они это сделают, то все это настолько связано с SQLite, что вы не сможете переключить слой данных на что-то другое). Существует несколько предсказуемых причин сбоя таких вещей, как Add / Delete / Update, и некоторые из них (несовместимые изменения в параллельных транзакциях) невозможно восстановить даже на уровне данных / постоянства (нарушение правил целостности, fi). Уровень персистентности должен переводить исключения в нечто значимое в терминах модельного уровня, чтобы верхние уровни могли решить, следует ли повторить попытку или завершиться неудачно.
источник
Как правило, вы должны ловить только определенные исключения (например, IOException), и только если у вас есть что-то конкретное, что нужно сделать после того, как вы поймали исключение.
В противном случае лучше всего позволить пузырям исключения всплыть на поверхность, чтобы их можно было разоблачить и разобраться с ними. Некоторые люди называют это безотказным.
У вас должен быть какой-то обработчик в корне вашего приложения, чтобы перехватывать необработанные исключения, которые всплывают снизу. Это дает вам возможность представить, сообщить или управлять Исключением подходящим способом.
Упаковка исключений полезна, когда вам нужно создать исключение в распределенной системе, а у клиента нет определения ошибки на стороне сервера.
источник
Представьте, что вы пишете класс стека. Вы не помещаете в класс никакого кода обработки исключений, в результате он может создать следующие исключения.
Упрощенный подход к переносу исключений может решить включить оба этих исключения в класс исключений StackError. Тем не менее, это действительно упускает смысл упаковки исключений. Если объект выдает исключение низкого уровня, это должно означать, что объект сломан. Однако есть один случай, когда это приемлемо: когда объект фактически сломан.
Смысл обертывания исключений заключается в том, что объект должен давать правильные исключения для обычных ошибок. Стек должен вызывать StackEmpty, а не ArrayIndexError при извлечении из пустого стека. Намерение не состоит в том, чтобы не вызывать другие исключения, если объект или код поврежден.
Чего мы действительно хотим избежать, так это перехватывать низкоуровневые исключения, которые были переданы через высокоуровневые объекты. Класс стека, который выбрасывает ArrayIndexError при извлечении из пустого стека, является незначительной проблемой. Если вы на самом деле поймаете ArrayIndexError, у нас возникнет серьезная проблема. Распространение ошибок низкого уровня - гораздо менее серьезный грех, чем их выявление.
Вернемся к вашему примеру SQLException: почему вы получаете SQLException? Одна из причин в том, что вы передаете недопустимые запросы. Однако, если ваш уровень доступа к данным генерирует неверные запросы, он поврежден. Он не должен пытаться переразметить свою поломку в исключении DataAccessFailure.
Однако исключение SQLException также может возникнуть из-за потери соединения с базой данных. Моя стратегия заключается в том, чтобы перехватить исключение на последней линии защиты, сообщить пользователю, что соединение с базой данных было потеряно, и отключиться. Так как приложение имеет потерянный доступ к базе данных, на самом деле сделать намного больше нечего.
Я не знаю, как выглядит твой код. Но, похоже, вы слепо переводите все исключения в исключения более высокого уровня. Вы должны делать это только в относительно небольшом количестве случаев. Большинство исключений нижнего уровня указывают на ошибки в вашем коде. Ловить и перематывать их контрпродуктивно.
источник