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

Нехорошая практика ловить Throwable?

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

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

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

Ответ 1

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

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

Ответ 2

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

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

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

Аналогичная проблема возникает с catching 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);
 }

Ответ 3

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

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

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

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

Ответ 4

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

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

Ответ 5

прямо из 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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

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

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

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

Ответ 9

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

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

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);
}

Но что произойдет, если произойдет исключение any? Вы не должны останавливаться, поскольку одна передача может быть успешной, а другая - нет, вы должны продолжать использовать всех пользователей 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

Ответ 10

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

Ответ 11

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

Пример.

    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)

Ответ 12

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

Ответ 13

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

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

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

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

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

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

Ответ 14

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

  • Вы хотите закрыть приложение в ответ на ошибки, особенно AssertionError что в противном случае будет безвредным.
  • Вы реализуете механизм объединения потоков, подобный ExecutorService.submit(), который требует от вас пересылки исключений обратно пользователю, чтобы они могли его обрабатывать.