雖然JVM是一種基於棧的引擎,但Java語言沒有真正提供訪問棧的方式。即使在某些很少的情況下,這樣做很有用。
一個例子
方法的result值放在了棧裏面。如果你看下面的例子:
public int method() {
if (something)
return 1;
...
if (somethingElse)
return 2;
...
return 0;
}
如果我們忽略中止異常,錯誤處理和其他學術性的討論。我們能說上面這個方法“肯定”會返回1,2或0。並且這個值在跳出方法之前就放到了棧裏面。
現在,有時只是當一個給定的值返回時, 它可能是一個採取某些操作的用例。人們可能被誘騙進了老式的關於多重返回語句是否邪惡的網絡論戰並且整個方法應該如下:
public int method() {
int result = 0;
if (something)
result = 1;
...
if (somethingElse)
result = 2;
...
// return之前的重要事件
if (result == 1337)
log.info("hehehe ;-)");
return result;
}
當然,上面的例子是錯誤的。因爲,”if (something) return 1“和”if (something) return 2” 語句會立即中斷方法執行。爲了完成相同的“單一返回語句”技術,我們得這樣重寫代碼:
public int method() {
int result = 0;
if (something)
result = 1;
else {
...
if (somethingElse)
result = 2;
else {
...
}
}
// return之前的重要事件
if (result == 1337)
log.info("hehehe ;-)");
return result;
}
從棧裏面訪問返回值
我們真正想做的是用我們原始的實現在return之前查看棧裏面都有什麼值。比如,會返回什麼值。下面是僞Java代碼:
public int method() {
try {
if (something)
return 1;
...
if (somethingElse)
return 2;
...
return 0;
}
// Important action here prior to return
finally {
if (reflectionMagic.methodResult == 1337)
log.info("hehehe ;-)");
}
}
好消息是:是的,我們能。這裏有一個簡單的竅門來完成上述功能。
public int method() {
int result = 0;
try {
if (something)
return result = 1;
...
if (somethingElse)
return result = 2;
...
return result = 0;
}
// returnp之前的重要事件
finally {
if (result == 1337)
log.info("hehehe ;-)");
}
}
壞消息是:你必須永遠不能忘記給result賦值。當Java語言不允許你這樣做的時候,這個技術偶爾對訪問方法棧非常有用。
當然
當然你也能依靠這個無聊的解決方案:
public int method() {
int result = actualMethod();
if (result == 1337)
log.info("hehehe ;-)");
return result;
}
public int actualMethod() {
if (something)
return result = 1;
...
if (somethingElse)
return result = 2;
...
return result = 0;
}
並且可能在大多數情況下,這種技術的確更好(可讀性更好)。但是有時,你想要在finally代碼塊裏做更多事情而不僅僅是記錄日誌的話,或許你不想重構這個方法而你想要訪問的不僅是返回值。