Вопрос

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

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

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

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

Это было полезно?

Решение

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

Кроме того, Throwable href="http://download.orcle.com/javase/6/docs/api/java/lang/ermor.html" Rel="noreferrer"> Error также и это Обычно нет точки возвращения .Вы не хотите ловить / обращаться с этим, вы хотите, чтобы ваша программа умереть сразу, чтобы вы могли исправить его правильно.

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

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

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

Теперь предположим, что getUserInput() блокируется на некоторое время, а другой поток останавливает ваш поток наихудшим из возможных способов (он вызывает thread.stop()).Ваш блок catch поймает 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, вы также можете поймать InterruptedException который требует особого отношения.Видишь Работа с InterruptedException для получения более подробной информации.

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

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

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

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

 * 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
.

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

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

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

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

Может быть базовым классом для всех классов, чем можно бросить (не только исключения).Здесь мало что можно сделать, если вы поймаете OutofMemoryError или KernelError (см. Когда поймать Java.Lang.Error? )

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Пример.

    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)

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

Хотя перехват 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
    }
}

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top