以下只是伪代码。
function x(node){
if(node.val == 42)
return true; // What if I throw an exception here ?
val1 = node.left ? x(node.left) : false ;
val2 = node.right ? x(node.right): false;
return val1 || val2 ;
}
让我们说我试图在树上找到42。使用上面的代码,如果我返回一个有效值,它将冒泡到整个递归链,然后最终返回。
我的假设是,如果我只是抛出异常而不是在第3行返回true,它实际上不会通过递归链冒出来并直接返回给调用者。
抛出一个Exception来打破整个链条是一个好习惯。因为我们在line 4
说,它确实在一些嵌套堆栈中找到了42,它仍然会在line 5
上追求递归。如果我只是在line 3
抛出一个异常,我们可以避免那种不必要的计算。
问题更多的是编译器内部,如果我只抛出一个未处理的异常,它是否仍会冒泡到递归堆栈(这使得这种方法毫无意义)或直接返回到父调用的程序计数器。
出于几个不同的原因,我不建议抛出异常来打破递归链。
finally
块或try
-with-resources语句,跟踪对象引用对于垃圾收集目的等,仍然需要遍历调用堆栈,就像在调用链中返回值一样,并且几乎肯定不会比更标准的方法更快。if (myCall()) {...}
那样做,而是需要有单独的分支,一个用于调用正常返回值的一个分支,另一个用于抛出它的情况。如果他们忘记这样做,运行时的代码可能会因为异常而失败,而事实上它实际上是按预期运行的。更糟糕的是,你实际上会颠倒异常的正常使用。如果你的代码在成功时抛出异常并在失败时返回一个值,那么读取你的代码的人可能会变成“嗯?”弄清楚你的意思之前至少一次。虽然你最初的问题主要是关于效率问题,但我认为其他两点 - 可用性和清晰度 - 仍然强烈反对不以这种方式做事。