为什么例外。fillInStackTrace返回抛出?
-
19-09-2019 - |
题
我觉得异常。fillInStackTrace应的回报的异常或衍生出异常的对象。考虑到两个职能如下,
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();
}
}
- 的
exception handler
不可能赶上new Throwable()
在第一个函数f()
. - 的
exception handler
可以赶上的e.fillInstackTrace()
在第二个函数g()
. - 但第二个函数
g()
仍然需要throws Throwable
.这真的是奇怪的,因为我们能赶上e.fillInstackTrace()
.
所以我的问题是,为什么不例外。fillInStackTrace回报的异常或例外的来源,而不是发展这样一个奇怪法?
编辑:
要 澄清 我的问题:我的意思是"怪的语法"的
- 由于
Exception.fillInStackTrace()
返回Throwable
参考,例外处理其收到Exception
应当参考不能够赶上的例外。因为java不允许implict垂头丧气,它应该是这样的return (Exception)e.fillInstackTrace()
. - 由于它的设计,例外处理程序接收的
Exception
参考可以处理Throwable
例外的是,没有需要标记的方法g()
抛Throwable
例外。但java编译器将强制执行我们这样做。
谢谢。
解决方案
它实际上是容易回答你的问题开始与问题2。
你问:2.由于它的设计,例外处理程序接收的异常引用可以处理的抛出的例外,没有需要标记的方法克()throws抛出的例外。但java编译器将强制执行我们这样做。
回答:实际上,抓(例外e)无法赶上抛出.试试这个:
try {
Throwable t = new Throwable();
throw t.fillInStackTrace();
} catch (Exception e) {
System.out.println("outer exception handler");
e.printStackTrace();
}
你会看到的赶条款并未赶上扔在这种情况。
原因的捉条款的工作在你g()方法是,当你调用 throw e.fillInStackTrace()
, ,呼吁fillInStackTrace实际上返回一个例外(这是因为e是一个例外本身)。由于异常的子抛出,这并不违背《宣言》的fillInStackTrace.
现在对第一个问题
你问:1.由于例外。fillInStackTrace()返回抛出的参考,例外处理其收到的例外应当参考不能够赶上的例外。因为java不允许implict垂头丧气,它应该是这样的返回(例外)e。fillInstackTrace().
回答:这不正是一个隐含的垂头丧气。认为这是一个变化的过载。
让我们说你有
void process(Throwable t){
...
}
void process(Exception e){
...
}
如果你打电话 process(someObject)
, 它将在运行时确定是否具有第一或第二工艺方法被称为。同样,是否抓住(例外e)条款可以赶上你扔将在运行时确定,基于是否你扔一个异常或抛出.
其他提示
我很疑惑你的问题。还有清楚的东西有关java例外/例外处理,你不理解。所以让我们从头开始。
在爪哇,所有例外情况(在这个意义上,用这个术语是在爪哇语言的规范)的情况的某些类子类的 java.lang.Throwable
.有两个(并且只有两个)直接的子抛出;即 java.lang.Exception
和 java.lang.Error
.实例,所有这些类...包括抛出的实例和错误...被称为例外,在捷尔思.
一个例外处理程序渔获物的例外(在捷尔思义),被分配兼容的例外类型中使用的 catch
《宣言》。所以,例如:
try {
....
} catch (Exception ex) {
...
}
将捕获的任何例外扔的 try
方框,是一个实例 java.lang.Exception
或者直接或间接的子类型的 java.lang.Exception
.但它不会赶上的一个实例 java.lang.Throwable
, 因为这是(显然)不上述之一。
在另一方面:
try {
....
} catch (Throwable ex) {
...
}
将 抓住的一个实例 java.lang.Throwable
.
审查您的例子,在此,很明显为什么 f
方法不是追赶抛出的实例:它不匹配的异常类型的捕条款!相比之下,在该 g
方法的异常实例的例外类型的捕条款,并因此被捕。
我不明白你在说什么关于需要扔一个抛出在 g
.首先,事实上,该法宣布,它将引发抛出 不不 意思是,这实际上需要把它扔了。所有这说的是它 可能会 扔东西可分配给抛出...可能在未来的某一版本 g
法。其次,如果你要加入 throw e;
外赶块, 会 可以扔的东西是可分配给抛出.
最后,它通常是一个糟糕的想法是创建的实例抛出的、例外、错误和异常.你必须非常小心,何时以及如何赶上他们。例如:
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,
}
编辑 -在响应运的评论:
但我扔扔e。fillInStackTrace();应该是一个Intance的抛出,不例外!
对如果是的话,为什么不试说,具体而言,返回的对象是异常对象你打电话的方法。目的 fillInStacktrace()
方法是填写这堆跟踪现有的对象。如果你想要一个不同的例外,应该使用 new
创建一个。
实际上,我的意思是外的例外处理程序不应该抓住抛出扔扔e。fillInStackTrace().
我已经解释了为什么它不-因为抛出的实际上是原来的例外。是不是有什么有关我的解释,你不了解或者是你只是说你不喜欢的方式,Java定义?
编辑2
如果该外的例外处理程序可以处理的抛出的例外,为什么我们必须指定方法克会抛抛出异常
你误解了我是说...这是如果你有没有扔一个例外,那么 throws Throwable
不会是多余的。另一方面,我最后想我明白您的投诉。
我认为,关键在您的投诉是,你会得到一个编辑错误:
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.
}
}
我可以看到,这是有点意外。但这是不可避免的我很害怕。有没有办法(短的一个重大改变Java的类型系统),可以声明的签名 fillInStacktrace
这将工作在所有情况。例如,如果移动《宣言》的方法的异常类,你会只是重复相同的问题与亚型的例外。但如果你试图表达的签名,使用一般类型参数,它将意味着使所有亚类的抛出明确的通用类型。
幸运的是,治疗是真的很简单;投的结果 fillInStacktrace()
如下:
public void function() throws Exception {
try {
throw new Exception();
} catch (Exception ex) {
throw (Exception) (ex.fillInStackTrace());
}
}
以及最后一点是,它是非常不寻常的应用程序明确地呼叫 fillInStacktrace()
.鉴此,它将根本就没有值得Java的设计师有"打掉他们的胆量",试图解决这个问题。特别是因为它是真的只有一个小小的不便...在大多数。
我想你得问弗兰克喊(的 @author
的 java.lang.Exception
).正如其他人所说的那样, fillInStackTrace()
宣布 Throwable
和记录返回 this
, ,使其返回的类型必须 Throwable
.它只是继承的 Exception
.弗兰克可能拥有复盖它 Exception
, 像这样的:
public class Exception extends Throwable{
/**Narrows the type of the overridden method*/
@Override
public synchronized Exception fillInStackTrace() {
super.fillInStackTrace();
return this;
}
}
...但他没有。前Java1.5,原因是它会产生一个编辑错误。在1.5及以后,协变回归类型 都是允许的 和以上是合法的。
但是我的猜测是,如果上述复盖的存在,你会然后可以问为什么 RuntimeException
没有一个类似的复盖,为什么 ArrayStoreException
没有复盖该复盖,等等。因此弗兰克和朋友可能只是不想写那些数以百计的相同复盖。
值得注意的是,如果你处理你自己的定义的异常类,可以很容易地复盖 fillinStackTrace()
方法,因为我已经做了以上,并得到较窄的类型你之后。
使用仿制药,可以想象一下增加的声明 Throwable
为:
public class Throwable<T extends Throwable<T>>{
public synchronized native T fillInStackTrace();
}
...但是这不是真的令人满意,原因是超出范围的这种答案。
fillInStackTrace
返回的参考相同的对象。它的方法链接到允许再扔 Exception
和重置异常的堆踪。
public static void m() {
throw new RuntimeException();
}
public static void main(String[] args) throws Throwable {
try {
m();
} catch (Exception e) {
e.printStackTrace();
throw e.fillInStackTrace();
}
}
该方法返回型只能基本类型是 Throwable
.它可以generified这样的方法返回的参数化的类型。但是,情况并非如此。
RuntimeException e = new RuntimeException();
Throwable e1 = e.fillInStackTrace();
System.out.println(e1.getClass().getName()); //prints java.lang.RuntimeException
System.out.println(e == e1); //prints true
fillInStackTrace()
定义 Throwable
, ,不 Exception
.
不是所有亚类的 Throwable
例外情况(Error
, 为例)。尽 Throwable
感到关切的是,唯一可以保证有关返回的价值 fillInStackTrace()
是,它是一个实例 Throwable
(因为它只是返回同一目的,作为 Chandra Patni 注意到).
实际上 fillInStackTrace
返回同一目的是援引。
e.fillInStackTrace == e
总是真实的
这只是一个 快捷方式, 你也可以写信
} catch (Exception e) {
System.out.println("inner exception handler");
e.fillInStackTrace();
throw e;
}
或者使用一个铸造
throw (Exception) e.fillInStackTrace();
顺便说一句,情况与此相同 initCause()
.