Почему не поймать исключение поймать RuntimeException?

это очень странно для меня. RuntimeException наследует от Exception, который наследует от Throwable.

catch(Exception exc) { /* won't catch RuntimeException */

но

catch(Throwable exc) { /* will catch RuntimeException */

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

это довольно актуально для меня, так как у меня есть ситуация, когда RuntimeExceptions могут быть вызваны в терминальной операции. Я не уверен, что название для этого шаблона, но что-то вроде, мой класс EmailRoller принимает массив Callbacks. Код выглядит так:

for(Callback cb : callbacks) {
    try {
        cb.call(item);
    }
    catch(Exception exc) {
        logger.error("Error in callback: ", exc);
   }
}

Итак, это случай, когда что-то вроде OOME должно пролететь, потому что, если один из этих обратных вызовов потребляет всю память машины, это наверняка повлияет на работу других. Но NullPointerException? Или IndexOutOfBoundsException? Они повлияют на обратный вызов, но не будут не позволяйте другим бежать.

кроме того, это немного дизайн предприятия. Различные программисты или команды могут добавлять обратные вызовы для обработки элемента, но они должны быть изолированы друг от друга. Это означает, что как программист, ответственный за изоляцию этих обратных вызовов друг от друга, я не должен полагаться на них, чтобы убедиться, что ошибки не проскальзывают. Ловить Exception должно быть о правильной линии, но это не потому, что RuntimeException проскальзывает. Поэтому мой более общий вопрос:: что здесь хорошего? Просто catch(Exception | RuntimeException exc), который я считаю синтаксической ошибкой из-за наследования?

5 ответов


предпосылка вопроса ошибочна, потому что ловить Exception тут лови RuntimeException. Демо-код:

public class Test {
    public static void main(String[] args) {
        try {
            throw new RuntimeException("Bang");
        } catch (Exception e) {
            System.out.println("I caught: " + e);
        }
    }
}

выход:

I caught: java.lang.RuntimeException: Bang

ваш цикл будет иметь проблем, если:

  • callbacks равно null
  • что-нибудь изменяет callbacks во время выполнения цикла (если это была коллекция, а не массив)

возможно, это то, что вы видите?


catch (Exception ex) { ... }

будет catch RuntimeException.

все, что вы помещаете в блок catch, будет поймано, а также подклассы его.


догоняет Exception поймает RuntimeException


я столкнулся с аналогичным сценарием. Это происходило потому, что инициализация classA зависела от инициализации classB. Когда статический блок classB столкнулся с исключением времени выполнения, classB не был инициализирован. Из-за этого classB не создавал никаких исключений, и инициализация classA также не удалась.

class A{//this class will never be initialized because class B won't intialize
  static{
    try{
      classB.someStaticMethod();
    }catch(Exception e){
      sysout("This comment will never be printed");
    }
 }
}

class B{//this class will never be initialized
 static{
    int i = 1/0;//throw run time exception 
 }

 public static void someStaticMethod(){}
}

и да...ловить Exception также поймает исключения времени выполнения.


class Test extends Thread
{
    public void run(){  
        try{  
            Thread.sleep(10000);  
        }catch(InterruptedException e){  
            System.out.println("test1");
            throw new RuntimeException("Thread interrupted..."+e);  
        }  

    }  

    public static void main(String args[]){  
        Test t1=new Test1();  
        t1.start();  
        try{  
            t1.interrupt();  
        }catch(Exception e){
            System.out.println("test2");
            System.out.println("Exception handled "+e);
        }  

    }  
}

его вывод не содержит test2, поэтому он не обрабатывает исключение среды выполнения. @jon skeet, @Jan Zyka