web-dev-qa-db-ja.com

パラメータ「foo」は割り当てるべきではありません-何が害ですか?

この方法を比較してください:

void doStuff(String val) {
    if (val == null) {
        val = DEFAULT_VALUE;
    }

    // lots of complex processing on val
}

...このメソッドに:

void doStuff(String origVal) {
    String val = origVal;
    if (val == null) {
        val = DEFAULT_VALUE;
    }

    // lots of complex processing on val
}

前者の方法の場合、Eclipseは「パラメーター 'val'を割り当てるべきではありません」という警告を発します。どうして?

私の目には、前者の方がきれいです。一つには、それは私にtwovalの良い名前を思い付くように強制しません(1つの良い名前を思い付くのは十分に難しいです)。

(注:囲んでいるクラスにvalという名前のフィールドがないと仮定します。)

30
Matt McHenry

ここで誰もがcurmudgeonのケースを作ったようには見えません。

私は通常、パラメーターを変更しません。実際、明示的に禁止するために、パラメーターにfinalのマークを付ける傾向があります。いくつかの理由:

  • パラメータへの割り当ては、「出力パラメータ」として使用しようとすると混同される可能性があります、参照: javapractices.com 、そして明快さがすべてです

  • Favor Immutability、そしてそれは他の何よりもパラメータ値に当てはまります。プリミティブは同じことの単なる退化したケースであり、(一般的に)不変変数について推論する方が簡単です。参照、 有効Javaアイテム1 、または javapractices.com

  • そして最後に(NPI)、finalを自由に使用しますjavapractices.com 。パラメータシグニチャに含まれている可能性がありますが、予期しないエラーを識別する傾向があり、変更可能な変数が強調表示されます。これは通常、例外です。ほとんどのコードのほとんどの可変変数は、怠惰またはパフォーマンスに何らかの影響があるという認識のためにあります。慎重に選択され、不変で、名前の付いた中間計算がより明確で、読みやすく、検証しやすく、パフォーマンスのためにきれいに最適化できます。あなたの助けなしで。

私は要約であなたの特定のケースに賢く話すことはできませんが、私が違ったやり方でするかもしれない他のすべてのことを除けば、私は好むでしょう:

void doStuff(final String origVal)
{
    final String valOrDefault = (origVal == null) ? DEFAULT_VALUE : origVal;
    //lots of complex processing on valOrDefault 
}

または(引数が1つしかない実際のメソッドでnull値を処理しないと仮定すると、より複雑なものの一部である必要があります)...また、一般に、nullをとして受け入れるメソッドnullパラメータが例外であるべきであるという仮定を強化するためだけに、パラメータはそうするように明示的に文書化されるべきです。 2番目の方法では、 @NonNullアノテーション

/**
  * @param origVal string giving value, possibly null, in which case DEFAULT_VALUE is assigned
  */
void doStuff(final String origVal, ... )
{
    final String valOrDefault = (origVal == null) ? DEFAULT_VALUE : origVal; 
    // similar mucking about to make all the parameters behave, separate from
    // actually operating on them...
    ...
    reallyDoStuff(valOrDefault,...);
}

private void reallyDoStuff(final String value, ...)
{
   assert (value != null);
   // do your complex processing
}

StackOverflowに関する関連する質問(および関連する引数): "Javaで適用可能な場合は常にfinal修飾子を使用する...""メソッドパラメーターのfinalキーワード"" Javaでローカル変数とメソッドパラメータをファイナライズしますか? "

35
andersoj

メソッド内でパラメーターを再割り当てすることは、悪い習慣と見なされることがあります。これはおそらくC/C++に由来し、メソッドの完了後にdoSomething(myVar)を呼び出すとmyVarを変更できます。しかし、Javaの場合はそうではありません。

私見、あなたが方法の最初のこととしてそれをするならば、これは完全に問題ありません。あなたのコードを読んでいる誰もが何が起こっているのか理解するでしょう。ただし、コードの奥深くに埋もれていると混乱する可能性があります。

14
Nikita Rybak

私の経験では、デフォルトパラメータの番兵としてnullを使用することは、Pythonのイディオムに近いものです。 Javaでは、メソッドをオーバーロードするだけです。

void doStuff() {
    doStuff(DEFAULT_VALUE);
}

void doStuff(final String val) {
    assert (val != null); // or whatever
    ...
}
7
Josh Lee

パラメーター割り当てのインスタンスを無視するか、警告のフラグを立てるか、エラーのフラグを立てるかを指示するコンパイラー設定があります。

メニューバーに移動し、[Window..Preferences]を選択し、[Preferences]ダイアログのツリーコントロールで[Java..Compiler..Errors/Warnings]を選択し、[CodeStyle]セクションで[ParameterAssignment]設定を確認します。

alt text

6
Ladlestein

スタイルの問題 ;実際の潜在的な問題というよりも、プログラマー向けのガイドラインです。元のパラメータ値を破棄することは誤解を招くと感じる人もいるかもしれません。

1
maerics