最終的にjavaメソッド引数を作成する


91

final以下のコードの違いは何ですか。引数を宣言するのいずれかの利点がありますfinal

public String changeTimezone( Timestamp stamp, Timezone fTz, Timezone toTz){  
    return ....
}

public String changeTimezone(final Timestamp stamp, final Timezone fTz, 
        final Timezone toTz){
    return ....
}

4
パラメータが再利用または再割り当てされた場合に警告するコードアナライザがあります。(ローカル変数についても同じです)IMHO、これは、変更が望ましくない場合にそのようなパラメーターをキャッチするためのより良い方法です。
Peter Lawrey、2011年


デフォルトでは、Javaはすべてのインプットメソッド引数をfinalにする必要があると思います。参照を変更する場合は、手動で行う必要があります。そうすれば、罪悪感の要因がそのような多くのケースを防ぐでしょう。
シド

回答:


131

仮メソッドパラメータはローカル変数であるため、finalとして宣言されている場合にのみ、内部の匿名クラスからアクセスできます。

これにより、メソッド本体で別のローカルfinal変数を宣言する必要がなくなります。

 void m(final int param) {
        new Thread(new Runnable() {
            public void run() {
                System.err.println(param);
            }
        }).start();
    }

27
+1:これは重要な使用例であり、必要なときだけです。(残りの時間は、プログラマーを支援するために何が便利かという問題だけです。)
ドナルフェロー

3
これの背後にある理由を尋ねてもいいですか?
KodeWarrior 2014年

20
これ以上必要なJava 8と
アミットParashar

3
@simgineerはここで読む:stackoverflow.com/questions/28408109/...
PeterMmm

3
@AmitParashar真ですが、Java 8 では、内部クラスで変数を使用する必要があるたびにキーワード "final" を使用する必要がなくなります...実際には、コンパイラは最終性を暗黙的にしているだけですが、変数を効果的に最後にする必要があります...したがって、後で割り当てようとすると、コンパイル時エラーが発生します。Java 8SNEAK 100 :)
varun

38

最後のキーワードの最後の単語から抽出

最終パラメータ

次のサンプルでは、​​最終的なパラメータを宣言しています。

public void doSomething(final int i, final int j)
{
  // cannot change the value of i or j here...
  // any change would be visible only inside the method...
}

ここでfinalを使用して、2つのインデックスiとjがメソッドによって誤ってリセットされないようにします。これは、パラメーターの値を誤って変更する陰湿なバグから保護するための便利な方法です。一般的に言って、短いクラスはこのクラスのエラーから保護するためのより良い方法ですが、最終的なパラメーターはコーディングスタイルへの有用な追加となります。

最終パラメータはメソッドシグネチャの一部とは見なされず、メソッド呼び出しを解決するときにコンパイラによって無視されることに注意してください。メソッドのオーバーライド方法に影響を与えることなく、パラメーターをfinal(またはnot)として宣言できます。


17
この例では、プリミティブの変更は常にメソッド内でのみ表示されるため、プリミティブではなくオブジェクトを使用した方がよい場合があります。オブジェクトの場合でも、変更することができます。新しいオブジェクトを指すことはできません。実際、私はそれについて考えています。finalは、AICを使用して変数宣言を保存し、何らかの理由で変更したくないパラメーターの偶発的な変更をコンパイラーに指摘させることを除いて、それを省略することに比べて何も変更しません。 。
Rob Grant

26

finalを使用すると、変数に新しい値を割り当てることができなくなります。これは、タイプミスを見つけるのに役立ちます。文体的には、受け取ったパラメータを変更せずにローカル変数にのみ割り当てることを好むので、finalはそのスタイルを適用するのに役立ちます。

パラメータにfinalを使用することをほとんど覚えていないことを認めなければなりません。

public int example(final int basicRate){
    int discountRate;

    discountRate = basicRate - 10;
    // ... lots of code here 
    if ( isGoldCustomer ) {
        basicRate--;  // typo, we intended to say discountRate--, final catches this
    }
    // ... more code here

    return discountRate;
}

1
引数をfinalとして宣言することがどのように役立つかを示す優れた例。私はこれに不満ですが、3つ以上のパラメータについても一口です。
JoseHdez_2 2018

14

それは大きな違いはありません。それはあなたが書くことができないことを意味します:

stamp = null;
fTz = new ...;

しかし、あなたはまだ書くことができます:

stamp.setXXX(...);
fTz.setXXX(...);

それは主にメンテナンスプログラマーへのヒントであり、メソッドの途中のどこかでパラメータに新しい値を割り当てないことは明らかではないため、混乱を招く可能性があります。


3

