9

私は 2 つのコレクションと、いくつかの基準が満たされているかどうかに基づいて、これらのコレクションのいずれかに追加されるアイテムを持っています。

ややうっかりして、書くことが合法であるという事実に出くわしました

(test(foo) ? cOne : cTheOther).add(foo);

それ以外の

if (test(foo)) {
 cOne.add(foo);
} else {
 cTheOther.add(foo);
}

1つ目は私を賢く感じさせますが(常にプラスです)、長期的な可読性、保守性などについては確信が持てません.メソッドを変更する場所は 1 つになります (2 つではなく、条件演算子を介して switch ステートメントを実装している場合はおそらく多くの場所になります)。主な欠点は、それが当てはまらない場合に発生します (つまり、いくつかのケースにメソッド呼び出しを追加する必要があり、他のケースには追加しない場合)。

2 つの方法 (または他の解決策) の長所と短所は何ですか?

条件演算子を使用してメソッドを呼び出すオブジェクトを設定するこの特定のインスタンスが正しい選択であると思わない場合、それが妥当な場合はありますか?

4

9 に答える 9

29

より単純なコード スニペットは次のようになります。

SomeClass component = test(foo) ? cOne : cTheOther;
component.add(foo);

つまり、割り当てとその使用を分離します。

于 2010-01-25T15:27:17.170 に答える
5

例が賢いのと同じように、可読性と保守性は常に最も賢明なアイデアです。

条件演算子に関しては、最大 2 つの値のみを使用する必要があります。条件がその最大値を超えると、読み取り不能になる可能性があります。条件演算子は、さまざまな値を処理する標準的な方法ではありません。

于 2010-01-25T15:25:51.893 に答える
1

この目的で使用される条件演算子は非常にまれであるため、目で実際に探しているわけではありません。

私と将来のメンテナーが分岐や複雑すぎることなどを簡単に見つけられるように、Java コードが一貫しているように見えるのが好きです。

Python など、式を介して多くの「トリック」を行っている言語を使用している場合、それは別の話です。

于 2010-01-25T16:20:33.890 に答える
1

条件演算子の使用に関する潜在的な問題の 1 つは、引数がより複雑になり始めたときです。たとえば、次の行が NullPointerException をスローするとします。

String aString = obj1.getValue() == null ? obj2.getString() : obj1.getValue().getString();

3 つの逆参照のうちどれが NPE の原因ですか? obj1obj2またはobj1.getValue()前のコードの推論によって解決できる場合もありますが、常にそうとは限りません…</p>

とはいえ、次の 2 つのコードを比較してください。

final String aString = obj1 == null ? "default" : obj1.getString();

final String aString;
if (obj1 == null) {
  aString = "default";
} else {
  aString = obj1.getString();
}

ほとんどの人は、条件文の方が読みやすく、より簡潔であると主張するでしょう。

さて、それはさておき、条件を使用してメソッドを呼び出すでしょうか? いいえ、視覚的な複雑さが増します。また、デバッグはコードを記述するよりも 2 倍難しいことを覚えておく必要があります。つまり、コードが単純であればあるほど、あなたや他の誰かが 6 か月以内に理解できるようになるということです。受け入れられた回答で2行バージョンを使用していただければ幸いです。

于 2010-01-25T21:17:52.623 に答える
1

if ステートメントの各ブランチで関数を長時間呼び出すことには反対です。なぜなら、呼び出される関数が同じであることが偶然であるかどうかが常に明確であるとは限らず、呼び出された関数を変更する必要がある場合は 2 つの場所を変更する必要があるからです。関数 (わかりました、「追加」は簡単なケースです)。そのため、通常は正しいオブジェクトを変数に割り当てますが (通常は if ステートメントで、通常は他にもいくつかの処理が行われます)、一般的なコードはすべて条件の外側に引き出します。

于 2010-01-25T16:02:54.590 に答える
1

私の好みの方法は次のとおりです。

final boolean    result;
final Collection c;

result = test(foo);

if(result)
{
    c = cOne;;
} 
else 
{
    c = cOther;;
}

c.add(foo);

まず、次の 2 つの理由から、呼び出しを行って一時変数に値を割り当てない (test(foo) 呼び出し) ことは好きではありません。

  1. デバッグが簡単です(System.out.println、またはデバッガーでさえ-メソッドに副作用がある場合、デバッガーでそれを見るだけで再度呼び出されるため、副作用が発生します)。
  2. 副作用がなくても、コードをより効率的にするために複数回呼び出すことを思いとどまらせます。コンパイラ/ホットスポットは、不要な一時変数の削除に対処する必要があります。

第二に、目をぼかすと同じように見えるコードが好きではありません。cOne.add(foo) と cOther.add(foo) を同じように「見える」ようにすると、目を「ぼかす」ことができます。たとえば、リストに変更し、add(E) の代わりに add(int, E) を使用している場合、コードを変更する場所は 1 か所しかないため、間違いを犯す変更が少なくなります (cOne.add など)。 (1, foo) と cOther.add(2, foo) の両方を add(1, foo)) にする必要があります。

編集(コメントに基づく)

いくつかの選択肢がありますが、コードのレイアウト方法によって異なります。私はおそらく次のようなものに行きます:

private Collection<Whatever> chooseCollection(final Whatever             foo,
                                              final Collection<Whatever> a,
                                              final Collection<Whatever> b)
{
    final boolean              result;
    final Collection<Whatever> c;

    result = test(foo);

    // could use a conditional - I just hate using them
    if(result)
    {
        c = a;
    }
    else
    {
        c = b;
    }

    return (c);
}

そして、次のようなものがあります:

for(......)
{
    final Collection<Whatever> c;
    final Whatever             foo;

    foo = ...;
    c = chooseCollection(foo, cOne, cOther);
    c.add(foo;
}

基本的に、私は { } ブロック内の何かに対して、それが理にかなっている場合 (そして通常はそうです) のメソッドを作成します。小さなメソッドがたくさんあるのが好きです。

于 2010-01-25T17:17:54.747 に答える
0

私は最初のもの(またはマットによる中間ソリューション)を好みます。ただ短いです。プロジェクトで条件演算子がかなり頻繁に使用されると、人々はそれに慣れ、「読みやすさ」が向上します。

言い換えれば、Perlに慣れている場合は、簡単に読むことができます。

于 2010-01-25T15:35:41.160 に答える
0

matt b の発言に加えて、条件演算子を使用する場合は、さらに一歩進んでこの形式を使用できます。

SomeClass component = test(foo) 
   ? cOne 
   : cTheOther;
component.add(foo);

これにより、コードが if-else のようになり、読みやすくなります。

于 2010-01-25T18:40:12.823 に答える
0

IMHO「フル」の長いバージョンは、もう少し読みやすく、長期的なメンテナンスには間違いなく優れています。

于 2010-01-25T15:25:56.013 に答える