Если вы пишете код, похожий на фреймворк (загрузка сторонних классов), было бы разумно поймать LinkageError(определение класса не найдено, неудовлетворенная ссылка, несовместимое изменение класса).
Я также видел несколько глупых сторонних кодов, генерирующих подклассы Error, так что вам тоже придется справиться с ними.
Кстати, я не уверен, что от этого невозможно вылечиться OutOfMemoryError.
То, что я должен был сделать, чтобы загрузить библиотеки DLL, не удалось бы, если бы они были неправильно настроены. Не является фатальной ошибкой для этого приложения.
Марио Ортегон,
7
Иногда имеет смысл перехватить OutOfMemoryError - например, когда вы создаете большие списки массивов.
SpaceTrucker
3
@SpaceTrucker: хорошо ли этот подход работает в многопоточных приложениях, или существует значительный риск того, что из-за этого не удастся выделить меньшее количество ресурсов в других потоках? … Предположительно только в том случае, если ваши массивы были достаточно малы, чтобы их можно было разместить, но ничего не оставляли для кого-либо.
PJTraill
@PJTraill Я не уверен в этом. Это потребует некоторых реальных статистических выборок. Я думал, что видел такой код, но не могу вспомнить, где он был.
SpaceTrucker,
51
Никогда. Никогда нельзя быть уверенным, что приложение сможет выполнить следующую строку кода. Если вы его получите OutOfMemoryError, у вас нет гарантии, что вы сможете сделать что-либо надежно . Поймать RuntimeException и проверить исключения, но не ошибки.
Никогда не говори никогда. у нас есть тестовый код, который делает «assert false»; затем перехватывает AssertionError, чтобы убедиться, что установлен флаг -ea. Кроме этого ... да, вероятно, никогда ;-)
Outlaw Programmer
3
Как насчет серверного приложения, которое передает запросы рабочим потокам. Может быть, нет смысла перехватывать Throwable в рабочем потоке, чтобы перехватить любые ошибки, и хотя бы попытаться записать, что пошло не так?
Ли
11
Никогда ... кроме случаев, когда это абсолютно необходимо. Никогда - сильное слово, и всегда есть исключения из правил. Если вы создаете фреймворк, не так уж и маловероятно, что вам придется вылавливать и обрабатывать определенные ошибки, даже если это просто регистрация.
Робин
Как насчет ошибок, например, NoSuchMethodError, которые возникают из-за методов сторонней библиотеки?
ha9u63ar
@OutlawProgrammer Для справки, есть и другие способы провести тот же тест:boolean assertionsEnabled = false; assert assertionsEnabled = true;
shmosel
16
Как правило, вы всегда должны ловить java.lang.Errorи записывать это в журнал или отображать его пользователю. Я работаю в службе поддержки и ежедневно вижу, что программисты не могут сказать, что произошло в программе.
Если у вас есть поток демона, вы должны предотвратить его завершение. В остальных случаях ваше приложение будет работать правильно.
Ловить надо только java.lang.Errorна высшем уровне.
Если вы посмотрите на список ошибок, вы увидите, что с большинством из них можно справиться. Например, ошибка ZipErrorвозникает при чтении поврежденных zip-файлов.
Наиболее частыми ошибками являются OutOfMemoryErrorи NoClassDefFoundError, которые в большинстве случаев являются проблемами во время выполнения.
Например:
int length =Integer.parseInt(xyz);byte[] buffer =newbyte[length];
может вызвать ошибку, OutOfMemoryErrorно это проблема времени выполнения, и нет причин для завершения вашей программы.
NoClassDefFoundErrorчаще всего возникают, если библиотеки нет или вы работаете с другой версией Java. Если это необязательная часть вашей программы, вам не следует прекращать ее.
Я могу привести еще много примеров того, почему лучше поймать Throwableна верхнем уровне и создать полезное сообщение об ошибке.
Я подозреваю, что в таких случаях лучше отказать демону с соответствующими предупреждениями, чем иметь возможность, что он останется живым как некий эфирный призрак на неудачной jvm, где он может дать ложный предлог, что он действительно жив и что-то делает
Эндрю Norman
OutOfMemoryErrorне является ошибкой во время выполнения, нет гарантии, что приложение сможет исправить ее. Если вам повезет, вы можете получить OOM, new byte[largeNumber]но если этого выделения было недостаточно, чтобы вызвать OOM, оно могло быть запущено в следующей строке или следующем потоке. Это проблема времени выполнения, потому что если lengthэто ненадежный ввод, он должен быть проверен перед вызовом new byte[].
Jeeyoung Kim
NoClassDefFoundErrorможет произойти где угодно , так как он вызывается, когда скомпилированный код Java не может найти класс. Если ваш JDK настроен неправильно, он может сработать при попытке использовать java.util.*класс, и практически невозможно программировать против него. Если вы дополнительно включаете зависимость, вы должны использовать ее, ClassLoaderчтобы проверить, существует ли она, что вызывает ClassNotFoundException.
Jeeyoung Kim
1
ZipErrorуказывает, что файл jar, содержащий классы, является поврежденным файлом zip. Это довольно серьезная проблема, и на данный момент вы не можете доверять никакому исполняемому коду, и было бы безответственно пытаться «оправиться» от него.
Jeeyoung Kim
2
В общем, может быть полезно поймать java.lang.Errorили java.lang.Throwableна верхнем уровне и попытаться что-то с ним сделать - например, записать сообщение об ошибке. Но на этом этапе нет гарантии, что это будет выполнено. Если ваша JVM работает с OOM, попытка регистрации может выделить больше Strings, что вызовет другой OOM.
Jeeyoung Kim
15
В многопоточной среде его чаще всего хочется поймать! Когда вы поймаете это, зарегистрируйте его и завершите работу всего приложения! Если вы этого не сделаете, какой-то поток, который может выполнять какую-то важную часть, будет мертв, а остальная часть приложения будет думать, что все в порядке. Из-за этого может случиться много нежелательных ситуаций. Одна из самых маленьких проблем заключается в том, что вы не сможете легко найти корень проблемы, если другие потоки начнут генерировать некоторые исключения из-за того, что один поток не работает.
Даже в некоторых случаях вам нужно обрабатывать разные ошибки по-разному, например, в OutOfMemoryError вы сможете регулярно закрывать приложение (даже, возможно, освободить некоторую память и продолжить), в некоторых других вы мало что можете сделать.
вызывающая система, выход при перехвате throwable имеет непреднамеренное последствие уничтожения всего, что работает на JVM, а не только рассматриваемого приложения. Обычно это не является хорошей практикой для веб-приложений, которые могут размещаться на сервере приложений с другими веб-приложениями (не говоря уже о том, что это повлияет на сам сервер приложений).
Эндрю Норман
9
Очень редко.
Я бы сказал только на верхнем уровне потока, чтобы ПОПЫТАТЬСЯ выдать сообщение с причиной смерти потока.
Если вы работаете во фреймворке, который делает это за вас, оставьте это фреймворку.
Почти никогда. Ошибки представляют собой проблемы, с которыми приложения обычно ничего не могут поделать. Единственным исключением может быть обработка представления ошибки, но даже это может пойти не так, как планировалось, в зависимости от ошибки.
Это Errorподкласс, Throwable
который указывает на серьезные проблемы, которые разумное приложение не должно пытаться уловить. Большинство таких ошибок являются ненормальными. [...]
От метода не требуется объявлять в своем предложении throws какие-либо подклассы Error, которые могут быть сгенерированы во время выполнения метода, но не обнаружены, поскольку эти ошибки являются ненормальными условиями, которые никогда не должны возникать.
Как упоминается в спецификации, выдается Errorтолько в тех случаях, когда есть вероятность, что когда возникает Errorошибка, приложение может сделать очень мало, а в некоторых случаях сама виртуальная машина Java может находиться в нестабильном состоянии (например, VirtualMachineError)
Хотя an Errorявляется подклассом, Throwableчто означает, что он может быть перехвачен try-catchпредложением, но, вероятно, в этом нет необходимости, поскольку приложение будет в ненормальном состоянии, когда ErrorJVM сгенерирует его.
Если вы достаточно сумасшедшие, чтобы создавать новую среду модульного тестирования, вашему исполнителю тестов, вероятно, потребуется отловить java.lang.AssertionError, выдаваемый любыми тестовыми примерами.
И есть пара других случаев, когда, если вы поймаете ошибку, вам придется ее повторно выбросить . Например, ThreadDeath никогда не следует ловить, это может вызвать большую проблему, если вы поймаете его в изолированной среде (например, на сервере приложений):
Приложение должно перехватывать экземпляры этого класса только в том случае, если оно должно очистить после асинхронного завершения. Если ThreadDeath перехватывается методом, важно, чтобы он был запущен повторно, чтобы поток действительно умер.
На самом деле это не проблема, потому что вы просто не улавливаете Errors.
Bombe,
4
Очень-очень редко.
Я сделал это только для одного очень известного случая. Например, java.lang.UnsatisfiedLinkError может быть сгенерирован, если два независимых ClassLoader загружают одну и ту же DLL. (Я согласен с тем, что мне следует переместить JAR в общий загрузчик классов)
Но наиболее распространенный случай - вам необходимо вести журнал, чтобы знать, что произошло, когда пользователь пришел с жалобой. Вам нужно сообщение или всплывающее окно для пользователя, а не молчание.
Даже программист на C / C ++ выдает сообщение об ошибке и сообщает что-то, чего люди не понимают, прежде чем она завершится (например, сбой памяти).
В приложении для Android я обнаруживаю ошибку java.lang.VerifyError . Библиотека, которую я использую, не будет работать на устройствах со старой версией ОС, и код библиотеки выдаст такую ошибку. Конечно, я мог бы избежать ошибки, проверив версию ОС во время выполнения, но:
Самый старый поддерживаемый SDK может измениться в будущем для конкретной библиотеки.
Блок ошибки try-catch является частью более крупного механизма отката. Некоторые конкретные устройства, хотя они должны поддерживать библиотеку, выдают исключения. Я ловлю VerifyError и все исключения, чтобы использовать запасное решение.
В идеале мы не должны обрабатывать / отлавливать ошибки. Но могут быть случаи, когда нам нужно это сделать, исходя из требований фреймворка или приложения. Скажем, у меня есть демон XML Parser, который реализует DOM Parser, который потребляет больше памяти. Если есть такое требование, как поток парсера , он не должен завершаться , когда он получает OutOfMemoryError , вместо этого он должен обработать его и отправить сообщение / письмо администратору приложения / фреймворка.
в идеале мы никогда не должны обнаруживать ошибку в нашем приложении Java, поскольку это ненормальное состояние. Приложение будет в ненормальном состоянии и может привести к повреждению или выдаче серьезно неправильного результата.
Было бы уместно отловить ошибку в модульных тестах, которые проверяют, сделано ли утверждение. Если кто-то отключает утверждения или иным образом удаляет утверждение, вы хотели бы знать
Возникает ошибка, когда JVM больше не работает должным образом или находится на грани. Если вы поймаете ошибку, нет гарантии, что блок catch будет работать, и тем более, что он будет работать до конца.
Это также будет зависеть от работающего компьютера, текущего состояния памяти, поэтому нет возможности проверить, попытаться сделать все возможное. У вас будет только печальный результат.
Ответы:
Как правило, никогда.
Однако иногда нужно отловить конкретные ошибки.
Если вы пишете код, похожий на фреймворк (загрузка сторонних классов), было бы разумно поймать
LinkageError
(определение класса не найдено, неудовлетворенная ссылка, несовместимое изменение класса).Я также видел несколько глупых сторонних кодов, генерирующих подклассы
Error
, так что вам тоже придется справиться с ними.Кстати, я не уверен, что от этого невозможно вылечиться
OutOfMemoryError
.источник
Никогда. Никогда нельзя быть уверенным, что приложение сможет выполнить следующую строку кода. Если вы его получите
OutOfMemoryError
, у вас нет гарантии, что вы сможете сделать что-либо надежно . Поймать RuntimeException и проверить исключения, но не ошибки.http://pmd.sourceforge.net/rules/strictexception.html
источник
boolean assertionsEnabled = false; assert assertionsEnabled = true;
Как правило, вы всегда должны ловить
java.lang.Error
и записывать это в журнал или отображать его пользователю. Я работаю в службе поддержки и ежедневно вижу, что программисты не могут сказать, что произошло в программе.Если у вас есть поток демона, вы должны предотвратить его завершение. В остальных случаях ваше приложение будет работать правильно.
Ловить надо только
java.lang.Error
на высшем уровне.Если вы посмотрите на список ошибок, вы увидите, что с большинством из них можно справиться. Например, ошибка
ZipError
возникает при чтении поврежденных zip-файлов.Наиболее частыми ошибками являются
OutOfMemoryError
иNoClassDefFoundError
, которые в большинстве случаев являются проблемами во время выполнения.Например:
может вызвать ошибку,
OutOfMemoryError
но это проблема времени выполнения, и нет причин для завершения вашей программы.NoClassDefFoundError
чаще всего возникают, если библиотеки нет или вы работаете с другой версией Java. Если это необязательная часть вашей программы, вам не следует прекращать ее.Я могу привести еще много примеров того, почему лучше поймать
Throwable
на верхнем уровне и создать полезное сообщение об ошибке.источник
OutOfMemoryError
не является ошибкой во время выполнения, нет гарантии, что приложение сможет исправить ее. Если вам повезет, вы можете получить OOM,new byte[largeNumber]
но если этого выделения было недостаточно, чтобы вызвать OOM, оно могло быть запущено в следующей строке или следующем потоке. Это проблема времени выполнения, потому что еслиlength
это ненадежный ввод, он должен быть проверен перед вызовомnew byte[]
.NoClassDefFoundError
может произойти где угодно , так как он вызывается, когда скомпилированный код Java не может найти класс. Если ваш JDK настроен неправильно, он может сработать при попытке использоватьjava.util.*
класс, и практически невозможно программировать против него. Если вы дополнительно включаете зависимость, вы должны использовать ее,ClassLoader
чтобы проверить, существует ли она, что вызываетClassNotFoundException
.ZipError
указывает, что файл jar, содержащий классы, является поврежденным файлом zip. Это довольно серьезная проблема, и на данный момент вы не можете доверять никакому исполняемому коду, и было бы безответственно пытаться «оправиться» от него.java.lang.Error
илиjava.lang.Throwable
на верхнем уровне и попытаться что-то с ним сделать - например, записать сообщение об ошибке. Но на этом этапе нет гарантии, что это будет выполнено. Если ваша JVM работает с OOM, попытка регистрации может выделить большеString
s, что вызовет другой OOM.В многопоточной среде его чаще всего хочется поймать! Когда вы поймаете это, зарегистрируйте его и завершите работу всего приложения! Если вы этого не сделаете, какой-то поток, который может выполнять какую-то важную часть, будет мертв, а остальная часть приложения будет думать, что все в порядке. Из-за этого может случиться много нежелательных ситуаций. Одна из самых маленьких проблем заключается в том, что вы не сможете легко найти корень проблемы, если другие потоки начнут генерировать некоторые исключения из-за того, что один поток не работает.
Например, обычно цикл должен быть:
Даже в некоторых случаях вам нужно обрабатывать разные ошибки по-разному, например, в OutOfMemoryError вы сможете регулярно закрывать приложение (даже, возможно, освободить некоторую память и продолжить), в некоторых других вы мало что можете сделать.
источник
OutOfMemoryError
и продолжить, вместо того, чтобы сразу же существовать, неразумно, потому что ваша программа тогда находится в неопределенном состоянии .Очень редко.
Я бы сказал только на верхнем уровне потока, чтобы ПОПЫТАТЬСЯ выдать сообщение с причиной смерти потока.
Если вы работаете во фреймворке, который делает это за вас, оставьте это фреймворку.
источник
Почти никогда. Ошибки представляют собой проблемы, с которыми приложения обычно ничего не могут поделать. Единственным исключением может быть обработка представления ошибки, но даже это может пойти не так, как планировалось, в зависимости от ошибки.
источник
Error
Обычно не должны быть пойманы , поскольку это указывает на ненормальное состояние , которое никогда не должно произойти .Из спецификации Java API для
Error
класса:Как упоминается в спецификации, выдается
Error
только в тех случаях, когда есть вероятность, что когда возникаетError
ошибка, приложение может сделать очень мало, а в некоторых случаях сама виртуальная машина Java может находиться в нестабильном состоянии (например,VirtualMachineError
)Хотя an
Error
является подклассом,Throwable
что означает, что он может быть перехваченtry-catch
предложением, но, вероятно, в этом нет необходимости, поскольку приложение будет в ненормальном состоянии, когдаError
JVM сгенерирует его.Там также краткий раздел по этой теме в разделе 11.5 Иерархия исключений из спецификации языка Java, 2nd Edition .
источник
Если вы достаточно сумасшедшие, чтобы создавать новую среду модульного тестирования, вашему исполнителю тестов, вероятно, потребуется отловить java.lang.AssertionError, выдаваемый любыми тестовыми примерами.
В противном случае смотрите другие ответы.
источник
И есть пара других случаев, когда, если вы поймаете ошибку, вам придется ее повторно выбросить . Например, ThreadDeath никогда не следует ловить, это может вызвать большую проблему, если вы поймаете его в изолированной среде (например, на сервере приложений):
источник
Error
s.Очень-очень редко.
Я сделал это только для одного очень известного случая. Например, java.lang.UnsatisfiedLinkError может быть сгенерирован, если два независимых ClassLoader загружают одну и ту же DLL. (Я согласен с тем, что мне следует переместить JAR в общий загрузчик классов)
Но наиболее распространенный случай - вам необходимо вести журнал, чтобы знать, что произошло, когда пользователь пришел с жалобой. Вам нужно сообщение или всплывающее окно для пользователя, а не молчание.
Даже программист на C / C ++ выдает сообщение об ошибке и сообщает что-то, чего люди не понимают, прежде чем она завершится (например, сбой памяти).
источник
В приложении для Android я обнаруживаю ошибку java.lang.VerifyError . Библиотека, которую я использую, не будет работать на устройствах со старой версией ОС, и код библиотеки выдаст такую ошибку. Конечно, я мог бы избежать ошибки, проверив версию ОС во время выполнения, но:
источник
довольно удобно поймать java.lang.AssertionError в тестовой среде ...
источник
В идеале мы не должны обрабатывать / отлавливать ошибки. Но могут быть случаи, когда нам нужно это сделать, исходя из требований фреймворка или приложения. Скажем, у меня есть демон XML Parser, который реализует DOM Parser, который потребляет больше памяти. Если есть такое требование, как поток парсера , он не должен завершаться , когда он получает OutOfMemoryError , вместо этого он должен обработать его и отправить сообщение / письмо администратору приложения / фреймворка.
источник
в идеале мы никогда не должны обнаруживать ошибку в нашем приложении Java, поскольку это ненормальное состояние. Приложение будет в ненормальном состоянии и может привести к повреждению или выдаче серьезно неправильного результата.
источник
Было бы уместно отловить ошибку в модульных тестах, которые проверяют, сделано ли утверждение. Если кто-то отключает утверждения или иным образом удаляет утверждение, вы хотели бы знать
источник
Возникает ошибка, когда JVM больше не работает должным образом или находится на грани. Если вы поймаете ошибку, нет гарантии, что блок catch будет работать, и тем более, что он будет работать до конца.
Это также будет зависеть от работающего компьютера, текущего состояния памяти, поэтому нет возможности проверить, попытаться сделать все возможное. У вас будет только печальный результат.
Вы также понизите читабельность вашего кода.
источник