【问题标题】:Is "precise rethrow with a final exception" working in Java SE 8?在 Java SE 8 中是否可以使用“带有最终异常的精确重新抛出”?
【发布时间】:2015-06-10 17:21:51
【问题描述】:
public class TestException extends except2 {

    public static void main(String[] args)throws Exception  {
       try {
            try {
                throw new TestException();
            }
            catch (final TestException e){         
            }
            throw new except2();
        }
        catch (TestException a){
        }
        catch (Exception e){
            throw e;
        }
    }

    public TestException(){
    }
}

class except2 extends Exception{
}

大家好,

我的 JDK 版本是 8u45,现在是最新版本。

我想知道在 SE 8 中仍然可以使用“带有最终异常的精确重新抛出”吗?

作为代码,如果我将“抛出异常”关闭,它将是编译错误,但根据SE7的“精确重新抛出最终异常”功能应该可以忽略它。

另外一个问题是我们都知道如果嵌套的try box发生了异常,我们还是应该把它扔到外层的catch box来避免编译错误,我本来以为只要抛出任意类型的异常就可以了& 它会做,我的测试结果也是如此,我认为这是让编译器知道 try box 和 catch box 中存在异常也得到了它。

但是如果我像下面的代码一样改变它:

public class TestException extends except2 {
    public static void main(String[] args)throws Exception  {
       try {
            try {
                throw new ArithmeticException();
            } catch (final TestException e){
                throw e;
            } 
        } catch (TestException a){
        } catch (Exception e){
            throw e;
        }
    }
}

(final TestException e) 部分将是编译错误消息:

"com.xxx.TestException" 异常不会在相应的 try 块中抛出",

我很困惑,因为如果嵌套的 catch 块无法处理异常,它应该转到外部。

那么,如果我在外部 try 块的末尾抛出一个 ArithmeticException,如下所示:

try {
    try {
        throw new TestException();
    }
    catch (final TestException e){
        System.out.println("d");
    }

    throw new ArithmeticException();
}
catch (TestException a){
}
catch (Exception e){
    throw e;
}

与外部捕获框catch (TestException a){}相同的错误

为什么会这样?

它应该被(Exception e) 块捕获。

如果我不能从嵌套try块的第一个异常中抛出不同类型的异常,为什么我可以在第一段代码中抛出except2?

【问题讨论】:

  • 你能压缩你的代码吗?有很多空白。
  • @SotiriosDelimanolis thx 伙计,新来这里的人,抱歉

标签: java exception


【解决方案1】:

这是该功能的 Oracle 示例,它仍然适用于 Java 8:

static class FirstException extends Exception { }
static class SecondException extends Exception { }

public void rethrowException(String exceptionName)
   throws FirstExceptio, SecondException // Since J7 no "Exception" needed
{
  try {
    if (exceptionName.equals("First")) {
      throw new FirstException();
    } else {
      throw new SecondException();
    }
  } catch (Exception e) {
    throw e; // effective final (i.e. not assigned)
  }
}

这在Oracle document 的后半部分进行了描述。您的示例都与它无关。尤其不是你有更具体和普遍的捕捉的那个。这在文档中明确提到不起作用。

如果您使用except2(我将其重命名为BaseException),您的第一个块将起作用,这是更具体的:

public class TestException extends BaseException {

    public static void main(String[] args) {
       try {
            try {
                throw new TestException();
            }
            catch (final BaseException e){
              throw e; // this is defined as BaseEx, will fail on Java 6
            }
        }
        catch (TestException a){ // this knows that no BaseEx is expected
        }
    }

    public TestException(){
    }
}

class BaseException extends Exception { }

如您所见,main() 方法不再需要抛出异常,因为第二个 catch 块就足够了。

【讨论】:

  • 对不起,伙计并没有真正理解你的意思,我认为我的代码没有违反文档中描述的规则。你能解释一下吗?欣赏!
  • 我只是指“没有其他前面的 catch 块可以处理它”,catch (TestException e1) { } catch (Exception e2) {} 就是这种情况
  • sry 你目前的意思是哪个代码块? 1,2 还是 3?在第一个代码中嵌套的 try-catch 块最终抛出 except2,它不能被 catch (TestException a) 处理,所以它被 catch (Exception e) 捕获,但根据精确重新抛出的特性我们应该是可以在方法签名后忽略throws 中的注释,但我的问题不在我的结果中。
  • 第一个 clode 块,我在我的答案中添加了一个变体,它实际上确实使用/精确地重新抛出。
  • sry mate..不知道你指的是哪一部分@@
【解决方案2】:

您的第一段代码可以缩短为

