Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么在某些情况下,在不声明的情况下重新抛出一次性垃圾是合法的?_Java - Fatal编程技术网

Java 为什么在某些情况下,在不声明的情况下重新抛出一次性垃圾是合法的?

Java 为什么在某些情况下,在不声明的情况下重新抛出一次性垃圾是合法的?,java,Java,我希望下面的代码在throw t上引发编译时错误,因为main未声明为throwThrowable,但它编译成功(在Java 1.7.0_45中),并生成您期望的输出(如果编译时错误得到修复) public class Test { public static void main(String[] args) { try { throw new NullPointerException(); } catch(Throwable t

我希望下面的代码在
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 {
            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();
    }
}
这并不是:

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 {
            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 {
            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中在哪里规定了这一点?还有其他类似这样的模糊情况吗?

当您捕获可丢弃的
异常
并且该变量实际上是最终变量时,您可以重新调用相同的变量,编译器将知道您可以在
try{}中抛出哪些已检查的异常catch
块。

因为编译器足够聪明,知道不能从try块抛出选中的异常,因此捕获的Throwable不是必须声明的选中异常

请注意,如果我没有弄错的话,从Java 7开始这是正确的。

这在(我的重点)中有介绍:

抛出表达式为catch子句C的final或effectivefinal异常参数的throw语句可以抛出异常类Eiff:

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

  • E的赋值与C的任何可捕获异常类兼容;及

(……)

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


这就是为什么他们会特意说一个最终的或有效的最终异常参数——如果您的示例中的
t
被重新分配,那么分析就会消失。

@PeterLawrey:不,我只是尝试了一下(我猜您的意思是
catch(final Throwable t)
)。我猜这是在Java7中引入的Multicatch工作中产生的。