Когда ловить java.lang.Error?

В каких ситуациях нужно ловить java.lang.Error на приложении?

См. Также stackoverflow.com/questions/2679330/…

Raedwald 02.04.2016 17:41
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
117
1
152 752
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

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

Никогда. Никогда нельзя быть уверенным, что приложение сможет выполнить следующую строку кода. Если вы получаете OutOfMemoryError, у вас есть нет гарантии, что вы сможете что-либо сделать надежно. Поймать RuntimeException и проверить исключения, но не ошибки.

http://pmd.sourceforge.net/rules/strictexception.html

Никогда не говори никогда. у нас есть тестовый код, который делает «assert false»; затем перехватывает AssertionError, чтобы убедиться, что установлен флаг -ea. Кроме этого ... да, наверное, никогда ;-)

Outlaw Programmer 09.12.2008 17:52

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

Leigh 09.12.2008 19:11

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

Robin 09.12.2008 22:49

Как насчет ошибок, например NoSuchMethodError, который исходит из сторонних библиотечных методов?

ha9u63ar 15.01.2016 18:56

@OutlawProgrammer Для записи, есть и другие способы выполнить тот же тест: boolean assertionsEnabled = false; assert assertionsEnabled = true;

shmosel 09.02.2017 10:59

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

An application should catch instances of this class only if it must clean up after being terminated asynchronously. If ThreadDeath is caught by a method, it is important that it be rethrown so that the thread actually dies.

На самом деле это не проблема, потому что вы просто выполняете нет catch Errors.

Bombe 09.12.2008 17:37
Ответ принят как подходящий

В общем, никогда.

Однако иногда нужно отлавливать конкретные ошибки.

Если вы пишете фреймворк-код (загружаете сторонние классы), было бы разумно поймать LinkageError (определение класса не найдено, неудовлетворенная ссылка, несовместимое изменение класса).

Я также видел, как какой-то тупой сторонний код генерирует подклассы Error, так что вам придется справиться и с ними.

Кстати, я не уверен, что восстановление с OutOfMemoryError невозможно.

То, что я должен был сделать, чтобы загрузить библиотеки DLL, потерпит неудачу, если они не будут правильно настроены. Не является фатальной ошибкой для этого приложения.

Mario Ortegón 11.12.2008 13:11

Иногда имеет смысл поймать OutOfMemoryError - например, когда вы создаете большие списки массивов.

SpaceTrucker 14.03.2013 11:11

@SpaceTrucker: хорошо ли этот подход работает в многопоточных приложениях, или существует значительный риск того, что из-за этого не удастся выделить меньшее количество ресурсов в других потоках? … Предположительно только в том случае, если ваши массивы были достаточно малы, чтобы их можно было разместить, но ничего не оставляли для кого-либо.

PJTraill 11.06.2015 17:16

@PJTraill Я не уверен в этом. Это потребует некоторых реальных статистических выборок. Я думал, что видел такой код, но не могу вспомнить, где он был.

SpaceTrucker 13.06.2015 22:29

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

TwoThe 30.10.2020 13:49

Очень редко.

Я бы сказал, только на верхнем уровне потока, чтобы ПОПЫТАТЬСЯ выдать сообщение с причиной смерти потока.

Если вы работаете во фреймворке, который делает это за вас, оставьте это фреймворку.

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

Из спецификации Java API для класса Error:

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. [...]

A method is not required to declare in its throws clause any subclasses of Error that might be thrown during the execution of the method but not caught, since these errors are abnormal conditions that should never occur.

Как указано в спецификации, Error бросается только в тех случаях, когда Скорее всего, когда происходит Error, приложение мало что может сделать, и в некоторых обстоятельствах сама виртуальная машина Java может находиться в нестабильном состоянии (например, VirtualMachineError).

Хотя Error является подклассом Throwable, что означает, что он может быть перехвачен предложением try-catch, но, вероятно, в этом нет необходимости, поскольку приложение будет находиться в ненормальном состоянии, когда JVM выбрасывает Error.

Также есть небольшой раздел по этой теме в разделе 11.5 Иерархия исключений документа Спецификация языка Java, 2-е издание.

Очень-очень редко.

Я сделал это только для одного очень известного случая. Например, java.lang.UnsatisfiedLinkError может быть сгенерировано, если два независимость ClassLoader загружают одну и ту же DLL. (Я согласен с тем, что мне следует переместить JAR в общий загрузчик классов)

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

Даже программист на C / C++ выдает сообщение об ошибке и сообщает что-то, чего люди не понимают, прежде чем она завершится (например, сбой памяти).

Если вы достаточно сумасшедшие, чтобы создавать новую среду модульного тестирования, вашему исполнителю тестов, вероятно, потребуется отловить java.lang.AssertionError, выдаваемый любыми тестовыми примерами.

В противном случае смотрите другие ответы.

