如何在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编译器中的一个错误您可以扩展错误
,而不是可丢弃的。JavaError
类是一个未经检查的可丢弃的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 {