Действительно ли исключения для исключительных ошибок?

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

Однако Кшиштоф Цвалина говорит:

Одно из самых больших заблуждений относительно исключений заключается в том, что они предназначены для "исключительных условий". Реальность такова, что они предназначены для сообщения об ошибках. С точки зрения каркасного дизайна нет такой вещи, как "исключительное условие". Независимо от того, является ли условие исключительным или не зависит от контекста использования, --- но библиотеки многократного использования редко знают, как они будут использоваться. Например, исключение OutOfMemoryException может быть исключительным для простого приложения ввода данных; его не столь исключительным для приложений, выполняющих собственное управление памятью (например, SQL-сервер). Другими словами, одно исключительное состояние - это еще одно хроническое состояние.

Далее он также говорит, что исключения должны использоваться для:

  • Ошибки использования
  • Ошибки программы
  • Системные сбои

Учитывая, что Кшиштоф Квалина является премьер-министром для команды CLR в MS, я спрашиваю: что вы думаете о его заявлении?

Ответ 1

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

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

  • NotImplementedException - очень подходящий способ обозначить, что конкретный метод или функция недоступны, а не просто возвращаются, не делая что-нибудь.
  • OutOfMemory исключения - трудно представить себе лучший способ справиться с этим тип ошибки, поскольку он представляет собой распределение по всей области или общей памяти OS отказ. Это необходимо для решения, конечно!
  • NullPointerException. Доступ к пустой переменной - ошибка программиста, а IMO это еще одно хорошее место, чтобы заставить ошибку пузыриться на поверхности.
  • ArrayIndexException. На неустойчивом языке, таком как C, переполнение буфера являются катастрофическими. Более нищие языки могут возвращать нулевое значение некоторого типа или в некоторые реализации, даже обертывание массива. На мой взгляд, бросая исключение - гораздо более элегантный ответ.

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

Ответ 2

Для людей, которые пишут рамки, возможно, это интересно.

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

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

Пример. Не используйте исключения для проверки ввода пользователя. Люди все время вводят ошибки ввода. Это не исключительная причина, почему мы пишем программное обеспечение. Для чего нужны утверждения if.

Когда ваше приложение получает исключение OutOfMemory, нет смысла его ловить. Это исключительное. Понятие "последовательное выполнение" выходит из окна. Ваше приложение обречено, просто потерпите крах и надеемся, что ваша транзакция RDBMS закончится до того, как вы потерпите крах.

Ответ 3

Действительно трудно понять, что именно истолковывает "исключительное условие", гарантирующее использование исключения в программе.

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

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

Чтобы дать конкретный пример, скажем, у нас есть метод getHeader(File f), который читает некоторый заголовок из файла и возвращает объект FileHeader.

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

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

(Или, альтернативно, у нас могут быть константы класса для объектов FileHeader, которые указывают условия FileNotFound и такие, имитирующие коды ошибок, но на самом деле у них есть булевский тип с TRUE, FALSE, FILE_NOT_FOUND.)

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

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

Однако это не означает, что все должно обрабатываться исключениями. Как указано S.Lott:

Не используйте исключения для проверки пользователя вход, например. Люди делают ошибки все время. То, что if-statements для.

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

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

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

Немного сложно решить, что является исключительным, а что нет.

Ответ 4

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

Например, "pythonic" способ проверить, содержит ли строка целое число, чтобы попробовать int (theString) и посмотреть, вызывает ли это исключение. Это "исключительная ошибка"?

Опять же, в Python цикл for всегда считается действующим на итераторе, и итератор должен вызывать исключение "StopIteration", когда он заканчивает свое задание (цикл for улавливает это исключение). Является ли это "исключительным" любым способом?

Ответ 5

Я думаю, что ближе к земле вы являетесь менее подходящими исключениями, как средство коммуникации с ошибкой. При более высокой абстракции, такой как Java или .net, исключение может сделать элегантный способ передавать сообщения об ошибках вашим абонентам. Это, однако, не относится к C. Это также конструктивное решение рамки vs api.

Ответ 6

Если вы практикуете "рассказывать, не спрашивайте", то исключение - это только то, как программа говорит "Я не могу этого сделать". Это "исключительный", поскольку вы говорите "делать X", и он не может делать X. Простая ситуация обработки ошибок. На некоторых языках это обычное дело, так как в Java и С++ люди имеют другие мнения, потому что исключения становятся довольно дорогостоящими.

Общее: исключение означает "Я не могу"

Pragmatic:... если вы можете позволить себе так работать на своем языке.

Гражданство:... и ваша команда позволяет это.

Ответ 8

Я сам об этом думал. Что мы подразумеваем под "исключительным"? Может быть, нет строгого определения, но существуют ли какие-либо эмпирические правила, которые мы можем использовать, чтобы решить, что является исключительным в данном контексте?

Например, было бы справедливым сказать, что "исключительным" является условие, которое нарушает договор функции?

Ответ 9

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

Во-первых, они создают объект для инкапсуляции исключения, который по определению должен сделать его намного дороже обработки простого оператора if. В качестве примера Java вы должны вызывать File.exists(), а не регулярно ожидать и обрабатывать исключение FileNotFoundException.

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

