За прошедшие годы проверенные исключения Java получили плохую репутацию. Показательным признаком является то, что буквально это единственный язык в мире, который имеет их (даже не на других языках JVM, таких как Groovy и Scala). Известные библиотеки Java, такие как Spring и Hibernate, также не используют их.
Я лично нашел для них одно применение ( в бизнес-логике между слоями), но в остальном я довольно анти-проверенные исключения.
Есть ли другие способы использования, которые я не понимаю?
java
exceptions
errors
Брэд Купит
источник
источник
Ответы:
Прежде всего, как и любой другой парадигме программирования, вам нужно сделать это правильно, чтобы она работала хорошо.
Для меня преимущество проверенных исключений состоит в том, что авторы библиотеки времени выполнения Java УЖЕ решили для меня, какие общие проблемы я мог бы ожидать, чтобы иметь возможность обрабатывать в вызывающей точке (в отличие от верхнего уровня catch-print- print- блок) и как можно раньше подумайте, как справиться с этими проблемами.
Мне нравятся проверенные исключения, потому что они делают мой код более надежным, заставляя меня думать о восстановлении после ошибок как можно раньше.
Чтобы быть более точным, для меня это делает мой код более устойчивым, поскольку заставляет меня рассматривать странные угловые случаи очень рано в процессе, а не говорить «Ой, мой код не обрабатывает, если файл еще не существует» на основе ошибка в работе, которую вы должны затем переработать для обработки своего кода. Добавление обработки ошибок в существующий код может быть нетривиальной задачей - и, следовательно, дорогостоящим - при достижении обслуживания, а не просто делать это с самого начала.
Возможно, отсутствующий файл является фатальной вещью и должен привести к аварийному завершению работы программы, но затем вы принимаете это решение с
Это также показывает очень важный побочный эффект. Если вы заключили исключение, вы можете добавить объяснение, которое идет в трассировке стека ! Это настолько мощно, потому что вы можете добавить информацию, например, об имени файла, который отсутствовал, или параметрах, переданных этому методу, или другой диагностической информации, и эта информация присутствует прямо в трассировке стека, которая часто является единственной вещью, которую вы получить, когда программа потерпела крах.
Люди могут сказать: «Мы можем просто запустить это в отладчике для воспроизведения», но я обнаружил, что очень часто производственные ошибки не могут быть воспроизведены позже, и мы не можем запускать отладчики в производстве, за исключением очень неприятных случаев, когда по существу ваша работа поставлена на карту.
Чем больше информации в вашей трассировке стека, тем лучше. Проверенные исключения помогают мне быстро получить эту информацию.
РЕДАКТИРОВАТЬ: Это касается и дизайнеров библиотеки. Одна библиотека, которую я использую ежедневно, содержит много, много проверенных исключений, которые могли бы быть разработаны намного лучше, делая их менее утомительными для использования.
источник
У вас есть два хороших ответа, которые объясняют, какие проверенные исключения стали на практике. (+1 к обоим.) Но было бы также полезно изучить то, для чего они были предназначены в теории, потому что намерение действительно стоит.
Проверенные исключения на самом деле предназначены для того, чтобы сделать язык более безопасным. Рассмотрим простой метод, такой как умножение целых чисел. Вы можете подумать, что тип результата этого метода будет целочисленным, но, строго говоря, результатом является целочисленное значение или исключение переполнения. Рассматривая целочисленный результат сам по себе как тип возвращаемого значения метода, не выражается полный диапазон функции.
В этом свете не совсем верно утверждать, что проверенные исключения не нашли свое применение в других языках. Они просто не приняли форму, которую использует Java. В приложениях на Haskell обычно используют алгебраические типы данных, чтобы различать успешное и неудачное завершение функции. Хотя само по себе это не исключение, намерение во многом совпадает с проверенным исключением; это API, разработанный для того, чтобы заставить потребителя API обрабатывать как успешное в неудачном случае, например:
Это говорит программисту, что функция имеет два дополнительных возможных результата помимо успеха.
источник
IMO, проверенные исключения являются ошибочной реализацией того, что могло бы быть довольно приличной идеей (при совершенно других обстоятельствах - но на самом деле даже не является хорошей идеей в текущих обстоятельствах).
Хорошая идея заключается в том, что было бы неплохо, чтобы компилятор проверил, что все исключения, которые может вызвать программа, будут перехвачены. Недостаток реализации заключается в том, что для этого Java заставляет вас иметь дело с исключением непосредственно в любом классе, вызывающем все, что объявлено для создания проверенного исключения. Одна из самых основных идей (и преимуществ) обработки исключений состоит в том, что в случае ошибки она позволяет промежуточным уровням кода, которые не имеют ничего общего с конкретной ошибкой, полностью игнорировать ее существование. Проверенные исключения (как реализовано в Java) не позволяют этого, тем самым уничтожая главное (основное?) Преимущество обработки исключений для начала.
Теоретически, они могли бы сделать проверенные исключения полезными, применяя их только на уровне всей программы - то есть, «собирая» программу, строили дерево всех путей управления в программе. Различные узлы в дереве будут помечены 1) исключениями, которые они могут генерировать, и 2) исключениями, которые они могут перехватить. Чтобы убедиться, что программа верна, вы должны были пройтись по дереву и убедиться, что каждое исключение, которое было сгенерировано на любом уровне дерева, было перехвачено на каком-то более высоком уровне дерева.
Причина, по которой они этого не сделали (я полагаю, в любом случае), заключается в том, что это будет мучительно сложно - на самом деле, я сомневаюсь, что кто-то написал систему сборки, которая может сделать это для чего угодно, кроме очень простого (граничащего с игрушкой) ") языки / системы. Для Java такие вещи, как динамическая загрузка классов, делают это еще сложнее, чем во многих других случаях. Хуже того (в отличие от чего-то вроде C) Java (по крайней мере, обычно) не компилируется статически / не связана с исполняемым файлом. Это означает, что ничто в системе на самом деле не имеет глобальной осведомленности даже для того, чтобы пытаться выполнять такого рода принудительные меры, пока конечный пользователь фактически не начнет загружать программу для ее запуска.
Осуществление правоприменения в этот момент нецелесообразно по нескольким причинам. Во-первых, даже в лучшем случае это увеличит время запуска, что уже является одной из самых больших и распространенных жалоб на Java. Во-вторых, чтобы сделать много хорошего, вам действительно нужно обнаружить проблему достаточно рано, чтобы программист мог ее исправить. Когда пользователь загружает программу, уже слишком поздно делать что-то хорошее - в этот момент ваш единственный выбор - игнорировать проблему или вообще отказаться от загрузки / запуска программы, если есть вероятность, что возникнет исключение. это не было поймано.
Как таковые, проверенные исключения хуже, чем бесполезные, но альтернативные варианты проверенных исключений еще хуже. Хотя основная идея для проверенных исключений кажется хорошей, на самом деле она не очень хороша и оказывается особенно плохо подходящей для Java. Для чего-то вроде C ++, который обычно компилируется / связывается в законченный исполняемый файл без ничего похожего на рефлексию / динамическую загрузку классов, у вас будет немного больше шансов (хотя, откровенно говоря, даже тогда их правильное применение без того же беспорядка, который они в настоящее время причина в Java все еще вероятно была бы вне текущего уровня техники).
источник
UnexpectedException
тип, производный отRuntimeException
. Обратите внимание, что «бросает» и «не ожидает» не противоречат друг другу; еслиfoo
бросаетBozException
и звонитbar
, это не значит, что он ожидаетbar
броситьBozException
.Они действительно хороши для раздражающих программистов и поощрения проглатывания исключений. Половина исключений заключается в том, что у вас есть разумный способ обработки ошибок по умолчанию, и вам не нужно думать о явном распространении ошибок, которые вы не можете обработать. (Разумное значение по умолчанию таково, что если вы никогда не обрабатываете ошибку где-либо в своем коде, вы фактически утверждаете, что это не может произойти, и у вас остается нормальный выход и трассировка стека, если вы ошибаетесь.) Проверено исключение поражения это. Они чувствуют, что им приходится явно распространять ошибки в C.
источник
throws FileNotFoundException
. Исправление:catch (FileNotFoundException e) { throw RuntimeException(e); }
Я думаю, будет справедливо сказать, что проверенные исключения были чем-то вроде неудачного эксперимента. В чем они ошиблись, так это в том, что сломали слои:
Хорошее разделение заинтересованных сторон нарушено, потому что теперь знания об ошибках, которые могли быть ограничены A и C, теперь должны быть разбросаны по B.
Есть хорошее обсуждение проверенных исключений в Википедии.
И у Брюса Экеля тоже есть хорошая статья . Вот цитата:
Я полагаю, что в случае C ++, если все методы имеют предложение
throws
спецификации, вы можете иметь несколько хороших оптимизаций. Однако я не верю, что у Java могли бы быть эти преимущества, потому чтоRuntimeExceptions
они не проверены. Современный JIT в любом случае должен быть в состоянии оптимизировать код.Одна приятная особенность AspectJ - смягчение исключений: вы можете превратить отмеченные исключения в непроверенные исключения, в частности, для улучшения наложения.
Возможно, иронично, что Java прошла через все эти проблемы, когда могла бы проверить
null
вместо этого, что могло бы быть гораздо более ценным .источник
Я люблю исключения.
Я, однако, постоянно смущен их неправильным использованием.
Не используйте их для обработки потока. Вам не нужен код, который пытается что-то сделать и использует исключение в качестве триггера, чтобы сделать что-то еще, потому что исключения являются объектами, которые нужно создавать и использовать память и т. Д. И т. Д. Только потому, что вы не могли потрудиться написать некоторые вроде проверки if () перед тем, как позвонить. Это просто лень и дает славному Исключению дурную славу.
Не глотай их. Когда-либо. При любых обстоятельствах. В качестве абсолютного минимума вы добавляете что-то в файл журнала, чтобы указать, что произошло исключение. Попытка отследить код, который поглощает исключения, - это кошмар. Опять же, проклинаю вас, глотатели исключений, за то, что вы принесли им огромную репутацию!
Относитесь к Исключениям с вашей головной уборной. Создайте свои собственные объекты исключений с осмысленными иерархиями. Сложите свою бизнес-логику и свои исключения рука об руку. Раньше я обнаруживал, что если я начну в новой области системы, я обнаружу необходимость подкласса Exception в течение получаса после кодирования, поэтому в эти дни я начинаю с написания классов Exception.
Если вы пишете «каркасные» фрагменты кода, убедитесь, что все ваши начальные интерфейсы написаны так, чтобы создавать ваши собственные новые исключения, где это уместно ... и убедитесь, что у ваших кодеров есть некоторый пример кода в месте, что делать, когда их код выдает IOException, но интерфейс, для которого они пишут, хочет выдать «ReportingApplicationException».
Как только вы поймете, как заставить Исключения работать на вас, вы никогда не оглядываетесь назад.
источник
initCause
или инициализируйте исключение с исключением, которое вызвало его. Пример: у вас есть утилита ввода / вывода, которая нужна вам только в случае сбоя записи. Однако существует несколько причин, по которым запись может завершиться неудачно (не удалось получить доступ, ошибка записи и т. Д.). Создайте свое собственное исключение с причиной 1, чтобы исходная проблема не была проглочена.Проверенные исключения есть и в ADA.
(Внимание, этот пост содержит твердо убежденные взгляды, с которыми вы можете столкнуться.)
Программисты не любят их и жалуются или пишут исключения, проглатывая код.
Проверенные исключения существуют, потому что вещи могут не только не работать, вы можете выполнить анализ режима отказа / эффектов и определить это заранее.
Чтение файла может завершиться ошибкой. Вызовы RPC могут быть неудачными. Сетевой ввод-вывод может дать сбой. Данные могут быть неправильно отформатированы при разборе.
«Счастливый путь» для кода прост.
Я знал парня в университете, который мог бы написать отличный код «счастливого пути». Ни один из крайних случаев никогда не работал. В эти дни он делает Python для компании с открытым исходным кодом. Достаточно.
Если вы не хотите обрабатывать проверенные исключения, то вы действительно говорите:
Поэтому проверенные исключения не понравятся программистам, потому что это означает больше работы.
Конечно, другие люди хотели бы, чтобы эта работа была выполнена.
Возможно, они хотели получить правильный ответ, даже если файловый сервер вышел из строя / флешка USB умерла.
В сообществе программистов странная вера в то, что вы должны использовать язык программирования, который делает вашу жизнь проще, чем вам нравится, когда ваша работа заключается в написании программного обеспечения. Ваша задача - решить чью-то проблему, не позволяя вам заниматься программной джазовой импровизацией.
Если вы программист-любитель (не программирование за деньги), не стесняйтесь программировать на C # или другом языке без проверенных исключений. Черт возьми, вырежьте посредника и запрограммируйте логотип. Вы можете нарисовать красивые рисунки на полу с черепахой.
источник
Проверенные исключения должны были побудить людей обрабатывать ошибки, близкие к их источнику. Чем дальше от источника, тем больше функций завершается в середине работы, и тем более вероятно, что система перешла в несогласованное состояние. Кроме того, более вероятно, что вы поймали неправильное исключение случайно.
К сожалению, люди склонны либо игнорировать исключения, либо добавлять постоянно увеличивающиеся спецификации бросков. Оба они упускают суть того, что проверенные исключения должны поощрять. Они похожи на преобразование процедурного кода для использования многих функций Getter и Setter, которые якобы делают его OO.
По сути, проверенные исключения пытаются доказать определенную степень правильности вашего кода. Это почти та же идея, что и статическая типизация, поскольку она пытается доказать, что некоторые вещи верны, еще до того, как код будет запущен. Проблема в том, что все это дополнительное доказательство требует усилий и стоит ли оно того?
источник