Как правило, вы всегда должны ловить java.lang.Error и записывать его в журнал или отображать его пользователю. Я работаю в службе поддержки и ежедневно вижу, что программисты не могут сказать, что произошло в программе.

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

Вы должны ловить java.lang.Error только на самом высоком уровне.

Если вы посмотрите на список ошибок, вы увидите, что с большинством из них можно справиться. Например, ZipError возникает при чтении поврежденных zip-файлов.

Наиболее частыми ошибками являются OutOfMemoryError и NoClassDefFoundError, которые в большинстве случаев являются проблемами во время выполнения.

Например:

int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];

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

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

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

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

Andrew Norman 28.01.2016 02:01
OutOfMemoryError не является ошибкой времени выполнения, и нет гарантии, что приложение сможет исправить это. Если вам повезет, вы можете получить OOM в new byte[largeNumber], но если этого выделения было недостаточно, чтобы вызвать OOM, он мог быть запущен в следующей строке или следующем потоке. Это проблема времени выполнения, потому что, если length является ненадежным вводом, он должен быть проверен перед вызовом new byte[].
Jeeyoung Kim 19.04.2016 21:39
NoClassDefFoundError может возникать как везде, поскольку он вызывается, когда скомпилированный код Java не может найти класс. Если ваш JDK настроен неправильно, он может сработать при попытке использовать класс java.util.*, и программировать против него практически невозможно. Если вы дополнительно включаете зависимость, вы должны использовать ClassLoader, чтобы проверить, существует ли она, что вызывает ClassNotFoundException.
Jeeyoung Kim 19.04.2016 21:41
ZipError указывает, что jar-файл, содержащий классы, является поврежденным zip-файлом. Это довольно серьезная проблема, и на данный момент вы не можете доверять никакому исполняемому коду, и было бы безответственно пытаться «оправиться» от него.
Jeeyoung Kim 19.04.2016 21:43

В общем, может быть полезно поймать java.lang.Error или java.lang.Throwable на верхнем уровне и попытаться что-то с ними сделать - например, записать сообщение об ошибке. Но на этом этапе нет гарантии, что это будет выполнено. Если ваша JVM работает с OOM, попытка регистрации может выделить больше String, что вызовет другой OOM.

Jeeyoung Kim 19.04.2016 21:45

Я тоже согласен, хотя перехват Error считается плохой практикой, но перехват на самом высоком уровне кажется логичным, когда вам советуют не показывать ЛЮБУЮ техническую трассировку стека в пользовательском интерфейсе, обращенном к клиенту, а только некоторые предопределенные сообщения. Проблема в том, что инструмент отслеживания ошибок PMD, Sonar и т. д. Продолжают вас оскорблять :(

supernova 02.08.2016 16:50

Я согласен, на высшем уровне всегда нужно ловить бросок и пробовать его распечатать. Если ваша система не работает или что-то, по крайней мере, вы пытались вывести ошибку. Вы ничего не получите, если не попытаетесь распечатать его. Независимо от ошибки.

Ludger 30.08.2019 14:13

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

Например, обычно цикл должен быть:

try {
   while (shouldRun()) {
       doSomething();
   }
}
catch (Throwable t) {
   log(t);
   stop();
   System.exit(1);
}

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

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

Raedwald 20.11.2015 12:20

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

Andrew Norman 28.01.2016 02:10

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

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

В приложении для Android я ловлю java.lang.VerifyError. Библиотека, которую я использую, не будет работать на устройствах со старой версией ОС, и код библиотеки выдаст такую ​​ошибку. Конечно, я мог бы избежать ошибки, проверив версию ОС во время выполнения, но:

  • Самый старый поддерживаемый SDK может измениться в будущем для конкретной библиотеки.
  • Блок ошибки try-catch является частью более крупного механизма отката. Некоторые конкретные устройства, хотя они должны поддерживать библиотеку, выдают исключения. Я ловлю VerifyError и все исключения, чтобы использовать запасное решение.

Ошибка возникает, когда JVM больше не работает должным образом или находится на грани отказа. Если вы поймаете ошибку, нет гарантии, что блок catch будет работать, и тем более что он будет работать до конца.

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

Вы также снизите удобочитаемость вашего кода.

очень удобно ловить java.lang.AssertionError в тестовой среде ...

Какую ценность вы пытаетесь добавить?

lpapp 27.11.2013 06:12

добавление значения набора тестов без прерывания

Jono 28.09.2017 12:53

В идеале мы не должны обрабатывать / отлавливать ошибки. Но могут быть случаи, когда нам нужно это сделать, исходя из требований фреймворка или приложения. Скажем, у меня есть демон XML Parser, который реализует Парсер DOM, который потребляет больше памяти. Если есть требование, например, поток парсера не должен умирать, когда он получает OutOfMemoryError, вместо этого он должен обработать его и отправить сообщение / письмо администратору приложения / фреймворка.

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