Это плохая практика, чтобы поймать Throwable?

Это плохая практика, чтобы поймать Throwable ?

Например, что-то вроде этого:

 try { // Some code } catch(Throwable e) { // handle the exception } 

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

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

Кроме того, Throwable покрывает Error а также, как правило, нет точки возврата . Вы не хотите ловить / обрабатывать это, вы хотите, чтобы ваша программа сразу умерла, чтобы вы могли исправить ее правильно.

Это плохая идея. На самом деле, даже catching Exception – обычно плохая идея. Рассмотрим пример:

 try { inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() ); } catch(Throwable e) { inputNumber = 10; //Default, user did not enter valid number } 

Теперь предположим, что getUserInput () блокирует некоторое время, а другой stream останавливает ваш stream наименее возможным способом (он вызывает thread.stop ()). Ваш блок catch ThreadDeath ошибку ThreadDeath . Это очень плохо. Поведение вашего кода после обнаружения этого исключения в основном не определено.

Аналогичная проблема возникает при выделении Exception. Возможно, getUserInput() неудачно из-за исключения InterruptException или исключения, отказавшего в доступе при попытке регистрации результатов или всех других сбоев. Вы не знаете, что пошло не так, потому что из-за этого вы также не знаете, как исправить эту проблему.

У вас есть три варианта:

1 – Поймать точно исключение (и), которым вы знаете, как обращаться:

 try { inputNumber = NumberFormat.getInstance().formatNumber( getUserInput() ); } catch(ParseException e) { inputNumber = 10; //Default, user did not enter valid number } 

2 – Повторите любое исключение, с которым вы столкнулись, и не знаете, как обращаться:

 try { doSomethingMysterious(); } catch(Exception e) { log.error("Oh man, something bad and mysterious happened",e); throw e; } 

3 – Используйте блок finally, поэтому вам не нужно помнить о том,

  Resources r = null; try { r = allocateSomeResources(); doSomething(r); } finally { if(r!=null) cleanUpResources(r); } 

Также имейте в Throwable , что когда вы поймаете Throwable , вы также можете поймать InterruptedException требующее специального лечения. Дополнительную информацию см. В разделе « Работа с InterruptedException» .

Если вы хотите только исключить исключенные исключения, вы можете также рассмотреть этот шаблон

 try { ... } catch (RuntimeException exception) { //do something } catch (Error error) { //do something } 

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

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

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

прямо из javadoc classа 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. * The ThreadDeath error, though a "normal" condition, * is also a subclass of Error because most applications * should not try to catch it. * 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. * * @author Frank Yellin * @version %I%, %G% * @see java.lang.ThreadDeath * @since JDK1.0 

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

Однако в этих обстоятельствах было бы лучше указать только конкретные ошибки, которые была выбрана библиотекой, а не все Throwables.

Throwable – базовый class для всех classов, чем может быть брошен (не только исключения). Мало что вы можете сделать, если вы поймаете OutOfMemoryError или KernelError (см. Когда нужно поймать java.lang.Error? )

ловли Исключения должны быть достаточными.

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

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

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

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

В веб-приложении, где вы должны показывать пользователю полную страницу ошибок. Этот код убедитесь, что это происходит, поскольку это большая try/catch вокруг всех ваших обработчиков запросов (сервлетов, действий расположений или любого controllerа …)

 try{ //run the code which handles user request. }catch(Throwable ex){ LOG.error("Exception was thrown: {}", ex); //redirect request to a error page. } 

}

В качестве другого примера рассмотрим, что у вас есть class обслуживания, который обслуживает бизнес по переводу средств. Этот метод возвращает TransferReceipt если передача выполнена или NULL если это невозможно.

 String FoundtransferService.doTransfer( fundtransferVO); 

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

 for(FundTransferVO fundTransferVO : fundTransferVOList){ FoundtransferService.doTransfer( foundtransferVO); } 

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

 for(FundTransferVO fundTransferVO : fundTransferVOList){ FoundtransferService.doTransfer( foundtransferVO); }catch(Throwable ex){ LOG.error("The transfer for {} failed due the error {}", foundtransferVO, ex); } } 

Вы можете просматривать множество проектов с открытым исходным кодом, чтобы увидеть, что throwable действительно кэшируются и обрабатываются. Например, вот поиск tomcat , struts2 и primefaces :

https://github.com/apache/tomcat/search?utf8=%E2%9C%93&q=catch%28Throwable https://github.com/apache/struts/search?utf8=%E2%9C%93&q=catch % 28Throwable https://github.com/primefaces/primefaces/search?utf8=%E2%9C%93&q=catch%28Throwable

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

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

 public Integer addNumbers(Integer a, Integer b) { Integer c = a + b; //This will throw a NullPointerException if either //a or b are set to a null value by the //calling method successfulAdditionAlert(c); return c; } private void successfulAdditionAlert(Integer c) { try { //Code here to read configurations and send email alerts. } catch (Throwable e) { //Code to log any exception that occurs during email dispatch } } 

Код для отправки уведомлений по электронной почте читает много системных конфигураций и, следовательно, может быть множество исключений, выведенных из этого блока кода. Но мы не хотим, чтобы какое-либо исключение, возникающее при отправке оповещения, распространялось на метод вызывающего, поскольку этот метод просто связан с суммой двух значений Integer, которые он предоставляет. Следовательно, код для отправки уведомлений по электронной почте помещается в блок try-catch , где Throwable улавливается, и все исключения записываются в журнал, позволяя остальной части streamа продолжать работу.

Если мы используем throwable , тогда он также охватывает Error, и все.

Пример.

  public class ExceptionTest { /** * @param args */ public static void m1() { int i = 10; int j = 0; try { int k = i / j; System.out.println(k); } catch (Throwable th) { th.printStackTrace(); } } public static void main(String[] args) { m1(); } 

}

Вывод:

 java.lang.ArithmeticException: / by zero at com.infy.test.ExceptionTest.m1(ExceptionTest.java:12) at com.infy.test.ExceptionTest.main(ExceptionTest.java:25) 

Throwable – суперclass всех ошибок и исключений. Если вы используете Throwable в предложении catch, он не только поймает все исключения, но и поймает все ошибки. Ошибки выдаются JVM, чтобы указать на серьезные проблемы, которые не предназначены для обработки приложением. Типичными примерами этого являются OutOfMemoryError или StackOverflowError. Оба они вызваны ситуациями, которые находятся вне контроля приложения и не могут быть обработаны. Поэтому вы не должны ловить Throwables, если вы не уверены, что это будет только исключение, находящееся внутри Throwable.

Вопрос немного расплывчатый; вы спрашиваете: «это нормально, чтобы поймать Throwable », или «нормально ли поймать Throwable и ничего не делать»? Многие люди здесь ответили на последнее, но это побочный вопрос; 99% времени вы не должны «потреблять» или отбрасывать исключение, будь вы Throwable или IOException или что-то еще.

Если вы распространяете исключение, ответ (например, ответ на столько вопросов) «зависит от этого». Это зависит от того, что вы делаете с исключением – почему вы его поймаете.

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

 try { … } catch(final Throwable throwable) { connection.rollback(); throw throwable; } 

Обратите внимание, что исключение не отбрасывается, а распространяется.

Но, как общая политика, ловить Throwable потому что у вас нет причины и слишком ленивы, чтобы увидеть, какие из них проходят, – это плохая форма и плохая идея.

Вообще говоря, вы хотите избежать ловушки Error но я могу придумать (по крайней мере) два конкретных случая, когда это уместно:

  • Вы хотите закрыть приложение в ответ на ошибки, особенно AssertionError что в противном случае будет безвредным.
  • Вы реализуете механизм объединения streamов, подобный ExecutorService.submit (), который требует от вас пересылки исключений обратно пользователю, чтобы они могли его обрабатывать.
  • Разница между использованием Throwable и Exception в попытке поймать
  • Как проверить, что исключение не выбрасывается?
  • Должны ли вы сообщать текст сообщений об исключениях?
  • Как поймать ВСЕ исключения / сбои в приложении .NET
  • Полезно ли использовать «goto» на языке, который поддерживает циклы и функции? Если да, то почему?
  • Блоки catch C ++ - исключение catch по значению или ссылке?
  • Зачем использовать в C #?
  • В чем разница между Application.ThreadException и AppDomain.CurrentDomain.UnhandledException?
  • Обработка исключений в запросах ajax JSF
  • Вы (действительно) пишете безопасный код исключения?
  • Исключение исключений нарушения доступа?
  • Давайте будем гением компьютера.