在Java中抛出多个异常

49

在Java中有没有办法抛出多个异常?


8
不清楚 OP 是要求“在多个异常中选择一个抛出”还是“同时抛出多个异常”。 - usr-local-ΕΨΗΕΛΩΝ
11个回答

67
一个方法可以抛出多个异常之一。例如:
 public void dosomething() throws IOException, AWTException {
      // ....
 }

这表示该方法可能会抛出这两个异常中的一个(以及任何未经检查的异常)。您不能同时抛出两个异常,这在Java或其他任何语言中都不太有意义。

您还可以抛出一个嵌套的异常,其中包含另一个异常对象。但这几乎不能算作“抛出两个异常”,它只是表示由两个异常对象(通常来自不同层)描述的单个异常情况。


那取决于观点;-) 显然这并没有回答如何抛出多个异常的问题。 - kap

31

你不能抛出两个异常。也就是说,你不能这样做:

try {
    throw new IllegalArgumentException(), new NullPointerException();
} catch (IllegalArgumentException iae) {
    // ...
} catch (NullPointerException npe) {
    // ...
}

替代方案1:异常A由异常B 引起

您可以使用cause-constructor嵌套异常来执行以下操作:

try {
    Exception ex1 = new NullPointerException();

    // Throw an IllegalArgumentException that "wraps" ex1
    throw new IllegalArgumentException(ex1);
} catch (IllegalArgumentException iae) {
    // handle illegal argument...
    throw iae.getCause(); // throws the cause (the NullPointerException)
}

这篇文章介绍了关于链式异常的好方法:Programming.Guide: Chained Exceptions

备选方案2:使用suppressed异常

一个异常可以抑制另一个异常。

try {
    Exception ex1 = new NullPointerException();

    // Throw an IllegalArgumentException that "suppresses" ex1
    IllegalArgumentException ex2 = new IllegalArgumentException();
    ex2.addSuppressed(ex1);
    throw ex2;
} catch (IllegalArgumentException iae) {
    // handle illegal argument...
    ... iae.getSuppressed() ... // get hold of the suppressed exceptions
}

这是一篇关于抑制异常的好文章:Programming.Guide: Suppressed Exceptions


25

我想你可以创建一个包含已捕获异常列表的异常,并抛出该异常,例如:

class AggregateException extends Exception {
    List<Exception> basket;
}

7
要在Java中抛出多个异常,首先需要将每个异常压缩为一个自定义异常,然后抛出相同的自定义异常。请检查以下代码片段以实现此目的。
  public class AggregateException extends Exception {


        public void addException(Exception ex){

        addSuppressed(ex);
        exception = true;
    }
}


public class AnyClass{

    public AggregateException aggExcep = new AggregateException();

    public void whereExceptionOccurs(){
        try{

              //some code
        }catch(Exception e){

              aggExcep.addException(e);
              //throw aggExcep;
        }  
    }
}

在 catch 块中,可以使用相同的引用 aggExcep 调用 addException 方法来抑制任何异常。在需要显式抛出 aggExcep 的地方,可以使用 'throw' 关键字。

Throwable 类中预定义了

void addSuppressed(Throwable exception)

方法,它将指定的异常附加到被抑制的异常列表中,以便传递此异常。


7

抛出多个异常是没有意义的,因为你不可能有多个错误(错误可能有多个原因,但在任何时候只能有一个错误)。

如果你需要跟踪原因,可以链接异常:

} catch (Exception ex) {
    throw new RuntimeException("Exc while trying ...", ex);
}

这些可以通过 getCause() 获得。