class TestException extends except2 throws Exception {
    public static void main(String[] args) {
        try {
            throw new except2(); // this
        } catch (TestException a) {
        } catch (Exception e) {
            throw e;
        }
    }

    public TestException() {
    }
}

class except2 extends Exception {
}

你正在抛出一个except2。 TestException 是 except2,但 except2 不一定是 TestException。第一个 catch 块无法处理 except2 异常。所以第二个必须。由于它进一步throws 那个异常,并且必须检查那个异常,你需要有一个throws 子句。

你的第二段代码

class TestException extends except2 {
    public static void main(String[] args) throws Exception {
        try {
            try {
                throw new ArithmeticException();
            } catch (final TestException e) { // nothing above throws a TestException
                throw e;
            }
        } catch (TestException a) {
        }
        catch (Exception e) {

            throw e;
        }
    }
}

正在尝试在嵌套的 try 块中捕获 TestException。但是由于TestException 是一个检查异常,编译器可以并且确实检查它是否可以在该块中抛出。在你的情况下,它不能。所以它抱怨试图抓住它是没有用的。

最后,在你的最后一个sn-p中

class TestException extends except2 {
    public static void main(String[] args) throws Exception {
        try {
            try {
                throw new TestException();
            } catch (final TestException e) {
                System.out.println("d");
            }
            throw new ArithmeticException();
        } catch (TestException a) {
        } catch (Exception e) {
            throw e;
        }
    }
}

您在嵌套的try-catch 语句中抛出和捕获TestException。所以你可以将代码减少到

class TestException extends except2 {
    public static void main(String[] args) throws Exception {
        try {
            throw new ArithmeticException();
        } catch (TestException a) {
        } catch (Exception e) {
            throw e;
        }
    }
}

这与您的第二段代码有相同的问题。那里没有可以抛出TestException的代码路径。


关于cmets,为了简化第二个sn-p,误差减少到

class TestException extends except2 {
    public static void main(String[] args) throws Exception {
        try {
            throw new ArithmeticException();
        } catch (final TestException e) { // nothing above throws a TestException
            throw e;
        }
    }
}

你有一个catch(TestException),但没有抛出一个TestException,所以这是编译器拒绝的无用代码。


来自 cmets,这是您的案例 2 和 3 的问题

// ignore everything around this
try {
    // nothing in this block 
    // can throw a TestException

    throw new ArithmeticException();

// this whole catch block is useless code
// Test Exception can never be thrown
} catch (final TestException e){ 
    throw e;
} 
// ignore everything around this

【讨论】:

  • 对不起兄弟,但是“精确地重新抛出最终异常”功能的想法是编译器会自动验证你重新抛出异常的实际类型,所以你不必添加超级异常的类型捕获它的 catch 块,在这种情况下是“异常”?thx!第二部分,是的,ArithmeticException 可以被嵌套的 TestException try 块捕获,但它应该留给另一个 catch 块来连续匹配 rite?然后问题仍然发生。
  • 那么关于第三部分,我们不需要在每个 catch 块中明确地重新抛出 obj ,除非你在方法签名仪式的抛出中注意到它?在这种情况下,为什么 TestException catch 块需要重新抛出?
  • @kiah 在第一个示例中,您抛出了一个except2,这是一个检查异常。 catch(TestException) 无法捕捉到这一点。因此它必须被catch(Exception) 捕获。由于except2 是一个已检查异常并且这是编译器知道的唯一异常,因此您必须处理这个异常被重新抛出的事实,要么使用另一个封闭的try-catch 语句,要么使用方法级别的throws 声明。
  • @KiahStarck A catch(TestException) 无法捕捉到ArithmeticException。但这不是问题。问题是编译器知道 第二个 sn-p 中的任何内容都不会抛出 TestException,而该 TestException 会被嵌套的 catch(TestException)** 捕获。因此,它会以错误方式拒绝代码。
  • > 第二个 sn-p 中没有任何东西可以抛出一个 TestException,它会被嵌套的 catch(TestException) 捕获 我认为你的意思是第二个嵌套的代码 @ 987654354@ 我的意识是嵌套的try确实抛出了TestException,嵌套的catch块确实被捕获了,但是我们仍然需要为封闭的catch块抛出异常,否则会出现编译错误,但是如果我们throw except2,它可以工作,如果 throws ArithmeticException 会出错,但它应该都通过编译,这就是我的问题所在。欣赏!
猜你喜欢
  • 2011-10-16
  • 2018-04-09
  • 2020-03-10
  • 2010-12-18
  • 1970-01-01
  • 1970-01-01
  • 2011-10-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多