当前位置: 首页 > 面试题库 >

为什么在某些情况下不声明而重新抛出Throwable是合法的?

经骁
2023-03-14
问题内容

我希望下面的代码在上引发编译时错误throw t;,因为main未声明为throw Throwable,但编译成功(在Java
1.7.0_45中),并且如果编译时错误为,则会生成您期望的输出固定。

public class Test {
    public static void main(String[] args) {
        try {
            throw new NullPointerException();

        } catch(Throwable t) {
            System.out.println("Caught "+t);
            throw t;
        }
    }
}

如果Throwable更改为,它也会编译Exception

不会按预期方式编译:

public class Test {
    public static void main(String[] args) {
        try {
            throw new NullPointerException();

        } catch(Throwable t) {
            Throwable t2 = t;
            System.out.println("Caught "+t2);
            throw t2;
        }
    }
}

这样编译:

public class Test {
    public static void main(String[] args) {
        try {
            throwsRuntimeException();

        } catch(Throwable t) {
            System.out.println("Caught "+t);
            throw t;
        }
    }

    public static void throwsRuntimeException() {
        throw new NullPointerException();
    }
}

这不是:

public class Test {
    public static void main(String[] args) {
        try {
            throwsCheckedException();

        } catch(Throwable t) {
            System.out.println("Caught "+t);
            throw t;
        }
    }

    public static void throwsCheckedException() {
        throw new java.io.IOException();
    }
}

这也可以编译:

public class Test {
    public static void main(String[] args) throws java.io.IOException {
        try {
            throwsIOException();

        } catch(Throwable t) {
            System.out.println("Caught "+t);
            throw t;
        }
    }

    public static void throwsIOException() throws java.io.IOException {
        throw new java.io.IOException();
    }
}

一个更复杂的示例-被检查的异常由外部catch块捕获,而不是被声明为抛出。这样编译:

public class Test {
    public static void main(String[] args) {
        try {
            try {
                throwsIOException();

            } catch(Throwable t) {
                System.out.println("Caught "+t);
                throw t;
            }
        } catch(java.io.IOException e) {
            System.out.println("Caught IOException (outer block)");
        }
    }

    public static void throwsIOException() throws java.io.IOException {
        throw new java.io.IOException();
    }
}

因此,当编译器可以确定捕获的异常始终合法地重新抛出时,似乎有一种特殊情况允许重新抛出异常。这样对吗?JLS在哪里指定?还有其他类似的晦涩难解案例吗?


问题答案:

JLS
11.2.2
(重点是我)对此进行了介绍:

如果throw语句的抛出表达式catch子句C 的最终或有效的最终 异常参数 ,则可以抛出异常类E iff:

  • E是一个异常类,声明C的try语句的try块可以抛出该异常类;和

  • E是与C的任何可捕获异常类兼容的分配 ;和

(…)

换句话说,Edoc中引用的类型 是可以抛出 的类型,而不是捕获它的catch子句参数的类型( catchable异常类 )。它只需要在 分配
上与catch子句参数 兼容 ,但是在分析中不使用该参数的类型。

这就是为什么竭尽全力说出 最终或有效的最终异常参数的 原因-如果t在您的示例中重新分配了 异常 ,则分析将超出预期范围。



 类似资料:
  • 我希望下面的代码在上引发一个编译时错误,因为没有声明为throw,但它编译成功(在Java 1.7.0_45中),并生成您希望的输出,如果该编译时错误得到修复的话。 如果更改为,它也会进行编译。 这并不像预期的那样编译: 这将编译: 这并不是:

  • 问题内容: 为什么 工作,但是 不是吗 问题答案: 为了理解这一点,让我们考虑一下编译器在两种可能性下每个步骤所做的事情。让我们开始: 编译器将‘4’转换为int。所以变成 然后编译器变成 ch是一个字符,编译器可以将54转换为字符,因为它可以证明转换没有损失。 现在让我们考虑第二个版本: ch在编译时没有已知值。因此,这成为 现在,编译器无法证明此(int)的结果在char范围内可存储。因此它

  • 我遇到了一个非常奇怪的问题,java线程正忙着等待。 我有一个线程忙于等待其他线程的静态变量的状态。假设忙碌等待的线程正在等待另一个线程的静态int变量达到某个值 如果我使用上面的代码,线程将被卡在忙等待中,不会跳出while循环,即使确实达到5。 但是,如果我使用其他代码,那么线程确实会跳出忙等待循环。有时,一旦达到5,其他时候会晚一点。但它会发生。对于我的特定示例,我将其用作“无意义的工作”

  • 问题内容: 我正在学习CopyOnWriteArrayList类。 复制新阵列的目的是什么? 是其他线程读取数组吗? 因此,如果系统具有高并发性,并且大多数线程的操作都在读取而不是写入,那么最好使用。 问题答案: 如该链接所述: CopyOnWriteArrayList是Java 5并发API中引入的并发Collection类,以及它在Java中流行的表亲。 工具列表界面类似,并且但它的一个线程安

  • 我想知道为什么java编译器允许在方法声明中抛出,而方法永远不会抛出异常。因为“throws”是处理异常的一种方式(告诉调用方处理它)。 因为有两种处理异常的方法(抛出和try/catch)。在try/catch中,它不允许捕获try块中未抛出的异常,但它允许在不抛出异常的方法中抛出。

  • 我用Kotlin和Jongo来访问MongoDB。Jongo使用Jackson来序列化/反序列化对象,以便从MongoDB中保存和读取它们。我使用Jackson-Kotlin模块来帮助使用构造函数序列化Kotlin数据类。 下面是一个序列化良好的数据类的示例: 下面是一个未能反序列化的类似类的示例: Jongo抛出以下异常,因为Jackson反序列化失败: 如果我像这样完整地注释会话数据类,它确实