6
请不要鼓励人们去捕获基本的 Exception。此外,为了重新包装异常,我会使用一个项目特定的异常基类。这样我就可以区分可接受的异常、我已经包装并计划处理的异常,以及意外的异常。 - unholysampler
取决于您所说的错误是什么。在为给定语言开发语义分析器的特定情况下,AST 可能包含多个语义错误,将它们“一次性”返回给用户可能会更有益,以避免他们不断编译代码以查看下一个错误。您可以认为这种情况不需要异常,简单的字符串就足够了。 - Novicegrammer
@初学者编程:我的设计是有一个包含错误列表的单一异常,消息为"发生了 " + errors.size() + " 个错误:\n" + errors.stream().map(String::valueOf).collect(joining("\n") - Aaron Digulla

7

我见过一种模式,即自定义异常在内部存储其他异常(无法记住为什么这样做),但它的形式是:

public class ContainerException extends Exception {

  private List<Exception> innerExeptions = new Arrayist<Exception>();

  // some constructors

  public void add(Exception e) {
    innerExceptions.add(e);
  }

  public Collection<Exception> getExceptions() {
    return innerExceptions;
  }
}

它是这样使用的:

try {
  // something
} catch (ContainerException ce) {
  ce.add(new RunTimeException("some Message");
  throw ce; // or do something else
}

在代码的后面,容器异常被评估并转储到日志文件中。


3

你可以有可能抛出多个不同的异常。例如:

if (obj == null)
    throw new NullPointerException();

if (some other case)
    throw new IllegalArgumentException();

if (this == this)
    throw new IOException();

这段代码可能会抛出多个不同的异常,但这些异常永远不会同时发生。


3
Andreas_D所描述的模式在处理服务器端编译用户提供的文件并希望反馈错误时非常有用。
例如,如果资源无法编译,则会生成CompilationException。编译可能意味着许多事情。例如,您可能会评估终端用户上传的文件中的文本,解析令牌,检查语法错误并确定文件是否有效。最终,该文件要么有效,要么无效,您希望返回适当的CompilationException以向上传播调用堆栈。
像Andreas所描述的那样,您可以拥有一个add()方法,使您可以将编译问题添加到异常中。这些问题本身不必是异常,但这取决于您。通常有助于坚持使用单个异常框架,以便您可以在多个地方使用相同的验证逻辑。
无论如何,您想要的是一个单一的CompilationException通过调用堆栈回退,因为这告诉框架该事物没有编译。如果任何人想知道原因,那么他们可以调用getCauses()来获取根本原因。
从UI的角度来看,这也非常有用。在异常上保留的信息可以在重新传输之前得到妥善处理,以便您可以向终端用户提供关于编译失败原因的信息。

1
我不确定您是否在询问同时抛出多个异常,还是我们可以编写代码来处理多个异常。我将尝试回答这两个问题。这是我在StackOverflow上的第一个答案,敬请谅解任何错误。
1)如果您想同时抛出多个
`try{
     ...
     //some method/action that can be a cause of multiple errors,say X and Y
     ...
 }catch(XException e){
      //Do something if exception X arises.
 }catch(YException e){
      //Do something if exception Y arises.
 }
`

ii) 在Java 7之后,您可以使用多重捕获功能。

try{
     ...
     //some method/action that can be a cause of multiple errors,say X and Y
     ...
 }catch(XException|YException e){
   // Take action appropriate to both types of exception.
  ...
 }

我相信这将解决你的疑惑。作为我的第一个答案,欢迎提出所有建议!

0

有一种方法可以使一个方法抛出多个异常,但不能同时抛出。例如,当编译由于某些原因失败时,您的方法只能抛出一个异常。 如果您必须涵盖不同的机会,您可能会声明您的方法抛出所有异常的父类“Exception”。 因此,如果您通常声明一个方法抛出异常,该方法可以抛出任何类型的异常。

例如:

public static void main(String[] args) throws Exception
{
  getClipboard();    // throws an UnsupportedFlavorException
  initIOActivity();  // throw an IOException
}

我不知道你实际上需要知道什么,但也许这可以帮助你。虽然自你发布以来已经过了很长时间^^
问候

如果你想抛出多个异常,你应该将你的方法定义为public void method() throws UnsupportedSomethingException, IOException {...}。使用Exception本身是一种快速失去正确处理异常所获得的大部分能力的方式。我只建议在UI线程或某些顶层捕获异常,以避免完全崩溃。 - indivisible

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接