Javaのパラメーター/変数に使用されるfinalキーワードは、参照をfinalとしてマークします。オブジェクトを別のメソッドに渡す場合、システムは参照変数のコピーを作成し、それをメソッドに渡します。新しい参照に最終のマークを付けることにより、再割り当てから保護します。それは時々良いコーディングの習慣と考えられています。


1
追加する必要があります。パラメータがプリミティブである場合、違いはありません。さらに、パラメーターがコレクション(オブジェクトのリスト...)の場合、finalを追加しても変更を防ぐことができませんでした。
Sam003

1
不変性は常に望ましい特性です。Javaには、それをそのまま使用するものはありません。変数をfinalにすることで、少なくとも参照の整合性が保証されます。
2015

1
同意する。しかし、本当にオブジェクトの不変性を実現したい場合は、ディープクローンを作成してみることができます。
Sam003

2

このメソッドの本文では、finalキーワードにより、引数参照が誤って再割り当てされて、それらの場合にコンパイルエラーが発生することが防止されます(ほとんどのIDEはすぐに文句を言うでしょう)。final一般的に可能な限り一般的に使用すると速度が上がると主張する人もいますが、最近のJVMではそうではありません。


2

私が見る2つの利点は次のとおりです。

1 メソッドの引数をfinalとしてマークすると、メソッド内での引数の再割り当てが防止されます

あなたの例から

    public String changeTimezone(final Timestamp stamp, final Timezone fTz, 
            final Timezone toTz){
    
    // THIS WILL CAUSE COMPILATION ERROR as fTz is marked as final argument

      fTz = Calendar.getInstance().getTimeZone();     
      return ..
    
    }

複雑なメソッドでは、引数をfinalとしてマークすると、これらの引数をメソッドのローカル変数として誤って解釈し、コンパイラーがこれらのケースにフラグを立てるように再割り当てするのに役立ちます(例を参照)。

2 匿名の内部クラスに引数を渡す

仮メソッドパラメータはローカル変数であるため、finalとして宣言されている場合にのみ、内部の匿名クラスからアクセスできます。


1

-過去(Java 8以前:-))

「final」キーワードの乱用は、内部の匿名クラスのメソッド変数のアクセシビリティに影響を与えました。

-最近の(Java 8+)言語では、そのような使用法は必要ありません。

Javaは「実質的に最終的な」変数を導入しました。コードが変数の値の変更を意味しない場合、ローカル変数とメソッドパラメーターは最終と見なされます。したがって、Java8 +でそのようなキーワードが表示された場合、それは不要であると想定できます。「実質的に最終」の導入により、ラムダを使用するときに入力するコードが少なくなります。


0

契約を定義してそれに固執するのに役立つ、Javaの単なる構成体です。ここで同様の議論:http : //c2.com/cgi/wiki?JavaFinalConsideredEvil

ところで-(twikiが言っているように)argをfinalとしてマークすることは、適切なプログラミング原則に従っていて、入力引数の参照を再割り当て/再定義する場合、一般的に冗長です。

最悪の場合、args参照を再定義しても、参照のみが渡されているため、関数に渡される実際の値には影響しません。


0

私は変数とフィールドを最終的にマークすることについて話している-メソッドの引数に適用されるだけではない。(メソッド/クラスをfinalとマークすることはまったく異なります)。

それはあなたのコードの読者/将来のメンテナーに有利です。変数の意味のある名前と一緒に、問題の変数が何を表しているかを確認/理解することは、コードの読者に役立ち、安心します。そして、同じスコープで変数を参照するときはいつでも、意味はそのままであることを読者に安心させます。同じなので、すべてのコンテキストで変数の意味を常に理解するために頭を掻く必要はありません。変数の「再利用」の乱用が多すぎるため、短いコードスニペットすら理解しづらくなっています。


-3

最後のキーワードは、パラメーターに新しい値を割り当てられないようにします。これを簡単な例で説明したいと思います

メソッドがあるとしましょう

method1(){

日付dateOfBirth = new Date( "1/1/2009");

method2(dateOfBirth);

method3(dateOfBirth); }

public mehod2(Date dateOfBirth){
....
....
....
}

public mehod2(Date dateOfBirth){
....
....
....
}

上記の場合、「dateOfBirth」にmethod2で新しい値が割り当てられると、method3からの出力が正しくなくなります。method3に渡される値は、method2に渡される前の値ではないためです。したがって、この最後のキーワードを回避するには、パラメーターに使用します。

これは、Javaコーディングのベストプラクティスの1つでもあります。


5
それは正しくありません。引数dateOfBirthがmethod2()で別の値に変更されたとしても、Javaは参照ではなく値で渡されるため、これはmethod2()に影響を与えません。
Flo
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.