我非常想在 Java 程序中使用未经检查的异常作为短路控制流结构。我希望这里有人可以建议我以更好,更清洁的方式来处理这个问题。
这个想法是我想缩短访问者对子树的递归探索,而不必在每个方法调用中检查“停止”标志。具体来说,我正在使用抽象语法树上的访问者构建控制流图。AST 中的一条return
语句应该停止对子树的探索,并将访问者发送回最近的封闭 if/then 或循环块。
超Visitor
类(来自XTC 库)定义
Object dispatch(Node n)
通过形式的反射方法回调
Object visitNodeSubtype(Node n)
dispatch
没有声明抛出任何异常,所以我声明了一个扩展的私有类RuntimeException
private static class ReturnException extends RuntimeException {
}
现在,return 语句的访问者方法看起来像
Object visitReturnStatement(Node n) {
// handle return value assignment...
// add flow edge to exit node...
throw new ReturnException();
}
每个复合语句都需要处理ReturnException
Object visitIfElseStatement(Node n) {
Node test = n.getChild(0);
Node ifPart = n.getChild(1);
Node elsePart = n.getChild(2);
// add flow edges to if/else...
try{ dispatch(ifPart); } catch( ReturnException e ) { }
try{ dispatch(elsePart); } catch( ReturnException e ) { }
}
这一切都很好,除了:
- 我可能会忘记在
ReturnException
某个地方捕获,编译器不会警告我。 - 我觉得脏。
有一个更好的方法吗?是否有一种我不知道的 Java 模式来实现这种非本地控制流?
[更新] 这个特定的例子有些无效:Visitor
超类捕获并包装异常(甚至RuntimeException
s),所以抛出异常并没有真正的帮助。我已经实施了enum
从visitReturnStatement
. 幸运的是,这只需要在少数地方进行检查(例如,visitCompoundStatement
),因此它实际上比抛出异常要少一些麻烦。
总的来说,我认为这仍然是一个有效的问题。虽然也许,如果您不依赖于第三方库,则可以通过明智的设计避免整个问题。