web-dev-qa-db-ja.com

Javaで「final」キーワードを過度に使用している

finalキーワードがクラスとメソッドのコンテキストで使用される目的と、変数に関するその使用の意図を理解していますが、しかし、私が始めたばかりのプロジェクトにはそれらの数が多すぎるようで、その背後にあるロジックに興味があります。

次のコードスニペットは、final変数とkey変数のvalueキーワードにあまり意味がないため、短い例です。

private <K, V> Collection<V> getValuesForKeys(
    final Map<K, V> map, final Collection<K> keys) 
{
    final Collection<V> values = new ArrayList<V>(keys.size());
    for (final K key : keys) {
        final V value = map.get(key);
        if (value != null) {
            values.add(value);
        }
    }
    return values;
}

私は、Googleを介して見つけた記事を通じて使用法を少し読んでいます。しかし、パターンは本当にコンパイラがコードを最適化するのを助けるようなことをしますか?

118
rjzii

リベラル の使用を示唆する多くの参考文献があります final 。 Java言語仕様には、最終的な変数に関するセクション も含まれています 。静的分析ツールのさまざまなルールもこれをサポートしています- [〜#〜] pmd [〜#〜] には、finalをいつ使用できるかを検出する ルールの数さえあります 私がリンクしたページには、finalの機能と、それを自由に使用する必要があることについて、いくつかのポイントが記載されています。

私にとって、finalの自由な使用は、ほとんどのコードで2つのことを達成しました。おそらくこれらは、コードサンプルの作成者がそれを使用するように駆り立てたものです。

  1. これにより、コードの意図がより明確になり、自己文書化コードにつながります。 finalを使用すると、プリミティブオブジェクトの値が変更されたり、新しいオブジェクトが作成されて既存のオブジェクトが上書きされたりするのを防ぎます。変数の値を変更する必要がなく、誰かが変更する場合、IDEおよび/またはコンパイラーが警告を表示します。開発者は問題を修正するか、final変数からの修飾子。いずれにしても、意図した結果が確実に達成されるように考える必要があります。

  2. コードによっては、最適化を潜在的に有効にするためのコンパイラのヒントとして機能します。これはコンパイル時間とは関係ありませんが、コンパイラーがコンパイル中に実行できることです。また、何も保証されていません。ただし、この変数またはこの変数によって参照されるオブジェクトの値が決して変更されないことをコンパイラーに通知すると、パフォーマンスの最適化が可能になる可能性があります。

同時実行性に関連する他の利点もあります。クラスまたはメソッドレベルで適用する場合、何をオーバーライドまたは継承できるかを確認する必要があります。ただし、これらはコードサンプルの範囲を超えています。繰り返しますが、私がリンクした記事では、finalの適用方法についてさらに詳しく説明しています。

コードの作成者がfinalを使用することにした理由を確認する唯一の方法は、作成者を見つけて自分自身に尋ねることです。

127
Thomas Owens

私の心の中の「最終」の主な利点は2つあります。

  • Final変数は、finalでない変数よりも「安全」です。いったんバインドされると、現在の状態が何であるかについての質問がなくなるためです。
  • 上記のため、変数をfinalにすることで、プログラマーは過度のメンタルジャグリングから解放されます-変数が変更されたかどうかを確認するためにコードをスキャンする必要がなくなります。この幸せな状況は、機能的な言語設定で時間を費やしたことがある人なら誰でもよく知っています。

この特定の例については、プログラマーが「最終」の習慣を身につけ、当然のことながら「最終」キーワードをどこにでも適用している場合があります。 (私は、個々の割り当てについて話すときにfinalキーワードがコンパイラーを助けるという概念に懐疑的です。確かに、割り当てが1つだけ行われたかどうかを判断するのに助けは必要ありませんか?)

私は、Java逆方向に取得しました—変数の「最終」キーワードはなく、すべてデフォルトで「最終」である必要があると考えています。可変変数が必要な場合は、そのためのキーワードを追加する必要があります(「var」など)。(別のコメンターが述べたように、scalaには、最終変数と非最終変数の「val」と「var」の2つのキーワードがあります。 、それぞれ-私はそれを取ります)。

37
nerdytenor

Javaでは、finalキーワードがが必要な私の知識の唯一の場所は、匿名クラスで確実に使用できる変数(コンパイラーは、この値を変更できないようにする必要があるため、内部で何らかのトリックを行うため)。

それは-私の知る限り-最後のキーワードでJavaコンパイラがmatterランタイムのJIT部分で発生します。

したがって、それは好みの問題です。ただし、多くのファイナルを使用することには非常に重要な利点が1つあります。つまり、将来のメンテナーにとってコードをreadに簡単にできるということです。

変数にfinalのマークを付けると、この変数は割り当てられても変更されることはありません。これは、コードを読み取るときに非常に重要です。最初の割り当てと同じであり、変数が再度割り当てられているかどうかを確認するためにその間のすべてのコードを精神的に解析する必要がないという変数の値を知る必要がある場合は知っています。他のもので。

また、変数がfinalマークされていないことがわかった場合、さらに変更されました!これは、5つの文字が欠けているだけで読者に伝えることができる非常に重要な情報です。

メンテナーがより速くより確実に仕事をするのを助けることができるものは、アプリケーションのメンテナンスがより安価であることを意味します!言い換えれば、finalは実際のお金を節約します。

注:Eclipseには、可能であればファイナルを挿入できる「ソースクリーンアップ」オプションがあります。これは、新しいコードの作成と古いコードの維持の両方に役立ちます(一部が欠落している場合は、最終を挿入し、変数が最初の割り当て後に変更されます)。私の直感は、これが原作者が発見して使用することを決めたものだということです。

主題は https://stackoverflow.com/q/316352/53897 でさらに議論されます

13
user1249

これに対する答えは、他の人が示唆するよりも簡単だと思います。それは意図やデザインではありません。かなり前のことですが、一部の場所(特にメソッドとクラス)にfinalを追加することで、JVMがより積極的に最適化できるようになったことは事実でした。その結果、何人かの人々は凶暴になり、最終的に文字通りeverywhereを入れて、コードをより速く実行しようとしました。

コンパイラではなく、最適化を行うJVMであることを付け加えておきます。さらに、ローカル変数をfinalに設定しても、パフォーマンスに影響が及ぶことはないと思います。

最後に、JVMの最適化がある程度進んでいるため、finalを使用しても、最近はそれほど大きな違いはないでしょう。

8
redjamjar

不変コレクションを作成するためにfinalキーワードがこのコンテキストで使用されているように見えます。不変コレクションは、推論するのが簡単です同時実行性(マルチスレッド)を必要とするプログラムで使用する方が安全です。

もちろんそうではありません。 finalキーワードは、コレクションへの参照が別のコレクションまたはnullへの参照で置き換えられないことを保証するだけです。

1
Robert Harvey