1

私は大規模なコードベースを持っており、そこには多くのインスタンスがあります

try {
   // attempt to do something important
} catch (Exception e) {
   // do something lame
}

アンチパターン。約700インスタンス。魔法のように、そしてまとめて、これらすべてを特殊なキャッチブロックの次の層に置き換えることができるツール(たとえば、IDEなど)があるかどうか疑問に思っています。以下に示す方法で、IntelliJまたはEclipseの「try/catchでラップ」するのと同様のマスリファクタリングを適用するもの。注:700個すべてが既知であると言っているわけではありませんIOException。これは、特定の場合にスローされる唯一の例外タイプが)であると想定した単なる例IOExceptionです。

私が探しているリファクタリングは、try{}IntelliJ/Eclipseが「catchでラップ」または「throws句に追加」クイックフィックスを提供するために行うのと同じブロックのセマンティック分析を行うものです。

try {
   // attempt to do something important
   // where an IOException is thrown
} catch (IOException e) {
   // still do something lame
}

私はこれが問題を「修正」しないことを理解していますが、それは考古学の段階的な手動ビットを節約します。

アイデア?

一般的な例外キャッチアンチパターンの検出に関する関連質問。

4

2 に答える 2

2

私はあなたがしようとしていることをするためのツールは存在しないと思います。次のアルゴリズムを考えることはできますが、スクリプトで自動化するには時間がかかる場合があります...スクリプトを作成するのに、手動で変更を加えるのと同じくらいの時間がかかる場合もあります。

  1. 新しい例外を定義する

class NeverThrown extends RuntimeException {}

  1. グローバルcatch (Exception e)置換catch (NeverThrown e)

  2. すべてのファイルをコンパイルする

  3. 発生するたびにunreported exception .... must be caught...、例外を特定し、catchまだ追加されていない場合は次のブロックに追加します。たとえば、次のように置き換えますcatch (NeverThrown e)catch (NeverThrown, IOException e)

  4. 出現するすべてのNeverThrown,クラスを削除し、クラス定義を削除します。

もちろん、より大きな知的努力は、「何か足りない」のではなく、何をすべきかを決定することです。まとめて行うことはできませんので、それぞれのケースを個別に検査する必要があります。もし私があなたなら、ステップ3で停止し、報告されたキャッチされなかった各例外を処理する方法を見つけようとしてエラーを調べます。

または、チェックされた例外を完全に非難し、すべてのtryブロックとcatchブロックを削除して、throws Exception各メソッドの後に追加することもできます:)

于 2012-03-28T20:44:55.143 に答える
2

問題は次のとおりです。

フォームのすべてのブロックを検索します。

 try { ... }
 catch (Exception e) { ... }

 try { ... }
 catch ( T1 e ) { ... }
 ....
 catch ( Tn e ) { ... }

すべてのT1、... Tn e、コード変更を実行できるプログラム変換システム、およびスローされた例外についての理由は、解決策のようです。

Javaフロントエンドを備えたDMSソフトウェアリエンジニアリングツールキットがこれを行う可能性があります。

メインブロック内からスローされた一連の例外を計算できるアナライザーが必要です。これらの例外をオブジェクト階層に従って分類することもできます。TmがTnの特殊化である場合、ネストされた試行としてTmおよびTnのハンドラーを生成することができます。DMSは完全な型分析を備えているため、コード内の型を判別し、コードブロックによってスローされます。例外のオブジェクト階層を計算するには、カスタムDMSコードを作成する必要があります。

コールグラフが必要なので、コールグラフで見つかった例外をtryサイトに伝播できます。それはありますが、Java1.7ではいくつかの作業が必要です。

コードを改訂するには、変換アプライヤーが必要です。一般的なケースを処理するには、連鎖キャッチについて心配する必要があると思います。DMSを使用すると、次のようになります。

rule specialize_catch(b_try: block,
      E: qualifed_identifer, e: IDENTIFIER, b_recover: block,
      c_pre: catches, c_post: catches):
   statement -> statement
 " try { \b_try } 
   \c_pre
   catch ( \E \e ) { \b_recover }
   \c_post "
 -> 
  " try { \b_try }
    \c_pre 
    catch ( \least_specialized\(\E\,\b_try\,\c_pre\) \e ) { \b_recover }
    catch ( \E e ) { \b_recover }
    \c_post "
    if exists_specialized_exception(E,b_try,c_pre);

変換される構文は、* meta * quotes "..."のコードであり、書き換えルールの構文から分離します。書き換えルールにはいくつかの部分があります。名前を指定します(多くの場合、数百になります)。これは、ターゲット言語(この場合はJava)で特定の名前付き構文形式を表し、メタクオーツおよびエスケープ(バックスラッシュ)形式以外の裸の形式で記述された名前付きプレースホルダー(b_try、E、b_recover、...)のセットを提供します。メタクオーツの内部。c_preは、一連のcatchコンストラクトの名前です。これを行うことができるのは、「キャッチ」が抽象で連想リストを形成するためであり、c_postについても同様です。これは、カスタムDMS機構を呼び出して結果(ブール値または新しい構文[ツリー])を計算できるメタ関数呼び出し(たとえば、least_specialized、exists_specialized_exception)を提供します。君' メタ関数呼び出しのleast_specializedには、Java言語の一部ではないため、メタ関数呼び出しの構文(コンマや括弧など)がエスケープされていることに注意してください。Javaコードの外部では、このようなメタ関数呼び出しはエスケープする必要はありません。そして最も重要なのは、左側(「これに一致」、メタ変数をバインド)と右側(ルール条件が真の場合は「これで置換」)があることです。

メタ関数least_specializedとexists_specializedは、メインコードブロックb_tryがスローする可能性のある例外、既存のキャッチc_preによって処理される例外、現在の例外タイプE、c_preより上およびEより下の最も一般的な例外、および新しいキャッチを計算します。ブロックが挿入されます。存在しない場合、ifは失敗し、例外の挿入は行われません。複製されたb_recoverブロックのクローンを削除するために、追加の変換が必要になる場合があります。

私は明らかにこれを実装しておらず、完全に考え抜いていない可能性があります。しかし、私はこれを可能な解決策への道として見ることができます。YMMV。

700のインスタンスの場合、DMSでこれを行うのはおそらくかなり限界です。個人的に1つあたり10分(編集、コンパイル、おっと...)かかった場合、それは7000分または~~ 100時間、約2週間です。これをこれほど速く実行するようにDMSを構成できるとは思えません。特に、これまでに実行したことがない場合はなおさらです。(私の会社には専門家のDMSユーザーがいますが、これは実行可能な時間枠である可能性があります)。

しかし、主張は、ツールが存在する可能性が高いということです。

于 2012-03-28T22:38:58.730 に答える