10

私は、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 ) { }
}

これはすべて正常に機能しますが、次の場合を除きます。

  1. 私はどこかで捕まえるのを忘れるかもしれReturnExceptionません、そしてコンパイラは私に警告しません。
  2. 汚れた感じがします。

これを行うためのより良い方法はありますか?この種の非ローカル制御フローを実装するために私が気付いていないJavaパターンはありますか?

[更新]この特定の例はやや無効であることが判明しました。Visitorスーパークラスは例外(sでも)をキャッチしてラップRuntimeExceptionするため、例外のスローは実際には役に立ちません。enumから型を返すという提案を実装しましたvisitReturnStatement。幸いなことに、これは少数の場所(たとえばvisitCompoundStatement)でチェックする必要があるだけなので、実際には例外をスローするよりも少し面倒ではありません。

一般的に、これはまだ有効な質問だと思います。おそらく、サードパーティのライブラリに縛られていない場合は、賢明な設計で問題全体を回避できます。

4

7 に答える 7

4

これはいくつかの理由で合理的なアプローチだと思います。

  • サードパーティを使用していて、チェックされた例外を追加できません
  • 少数の訪問者だけが必要なときに、多数の訪問者のどこでも戻り値をチェックすることは、不必要な負担です。

また、チェックされていない例外はそれほど悪いものではないと主張する人もいます。あなたの使用法は、長時間実行されているバックグラウンドタスクを吹き飛ばすために使用されるEclipseのOperationCanceledExceptionを思い出させます。

完璧ではありませんが、十分に文書化されていれば、私には問題ないようです。

于 2008-12-15T19:56:42.893 に答える
0

値を返すだけではない理由はありますか?本当に何も返したくない場合は、NULLなど。これははるかに簡単で、チェックされていないランタイム例外をスローするリスクはありません。

于 2008-12-15T19:35:57.880 に答える
0

次のオプションが表示されます。

  1. 先に進んで、そのRuntimeExceptionサブクラスを定義してください。最も一般的な呼び出しで例外をキャッチし、dispatchそこまで到達した場合はその例外を報告することで、深刻な問題をチェックします。
  2. 検索が突然終了する必要があると判断した場合、ノード処理コードが特別なオブジェクトを返すようにします。これでも、例外をキャッチする代わりに戻り値をチェックする必要がありますが、その方がコードの見栄えが良いかもしれません。
  3. ツリー ウォークが何らかの外部要因によって停止される場合は、すべてサブスレッド内で実行し、そのオブジェクトに同期フィールドを設定して、スレッドに途中で停止するように指示します。
于 2008-12-15T19:47:44.237 に答える
0

XTC の Visitor を使用する必要がありますか? これは非常に単純なインターフェースであり、必要に応じてキャッチすることを忘れない、チェック済みの ReturnExceptionをスローできる独自のインターフェースを実装できます。

于 2008-12-15T20:46:49.920 に答える
0

訪問者から値を返すのはなぜですか? 訪問者の適切なメソッドは、訪問されているクラスによって呼び出されます。行われたすべての作業は、ビジター クラス自体にカプセル化されます。何も返さず、独自のエラーを処理する必要があります。呼び出しクラスに必要な義務は、適切な visitXXX メソッドを呼び出すことだけです。(これは、タイプごとに同じ visit() メソッドをオーバーライドするのではなく、例のようにオーバーロードされたメソッドを使用していることを前提としています)。

訪問されたクラスは、訪問者によって変更されるべきではありません。また、訪問の発生を許可する以外に、それが何をするかについての知識を持っている必要もありません。値を返すか、例外をスローすると、これに違反します。

訪問者パターン

于 2008-12-15T20:11:13.847 に答える
0

あなたが言及したXTCライブラリを使用していません。accept(visitor)訪問者パターンの補完的な部分であるノードのメソッドをどのように提供しますか? これがリフレクション ベースのディスパッチャであるとしても、構文ツリーの再帰を処理する何かがまだあるはずですか?

この構造的な反復コードに簡単にアクセスでき、メソッドからの戻り値をまだ使用していない場合、子ノードに再帰しないようvisitXxx(node)に指示する単純な列挙型の戻り値またはブール値フラグを利用できますか?accept(visitor)

もしも:

  • accept(visitor)ノードによって明示的に実装されていない (いくつかのフィールドまたはアクセサーのリフレクションが進行中か、ノードが標準の制御フロー ロジックまたはその他の理由で子を取得するインターフェイスを実装しているだけです...)、および

  • ライブラリの構造的な反復部分をいじりたくない、または利用できない、または努力する価値がない...

最後の手段として、バニラ XTC ライブラリを使用している間は、例外が唯一のオプションである可能性があると思います。

興味深い問題ですが、例外ベースの制御フローが汚いと感じる理由は理解できます...

于 2008-12-15T22:04:05.710 に答える