我可以在同一个catch子句中捕获多个Java异常吗?

fro*_*die 668 java exception try-catch multi-catch

在Java中,我想做这样的事情:

try {
    ...     
} catch (/* code to catch IllegalArgumentException, SecurityException, 
            IllegalAccessException, and NoSuchFieldException at the same time */) {
   someCode();
}
Run Code Online (Sandbox Code Playgroud)

...代替:

try {
    ...     
} catch (IllegalArgumentException e) {
    someCode();
} catch (SecurityException e) {
    someCode();
} catch (IllegalAccessException e) {
    someCode();
} catch (NoSuchFieldException e) {
    someCode();
}
Run Code Online (Sandbox Code Playgroud)

有没有办法做到这一点?

Osc*_*Ryz 1083

自Java 7以来,这是可能的.多捕获块的语法是:

try { 
  ...
} catch (IOException | SQLException ex) { 
  ...
}
Run Code Online (Sandbox Code Playgroud)

但请记住,如果所有异常都属于同一个类层次结构,则可以简单地捕获该基本异常类型.

另请注意,如果ExceptionB直接或间接地从ExceptionA继承,则无法在同一块中捕获ExceptionA和ExceptionB.编译器会抱怨:

Alternatives in a multi-catch statement cannot be related by subclassing
  Alternative ExceptionB is a subclass of alternative ExceptionA