Сказав это, я лично обожаю исключения. Они освобождают вас от необходимости явной обработки всех этих ошибок, которые могут произойти, но, возможно, никогда не будут печататься, что приведет к повторной записи print-an-error-and-abort-on-non-zero-return- обработка кода каждого вызова метода.

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

Ответ 10

У К. Квалины есть точка. Будет полезно идентифицировать случаи, когда код будет терпеть неудачу (до предела)

Я согласен с С.Лоттом, что иногда проверка правильности лучше, чем бросание Исключения. Сказав это, OutOfMemory - это не то, что вы можете ожидать в своем приложении (если только он не выделяет большую память и не нуждается в памяти для продолжения).

Я думаю, это зависит от области приложения.

Ответ 11

Заявление Кшиштофа Квалины мало вводит в заблуждение. Исходное выражение относится к "исключительным условиям", для меня естественно, что я тот, кто определяет, что является исключительным или нет. Тем не менее, я думаю, что сообщение прошло через ОК, так как я думаю, что мы все говорим об исключениях разработчика.

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

Хорошим примером иерархии является spring иерархия исключений доступа к данным.

Ответ 12

Я думаю, что он прав. Взгляните на парсинг чисел в java. Вы не можете даже проверить строку ввода перед разбором. Вы вынуждены разбирать и извлекать NFE, если что-то пошло не так. Является ли синтаксическая ошибка чем-то исключительным? Думаю, нет.

Ответ 13

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

Проблема заключается в определении "исключительного". Вот мой:

Условие является исключительным, если оно вне предполагаемого нормального поведение части системы, которая вызывает исключение.

Это имеет некоторые последствия:

  • Исключительный зависит от ваших предположений. Если функция предполагает, что она передала действительные параметры, то бросание исключения IllegalArgumentException в порядке. Однако, если контракт функции говорит, что он каким-то образом исправит входные ошибки в входе, то это использование является "нормальным" и не должно генерировать исключение при ошибке ввода.
  • Исключительный зависит от уровня подсистемы. Функция сетевого ввода-вывода, безусловно, может вызвать исключение, если сеть разорвана, так как предполагает допустимое соединение. Однако ожидается, что брокер сообщений на основе ESB будет обрабатывать сброшенные соединения, поэтому, если он будет использовать такую ​​сетевую функцию ввода-вывода внутри, тогда ей необходимо будет правильно поймать и обработать ошибку. В случае, если это не очевидно, try/catch фактически эквивалентен подсистеме, говорящей, что "условие, которое является исключительным для одного из моих компонентов, на самом деле считается нормальным для меня, поэтому мне нужно его обработать".

Ответ 14

Утверждение, что исключения должны использоваться для исключительных обстоятельств, используется в "Эффективном Java Second Edition": одна из лучших java-книг.

Беда в том, что это исключено из контекста. Когда автор утверждает, что исключения должны быть исключительными, он только что показал пример использования исключений для завершения цикла while - плохого использования исключений. Цитировать:

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

Итак, все зависит от вашего определения "условие исключения". Из контекста вы можете подразумевать, что его очень редко можно использовать.

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

Проверено исключение - незначительные ошибки, которые не являются ошибками, и не должны останавливать выполнение. ех. IO или синтаксический анализ файла Непроверенное исключение - программирование "ошибка", нарушающее контракт метода - например. OutOfBoundsException. ИЛИ ошибка, которая делает продолжение выполнения очень плохой идеей - ex IO или синтаксический анализ файла очень важного файла. Возможно, файл конфигурации.

Ответ 15

В чем дело, какой инструмент нужен для выполнения этой работы.

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

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

Возникает ли неперехваченное исключение?

Будет ли исключение зависеть от обработки глобальных ошибок?

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

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

Если у меня есть метод, мне все равно, что вне этого метода. Мне все равно, что такое вход, как его обрабатывать и как вернуть ответ.

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

Теперь, если вы заботитесь о том, как обращаться с ошибкой, вы сделаете еще несколько размышлений и построите это в интерфейсе метода, например. если вы пытаетесь найти какой-либо объект, возможно, верните значение по умолчанию этого объекта, если его нельзя найти, а не выбросить какое-то исключение, например "Объект не найден".

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

Позвольте мне привести пример моей обработки ошибок для веб-службы.

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

Уровень 2. Метод веб-сервиса - завернутый в try/catch, чтобы гарантировать, что он всегда будет соответствовать его интерфейсу json.

Уровень 3. Методы работы - они получают данные, обрабатывают их и возвращают их в метод веб-службы.

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

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

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

Слишком часто я вижу, как try/catch ловит все в середине приложения, потому что разработчик испугался, что метод, который они используют, более сложный, чем кажется.

Ответ 16

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

Поэтому, чтобы ответить на ваш вопрос, нет. Исключения - для разрушительных событий, которые могут быть или не быть исключительными. Мне нравится это определение, оно простое и работает каждый раз - если вы покупаете исключения, как я. Например, пользователь отправляет неверный un/pw или у вас есть незаконный аргумент/неправильный ввод пользователя. Выброс исключения здесь является самым простым способом решения этих проблем, которые являются разрушительными, но не исключительными или даже непредвиденными.

Вероятно, их должны были называть перебоями, но эта лодка отплыла.