如何在java中编写未经检查的可丢弃文件

如何在java中编写未经检查的可丢弃文件,java,throwable,unchecked-exception,Java,Throwable,Unchecked Exception,我想写一个未选中的自定义可丢弃文件 有一些方法可以在抛出时欺骗编译器(例如),我就是这样实现的: public类CustomThrowable扩展了Throwable{ 公共CustomThrowable(字符串消息){ 超级(信息); } @抑制警告(“未选中”) 公共T unchecked()抛出T{ 扔掉这个; } } 但我在“赶时间”遇到了问题: 试试{ 抛出新的CustomThrowable(“foo”).unchecked(); } catch(CustomThrowable t)

我想写一个未选中的自定义可丢弃文件

有一些方法可以在抛出时欺骗编译器(例如),我就是这样实现的:

public类CustomThrowable扩展了Throwable{
公共CustomThrowable(字符串消息){
超级(信息);
}
@抑制警告(“未选中”)
公共T unchecked()抛出T{
扔掉这个;
}
}
但我在“赶时间”遇到了问题:

试试{
抛出新的CustomThrowable(“foo”).unchecked();
}

catch(CustomThrowable t){}/
Throwable
是一个已检查的错误,实际上不可能抛出此类错误,除非是运行时异常或错误

但实际上这是可能的。这里有一个例子

下面是一个实用程序,它在选中时抛出任何未选中的异常:

package org.mentallurg;

public class ExceptionUtil {

    private static class ThrowableWrapper extends Throwable {

        private Throwable throwable;

        public ThrowableWrapper(Throwable throwable) {
            super();
            this.throwable = throwable;
        }

        @SuppressWarnings("unchecked")
        public <T extends Throwable> T throwNested() throws T {
            throw (T) throwable;
        }
    }

    private static <T extends Throwable> T throwThis(T throwable) throws T {
        throw throwable;
    }

    public static <T extends Throwable> void throwUnchecked(T throwable) {
        new ThrowableWrapper(throwable).throwNested();
    }

}
请注意,在
main
doSomething
中都没有
throws-Throwable
子句。并且没有编译错误。在
RuntimeException
的情况下,这是可以理解的,但在
Throwable
的情况下则不然

如果我们执行它,我们会得到以下结果:

Exception in thread "main" java.lang.Exception: I am checked exception
    at org.mentallurg.Test.doSomething(Test.java:6)
    at org.mentallurg.Test.main(Test.java:11)
它是如何工作的

最重要的是这一部分:

new ThrowableWrapper(throwable).throwNested();
实际上,方法
throwNested
在这里可以抛出一个
Throwable
。这就是为什么Java编译器应该引发错误,并且应该要求这行代码要么被try/catch包围,要么应该添加
Throwable
子句。但事实并非如此。为什么?我相信这是Java编译器中的一个缺陷。其他线程中关于SO的一些注释提到了类型擦除,但它们是不正确的,因为类型擦除在运行时是相关的,正如我们所说的编译时

有趣的是,反编译的代码显示这里将抛出一个
可丢弃的
(非
运行时异常
,非
错误
):

  public static <T extends java.lang.Throwable> void throwUnchecked(T);
    Code:
       0: new           #28                 // class org/mentallurg/ExceptionUtil$ThrowableWrapper
       3: dup
       4: aload_0
       5: invokespecial #30                 // Method org/mentallurg/ExceptionUtil$ThrowableWrapper."<init>":(Ljava/lang/Throwable;)V
       8: invokevirtual #32                 // Method org/mentallurg/ExceptionUtil$ThrowableWrapper.throwNested:()Ljava/lang/Throwable;
      11: pop
      12: return

在所有这些情况下,如果我们用特定类替换泛型,那么Java编译器将报告一个错误,这是正确的。在使用泛型的情况下,Java编译器会忽略已检查的异常,并且不会报告任何错误。这就是为什么我认为这是Java编译器中的一个错误

您可以扩展
错误
,而不是
可丢弃的
。Java
Error
类是一个未经检查的
可丢弃的

Per(以及Jon Skeet;,毫无疑问的权威),似乎Java编译器内置了未经检查的异常支持,我可能无法插入

引用Jon的帖子:

规范第11.1.1节明确规定:

RuntimeException及其所有子类统称为运行时 异常类

未选中的异常类是运行时异常类和 错误类别

选中的异常类是除 未选中的异常类。即,选中的异常类 除了RuntimeException及其 子类和错误及其子类

是的,编译器肯定知道RuntimeException


我仍然希望其他人会给出一个“是的,你可以”的答案,所以我会再等几天再结束这个问题。

你知道RuntimeException扩展了Throwable吗?是的-我在避免扩展
RuntimeException
,因为1)我的Throwable不是一个例外,2)我想避免我的可丢弃文件被
catch(Exception e){}
块捕获。我无法将您的语句“可丢弃文件未检查”与我看到的编译器错误“未处理的异常”协调起来。除非IntelliJ中有一个奇怪的bug,否则我有经验证据证明可以检查一次性物品。@Thorbjørnravandersen:可以检查一次性物品。参见Java文档:为了对异常进行编译时检查,Throwable和Throwable的任何子类如果不是RuntimeException或Error的子类,都被视为检查过的异常。在我的脑海中,Throwable与Error(未检查)混在一起。我的缺点是在听起来很有知识之前不进行实际检查。问题是如何将任何
Throwable
作为未检查的异常抛出,而不必使用try/catch,也不必在
throws
子句中声明它。这不是一个坏主意,因为它将避免
catch(exception ex){}
blocks-如果我找不到更直接的方法,我可以试试。问题不在Java编译器中,而是您显式地抑制了未检查的警告。@ThorbjørnRavnAndersen:不。抑制了类型转换。无法抑制异常。这只是一个警告,不是编译器错误“。我们可以删除此抑制,代码仍将编译,即将创建类文件并可以执行。若有未锁定的异常,那个么将出现编译器错误,并且不会创建.class文件,并且不可能执行任何操作。很遗憾,您的评论没有解释任何内容。请尝试删除
@SuppressWarnings(“unchecked”)
,看看会发生什么。删除后的结果是一样的:Java编译器已创建.class文件。如果在IDE中打开源代码,当我使用默认严重性设置时,它会显示警告。但代码已成功编译,.class文件已创建,我已成功执行它。你试过了吗?;-)当然,删除抑制警告会导致警告,而不是编译错误。警告明确地告诉您代码有问题(但不是代码非法)。这不是Java编译器中的错误,因为它严格遵守JLS,但在添加泛型时是一个设计决策。这只是显式欺骗编译器的一种非常聪明的方法。是的,您不能定义一个可以抛出的Throwable子类
  public static <T extends java.lang.Throwable> void throwUnchecked(T);
    Code:
       0: new           #28                 // class org/mentallurg/ExceptionUtil$ThrowableWrapper
       3: dup
       4: aload_0
       5: invokespecial #30                 // Method org/mentallurg/ExceptionUtil$ThrowableWrapper."<init>":(Ljava/lang/Throwable;)V
       8: invokevirtual #32                 // Method org/mentallurg/ExceptionUtil$ThrowableWrapper.throwNested:()Ljava/lang/Throwable;
      11: pop
      12: return
public <T extends Exception> T throwNested() throws T {