Run Code Online (Sandbox Code Playgroud)

  • TT - 为什么重新定义`bitwise或`(```)运算符?为什么不使用逗号,或者具有更相似含义的运算符,`logical或`(`||`)? (80认同)
  • Java中的@ user1512999,按位XOR是^(插入符号),按位OR是| (管道)https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html (38认同)
  • 异或符号(I)与OR(||),A |不同 B表示A或B*,但*不表示A || B表示A或B或两者,因为例外情况是exceptionA或exceptionB,但不能同时发生.这就是为什么他们使用XOR而不是OR而你可以清楚地看到当异常被抛出时如果你输出2个异常,其中一个是另一个的子类型 (12认同)
  • @ArtOfWarfare也许他们认为在他们已经提出了针对泛型的[多重边界](http://docs.oracle.com/javase/tutorial/java/generics/bounded.html)的语法之后不再重要了. (10认同)
  • 值得一提的是,多捕获块中捕获的异常类型是对最派生的公共父级的值 (5认同)
  • @yanpas 不完全是。例如,当你重新抛出异常时,它会被作为“两个选项之一”而不是共同的父级来处理,即你不需要将父级放入 `throws` 子句中。 (2认同)
  • 选择“|”可能是因为它是其他语言中联合类型的标准语法。语言规范甚至将其称为“联合”,尽管它在此构造中仅在语法上有效(从 Java 7 开始): *“异常参数可以将其类型表示为单个类类型或两个或多个类类型的联合(称为替代项)。联合的替代项在语法上由 | 分隔。"* https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20 (2认同)
  • ``...如果所有异常都属于同一个类层次结构,您可以简单地捕获该基本异常类型。`` 事实并非如此。这样做,您将捕获所有其他(可能是不需要的)基本类型的子代。从语义上来说,这是不同的。 (2认同)

use*_*322 103

不完全是在Java 7之前,但我会做这样的事情:

Java 6和之前的版本

try {
  //.....
} catch (Exception exc) {
  if (exc instanceof IllegalArgumentException || exc instanceof SecurityException || 
     exc instanceof IllegalAccessException || exc instanceof NoSuchFieldException ) {

     someCode();

  } else if (exc instanceof RuntimeException) {
     throw (RuntimeException) exc;     

  } else {
    throw new RuntimeException(exc);
  }

}
Run Code Online (Sandbox Code Playgroud)



Java 7

try {
  //.....
} catch ( IllegalArgumentException | SecurityException |
         IllegalAccessException |NoSuchFieldException exc) {
  someCode();
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,您的Java 6示例打破了编译器告诉从哪里抛出什么的能力. (11认同)
  • 从可读性的角度来看,这是非常糟糕的做法. (5认同)
  • 在Java 6示例中,您不应该重新抛出原始异常而不是创建新的异常实例,即`throw exc`而不是`throw new RuntimeException(exc)`? (3认同)
  • 操作的实例有点贵,最好尽可能避免. (3认同)
  • @MichaelBlume是的,这不是那么糟糕.您总是可以使用`exc.getCause()`获取原始异常.作为旁注,Robert C. Martin(以及其他人)建议使用未经检查的异常(编译器不知道将从那里抛出什么样的异常); 请参阅_第7章:错误处理_他的书_清洁代码_. (2认同)
  • `Exception`s 用于 **exceptional** 情况。异常已经很昂贵了,`instaceof` 的昂贵在这里不应该成为一个问题...... (2认同)

cru*_*sam 23

在Java 7中,您可以定义多个catch子句,如:

catch (IllegalArgumentException | SecurityException e)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)


duf*_*ymo 15

不,每个客户一个.

只要在所有情况下采取相同的操作,您就可以捕获超类,例如java.lang.Exception.

try {
    // some code
} catch(Exception e) { //All exceptions are caught here as all are inheriting java.lang.Exception
    e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

但这可能不是最好的做法.只有在实际处理它的策略时才应该捕获异常 - 并且日志记录和重新抛出不是"处理它".如果您没有采取纠正措施,最好将其添加到方法签名中,然后让它冒泡到可以处理这种情况的人.

  • 我可以请求你改写关于捕获java.lang.Exception的部分吗?我意识到这是一个例子,但我觉得有些人可能会读到这个答案然后说:"哦,好吧,我只会抓住Exception",这可能不是他们想要(或应该)做的. (19认同)
  • 我不考虑记录和重新抛出任何处理.我宁愿让它冒泡到可以做一些有意义的事情的人身上.异常永远不会逃脱的最后一层(例如Web应用程序中的控制器)应该是在这种情况下记录错误的那一层. (4认同)
  • 我知道这一点,但我不想这样做......哦,好吧,我想我已经陷入了4次捕获,直到Java的下一个版本...... (2认同)

Mic*_*sin 14

如果存在异常层次结构,则可以使用基类来捕获所有异常子类.在简并的情况下,您可以捕获所有 Java异常:

try {
   ...
} catch (Exception e) {
   someCode();
}
Run Code Online (Sandbox Code Playgroud)

在更常见的情况下,如果RepositoryException是基类,而PathNotFoundException是派生类,则:

try {
   ...
} catch (RepositoryException re) {
   someCode();
} catch (Exception e) {
   someCode();
}
Run Code Online (Sandbox Code Playgroud)

上面的代码将捕获RepositoryException和PathNotFoundException以进行一种异常处理,并将所有其他异常集中在一起.从Java 7开始,按照@ OscarRyz的回答:

try { 
  ...
} catch( IOException | SQLException ex ) { 
  ...
}
Run Code Online (Sandbox Code Playgroud)

  • BTW catch子句按顺序处理,所以如果你在子类之前放置一个父异常类,那么它永远不会被调用,例如:try {...} catch(Exception e){someCode(); } catch(RepositoryException re){//从未到达} (7认同)
  • 实际上,正是因为它永远无法达到,所以这些代码甚至无法编译. (4认同)

Ole*_*ich 10

用户454322对Java 6(即Android)的回答更清晰(但不那么详细,也许不是首选)将是捕获所有Exceptions并重新抛出RuntimeExceptions.如果您计划在堆栈中进一步捕获其他类型的异常(除非您也重新抛出它们),这将无法工作,但会有效地捕获所有已检查的异常.

例如:

try {
    // CODE THAT THROWS EXCEPTION
} catch (Exception e) {
    if (e instanceof RuntimeException) {
        // this exception was not expected, so re-throw it
        throw e;
    } else {
        // YOUR CODE FOR ALL CHECKED EXCEPTIONS
    } 
}
Run Code Online (Sandbox Code Playgroud)

话虽如此,为了详细说明,最好设置一个布尔值或其他变量,并根据它在try-catch块之后执行一些代码.