我很有诱惑力使用未经检查的异常作为Java程序中的短路控制流构造.我希望有人能以更好,更清洁的方式告诉我这个问题.
我的想法是,我希望减少访问者对子树的递归探索,而不必在每个方法调用中检查"停止"标志.具体来说,我正在使用抽象语法树上的访问者构建控制流图.return
AST中的语句应该停止对子树的探索,并将访问者发送回最近的封闭if/then或循环块.
的Visitor
超类(从XTC库)定义
Object dispatch(Node n)
通过表单的反射方法回调
Object visitNodeSubtype(Node n)
dispatch
没有声明抛出任何异常,所以我声明了一个扩展的私有类 RuntimeException
private static class ReturnException extends RuntimeException { }
现在,return语句的visitor方法看起来像
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
),所以实际上比抛出异常要麻烦一点.
总的来说,我认为这仍然是一个有效的问题.虽然也许,如果你不依赖第三方库,可以通过合理的设计避免整个问题.