【问题标题】:How to make a try-catch block that keeps on calling a method on an object until there are no more exceptions to catch如何制作一个 try-catch 块,不断调用对象上的方法,直到没有更多异常要捕获
【发布时间】:2010-04-19 21:35:53
【问题描述】:

基本上遍历一个列表,
- 在第一个对象上调用方法
- 捕获第一个异常(如果有);如果没有更多要捕获的异常,则正常返回。否则,继续调用方法,直到所有异常都被捕获。
- 移动到下一个对象。

我可以遍历每个对象,调用方法,并捕获一个异常,但我不知道如何持续调用它的方法并继续捕获异常。

【问题讨论】:

  • “捕获第一个异常;如果没有更多异常要捕获...”是什么意思? 一个方法调用只能抛出一个异常,所以“first”和“more”在“invoke method”的上下文中没有意义。
  • 该方法抛出一个带有多个子类/子异常的异常。

标签: java loops try-catch try-catch-finally


【解决方案1】:

这类似于其他答案,但没有标志,这对我来说似乎很混乱。不过我不太明白这个问题,所以我只是把它扔在那里以防万一它有用。

for (Item item : items) {
  while (true) {
    try {
      item.doSomething();
      break;
    } catch (MyException ex) {
      log.warn("Something failed.", ex);
    }
  }
}

这种方法取决于未标记的break 语句的操作,该语句突然完成,然后正常退出封闭的while 语句。


基于后续的 cmets,我认为当有多个异常声明为由一个方法抛出时,我认为它的含义有些混乱。

方法的每次调用都可以通过抛出一个异常来终止。您无法以某种方式从中断处恢复调用,并处理后续异常。

因此,如果一个方法抛出多个异常,请捕获一个共同的祖先,然后继续。例如,如果一个方法抛出java.io.EOFException java.nio.channels.ClosedChannelException,你可以简单地捕获java.io.IOException,因为它是一个共同的祖先。 (出于同样的原因,您也可以捕获 java.lang.Exceptionjava.lang.Throwable。)在相同条件下再次调用该方法不会让您更进一步。

如果你想尝试调用每个对象的方法,即使有些失败,使用这个:

for (Item item : items) {
  try {
    item.doSomething();
  } catch (Exception ex) { /* This could be any common ancestor. */
    log.warn("Something failed.", ex);
  }
}

【讨论】:

    【解决方案2】:

    如果您正在谈论处理将引发多个异常的单个方法调用,则无法完成 - 无论您调用该方法多少次,它都会继续抛出第一个异常。你不能回到方法并从那里继续运行;抛出一个异常后,一切都结束了。

    但是,如果您正在谈论一种有时会抛出异常而有时不会抛出异常的方法,请尝试以下方法:

    boolean thrown = false;
    do {
        try {
            thrown = false;
            method();
        }
        catch (Exception e) {
            thrown = true;
            // Handle as you like
        }
    } (while thrown);
    

    【讨论】:

    • “无论你调用多少次方法,它都会继续抛出第一个异常” - 微不足道的反例:class Ex { int counter = 5; void throwFive() throws Exception { if (counter--) { throw new Exception("boo"); } } }
    • 对于类似的事情,请参阅我的第二个案例。请参阅您引用的句子的前面:“如果您正在谈论处理将引发多个异常的单个方法调用。”例如,void foo() throws Exception {throw new Exception("one"); throw new Exception("two");} 在这种情况下无法捕获第二个异常,因为它永远不会被抛出。
    • 啊,我现在明白你的意思了。而且确实是对的。很抱歉造成误解。
    【解决方案3】:

    这是我的理解。

    你有一个对象的方法,它可能会抛出一些异常。

    您想要做的是将它们全部捕获并继续处理列表中的下一个对象。

    对吗?

    所以,那就是:

    for( YourObject o : yourList ) {
        try {
           o.thatMethod();//invoke that risky method 
        } catch( SomeExceptionClass sec ) {
           // Do something with that exception
        } catch( SomeOtherExceptionClass soec ) {
           // Do something with that exception  
        } catch( YetAnotherxceptionClass yaec ) {
           // Do something with that exception
        } catch( OtherUnRelatedException oue ) {
           // Do something with that exception
        }
    }
    

    当你这样做时,如果thatMethod() 的调用抛出异常并且该异常列在catch 部分中,则执行流程将跳转到该异常,之后将继续正常流程(即for 循环并将继续下一个对象)

    我希望这是需要的。更多信息请阅读:The catch blockJava 教程部分Essential classes

    【讨论】:

      【解决方案4】:

      我假设您正在尝试对列表中的项目执行某种验证,其中通过抛出异常来报告验证错误。我还假设您正在尝试收集所有的验证错误。

      简单的答案是使用这种方法无法解决这个问题。要了解原因,请查看以下内容:

      boolean exceptionCaught = false;
      do {
          try {
              item.doSomething();
          } catch (MyException e) {
              exceptionCaught = true;
          }
      } while (exceptionCaught);
      

      这会失败,因为每次您调用item.doSomething() 时,它都会在完全相同的位置引发异常。最终结果是一个无限循环。

      您可以使用这种方法做的最好的事情是为列表中的每个item 捕获第一个异常。

      那么,您如何才能实现您想要实现的目标呢?答案是您必须更改验证代码以使用其他方式报告错误而不是抛出异常。例如,您可以更改:

      class Item {
          ...
          void validate() {
              if (noHat) {
                  throw new MyException("bad hat");
              }
              if (noPants) {
                  throw new MyException("world-wide pants");
              }
          }
      }
      

      到这样的事情:

      class Item {
          ...
          void isValid(List<MyException> errors) {
              boolean ok = true;
              if (noHat) {
                  errors.add(new MyException("bad hat"));
                  ok = false;
              }
              if (noPants) {
                  errors.add(new MyException("world-wide pants"));
                  ok = false;
              }
              return ok;
          }
      }
      

      乱七八糟!您可以通过各种方式对此进行加糖,但这种错误报告方式总是会更加复杂。但我认为没有一种实用的方法可以避免AND捕获ALL的验证错误。

      【讨论】:

        猜你喜欢
        • 2019-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-26
        • 2019-11-11
        相关资源
        最近更新 更多