Jic*_*hao 5 java exception-handling throwable
我认为Exception.fillInStackTrace应该返回Exception或派生的Exception对象.考虑到以下两个功能,
public static void f() throws Throwable {
try {
throw new Throwable();
} catch (Exception e) {
System.out.println("catch exception e");
e.printStackTrace();
}
}
public static void g() throws Throwable {
try {
try {
throw new Exception("exception");
} catch (Exception e) {
System.out.println("inner exception handler");
throw e.fillInStackTrace();
}
} catch (Exception e) {
System.out.println("outer exception handler");
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
exception handler没能赶上new Throwable()第一功能f().exception handler可以赶上e.fillInstackTrace()第二功能g().g()仍然需要throws Throwable.这真的很奇怪,因为我们可以抓住e.fillInstackTrace().所以我的问题是为什么Exception.fillInStackTrace不返回Exception或Exception派生而不是开发这样一个奇怪的语法?
编辑:
要澄清我的问题:我所说的"奇怪的语法"的意思是
Exception.fillInStackTrace()返回Throwable引用,接收Exception引用的异常处理程序不应该能够捕获异常.因为java不允许隐含向下转换,所以它应该是类似的return (Exception)e.fillInstackTrace().Exception引用可以处理Throwable异常,因此不需要标记该方法g()抛出Throwable异常.但是java编译器会强制我们这样做.谢谢.
Ste*_*n C 12
我对你的问题感到困惑.显然有一些你不理解的java异常/异常处理.所以让我们从头开始吧.
在java中,所有异常(在Java语言规范中使用该术语的意义上)是作为其子类的某个类的实例java.lang.Throwable.Throwable有两个(也就是两个)直接子类; 即java.lang.Exception和java.lang.Error.所有这些类的实例...包括Throwable和Error的实例......在JLS中称为异常.
异常处理程序捕获与catch声明中使用的异常类型兼容的异常(在JLS意义上).例如:
try {
....
} catch (Exception ex) {
...
}
Run Code Online (Sandbox Code Playgroud)
将捕获try块中抛出的任何异常,该块是java.lang.Exception直接或间接子类型的实例java.lang.Exception.但它不会捕获一个实例java.lang.Throwable,因为(显然)不是上述之一.
另一方面:
try {
....
} catch (Throwable ex) {
...
}
Run Code Online (Sandbox Code Playgroud)
将捕获一个实例java.lang.Throwable.
根据这一点回顾你的例子,很明显为什么该f方法没有捕获Throwable实例:它与catch子句中的异常类型不匹配!相比之下,在g方法中,Exception实例与catch子句中的异常类型匹配,因此被捕获.
我不明白你在说什么需要投掷一个Throwable g.首先,该方法声明它抛出Throwable的事实并不意味着它实际上需要抛出它.所有这一切都说它可能会抛出可分配给Throwable的东西...可能在该g方法的某个未来版本中.其次,如果你要添加throw e;到外catch块,这将是扔东西是分配给抛出.
最后,创建Throwable,Exception,Error和RuntimeException的实例通常是个坏主意.而且你需要非常小心何时以及如何抓住它们.例如:
try {
// throws an IOException if file is missing
InputStream is = new FileInputStream("someFile.txt");
// do other stuff
} catch (Exception ex) {
System.err.println("File not found");
// WRONG!!! We might have caught some completely unrelated exception;
// e.g. a NullPointerException, StackOverflowError,
}
Run Code Online (Sandbox Code Playgroud)
编辑 - 回应OP的评论:
但抛出e.fillInStackTrace(); 应该是一个可投掷的内容,而不是例外!
Javadoc特别指出返回的对象是您调用方法的异常对象.该fillInStacktrace()方法的目的是填充现有对象的堆栈跟踪.如果您想要一个不同的例外,您应该使用它new来创建一个.
实际上,我的意思是outter异常处理程序不应该捕获throw e.fillInStackTrace()抛出的Throwable.
我已经解释了它的原因 - 因为Throwable实际上是原始的Exception.有什么关于我的解释,你不理解或只是说你不喜欢Java的定义方式?
编辑2
如果outter异常处理程序可以处理Throwable异常,为什么我们必须指定方法g会抛出Throwable异常
你误解了我在说什么......如果你DID抛出一个异常,那就throws Throwable不会多余了.OTOH,我终于认为我了解你的抱怨.
我认为你抱怨的关键是你会遇到编译错误:
public void function() throws Exception {
try {
throw new Exception();
} catch (Exception ex) {
throw ex.fillInStackTrace();
// according to the static type checker, the above throws a Throwable
// which has to be caught, or declared as thrown. But we "know" that the
// exception cannot be anything other than an Exception.
}
}
Run Code Online (Sandbox Code Playgroud)
我可以看出这有些出乎意料.但是我害怕这是不可避免的.没有办法(对Java的类型系统没有重大改变)你可以声明fillInStacktrace在所有情况下都可以使用的签名.例如,如果您将方法的声明移动到Exception类,那么您只需要对Exception的子类型重复相同的问题.但是,如果您尝试使用泛型类型参数表达签名,则需要创建Throwable的所有子类显式泛型类型.
幸运的是,治愈非常简单; 施放结果fillInStacktrace()如下:
public void function() throws Exception {
try {
throw new Exception();
} catch (Exception ex) {
throw (Exception) (ex.fillInStackTrace());
}
}
Run Code Online (Sandbox Code Playgroud)
最后一点是应用程序显式调用是非常不寻常的fillInStacktrace().鉴于此,对于Java设计人员来说,试图解决这个问题并不值得"破坏他们的勇气".特别是因为它真的只是一个小小的不便......最多.
从问题2开始,回答问题实际上更容易.
您问:2.因为设计接收Exception引用的异常处理程序可以处理Throwable异常,所以不需要标记方法g()抛出Throwable异常.但是java编译器会强制我们这样做.
答:实际上,catch(例外e)无法捕获Throwable.试试这个:
try {
Throwable t = new Throwable();
throw t.fillInStackTrace();
} catch (Exception e) {
System.out.println("outer exception handler");
e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,你会看到catch子句没有捕获throw.
catch子句在你的g()方法中工作的原因是,当你调用时throw e.fillInStackTrace(),对fillInStackTrace的调用实际上会返回一个Exception(因为e本身就是一个Exception).由于Exception是Throwable的子类,因此不会与fillInStackTrace的声明相矛盾.
现在回答第一个问题
您问:1.由于Exception.fillInStackTrace()返回Throwable引用,接收Exception引用的异常处理程序不应该能够捕获异常.因为java不允许隐含向下转换,所以它应该像return(Exception)e. fillInstackTrace().
答:这不是一个隐含的向下倾斜.将此视为重载的变体.
让我们说你有
void process(Throwable t){
...
}
void process(Exception e){
...
}
Run Code Online (Sandbox Code Playgroud)
如果调用process(someObject),将在运行时确定是调用第一个还是第二个进程方法.类似地,catch(Exception e)子句是否可以捕获你的throw将在运行时根据你是抛出Exception还是Throwable来确定.
| 归档时间: |
|
| 查看次数: |
5825 次 |
| 最近记录: |