[英]Why does Throwable.getCause check to see if 'cause' is 'this' before returning `null` instead of just returning the cause directly?
I had a reason to go into the source code for Throwable.getCause
today and was a little surprised to see this code in that method:今天我有理由进入
Throwable.getCause
的源代码,并且在该方法中看到此代码时有点惊讶:
public synchronized Throwable getCause() {
return (cause==this ? null : cause);
}
This is from Java 1.8, but it looks the same in the later versions I've looked at.这是来自 Java 1.8,但在我看过的更高版本中看起来相同。
My question is: why not simply return cause
and be done with it?我的问题是:为什么不简单地
return cause
并完成它?
It isn't comparing cause
to null
, it's comparing cause
to this
.它不是将
cause
与null
进行比较,而是将cause
与this
进行比较。 To avoid circles, if cause
is this
, it returns null.为避免循环,如果
cause
是this
,则返回 null。
The code:编码:
public synchronized Throwable getCause() {
return (cause==this ? null : cause);
}
Says if the cause
is this
return null
otherwise return cause
(which may also be null
as it happens.说如果
cause
是this
返回null
否则返回cause
(它也可能是null
因为它发生。
The story starts with this: private Throwable cause = this;
故事是这样开始的:
private Throwable cause = this;
which is I believe the same in all versions >=1.4.我相信所有版本>=1.4 都是一样的。 That initialises the cause to being this object!
这将原因初始化为这个对象!
The intention is that Throwable
objects are immutable but it provides a method void initCause(Throwable cause)
that can only be called once to initialise the cause or cause initialised by a constructor.目的是
Throwable
对象是不可变的,但它提供了一个方法void initCause(Throwable cause)
只能调用一次来初始化原因或由构造函数初始化的原因。
As the documentation explains that allows the chaining of causes to sub-classes added before cause
was introduced that don't include it in one of their constructors.正如文档所解释的那样,允许将原因链接到在引入
cause
之前添加的子类,这些子类不包含在其构造函数之一中。
So the class somehow wants to know if initCause
has been called and throws IllegalStateException
if it has (my comments):因此,该类以某种方式想知道是否已调用
initCause
并抛出IllegalStateException
如果有)(我的评论):
public Throwable initCause(Throwable cause) {
if (cause == this) //Illogical! An exception can't be self caused!
throw new IllegalArgumentException();
if (this.cause != this)// false if cause has been initialised 'properly'.
throw new IllegalStateException();
this.cause = cause;
return this;
}
The class is using cause==this
to indicate cause
not set.该类使用
cause==this
来指示未设置cause
。 It can't use cause==null
because null
is a valid value.它不能使用
cause==null
因为null
是一个有效值。 So it uses the anomalous state of cause==this
because actively setting cause
to this
is the illogical state of a self-caused exception.所以它使用了
cause==this
的异常状态,因为主动设置cause
到this
是自引发异常的不合逻辑状态。
It works, sure.它确实有效。 But is it really a good idea?
但这真的是个好主意吗? I'm saying not.
我说不是。 It conflates the states of "cause not set" and "cause has been set and is set to
null
".它将“原因未设置”和“原因已设置并设置为
null
”的状态混为一谈。 A less contorted design just introduces a flag private boolean isCauseSet=false;
一个不太扭曲的设计只是引入了一个标志
private boolean isCauseSet=false;
and setting it if initCause
is ever called or a constructor that sets it is called.并在
initCause
被调用或设置它的构造函数被调用时设置它。
The convoluted code we see in Throwable
achieves nothing more than avoiding a boolean
.我们在
Throwable
看到的复杂代码只不过是避免了boolean
。 Saving a single boolean
field inside Throwable
really doesn't seem worth the bother.在
Throwable
保存单个boolean
字段似乎真的不值得打扰。 No useful application will ever have so many Throwable
objects in circulation for it to matter.没有任何有用的应用程序会在流通中拥有如此多的
Throwable
对象,因此它很重要。
该null
值由printStackTrace
方法使用, 例如,在调用stackTraceString
方法时,第 421..450行标识堆栈跟踪的输出应何时完成。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.