Это плохая практика ловить Throwable? - PullRequest
93 голосов
/ 21 мая 2011

Это плохая практика ловить Throwable?

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

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

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

Ответы [ 14 ]

88 голосов
/ 21 мая 2011

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

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

33 голосов
/ 21 мая 2011

Это плохая идея.На самом деле, даже поймать Exception обычно плохая идея.Давайте рассмотрим пример:

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

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

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

У вас есть три варианта получше:

1 - точно поймать исключение (s) вы знаете, как обрабатывать:

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);
 }
19 голосов
/ 16 апреля 2013

Также помните, что когда вы ловите Throwable, вы также можете поймать InterruptedException, что требует особой обработки. Подробнее см. Работа с InterruptedException .

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

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

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

13 голосов
/ 13 февраля 2014

прямо из javadoc класса Error (который рекомендует не ловить их):

 * An <code>Error</code> is a subclass of <code>Throwable</code> 
 * that indicates serious problems that a reasonable application 
 * should not try to catch. Most such errors are abnormal conditions. 
 * The <code>ThreadDeath</code> error, though a "normal" condition,
 * is also a subclass of <code>Error</code> because most applications
 * should not try to catch it. 

 * A method is not required to declare in its <code>throws</code> 
 * clause any subclasses of <code>Error</code> 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
13 голосов
/ 21 мая 2011

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

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

9 голосов
/ 22 мая 2011

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

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

5 голосов
/ 13 декабря 2015

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

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

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

}

В качестве другого примера рассмотрим, есть ли у вас класс обслуживания, который обслуживает перевод средств. Этот метод возвращает 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

5 голосов
/ 22 мая 2011

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

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

5 голосов
/ 21 мая 2011

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

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

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

3 голосов
/ 22 мая 2018

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

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

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

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

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

Но, как правило, ловить Throwable, потому что у вас нет причины и вам лень видеть, какие конкретные исключения выдают, является плохой формой и плохой идеей.

...