私は、Javaプログラムの短絡制御フロー構造として、チェックされていない例外を使用するように強く誘惑されています。ここの誰かがこの問題を処理するためのより良い、よりクリーンな方法について私にアドバイスしてくれることを願っています。
アイデアは、すべてのメソッド呼び出しで「停止」フラグをチェックすることなく、訪問者によるサブツリーの再帰的な探索を短縮したいということです。具体的には、抽象構文ツリーの訪問者を使用して制御フローグラフを作成しています。ASTのreturn
ステートメントは、サブツリーの探索を停止し、訪問者を最も近い囲んでいるif/thenまたはループブロックに戻す必要があります。
( XTCライブラリからの)Visitor
スーパークラスは次のように定義します
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
スーパークラスは例外(sでも)をキャッチしてラップRuntimeException
するため、例外のスローは実際には役に立ちません。enum
から型を返すという提案を実装しましたvisitReturnStatement
。幸いなことに、これは少数の場所(たとえばvisitCompoundStatement
)でチェックする必要があるだけなので、実際には例外をスローするよりも少し面倒ではありません。
一般的に、これはまだ有効な質問だと思います。おそらく、サードパーティのライブラリに縛られていない場合は、賢明な設計で問題全体を回避できます。