web-dev-qa-db-ja.com

Java

Javaでは、すべての変数(ローカルまたはクラス)を宣言する慣行があり、実際にそうである場合はパラメーターfinalがあります。

これにより、コードは非常に冗長になりますが、コードの読み取り/把握が容易になり、意図が明確に示されているため、ミスも防止されます。

これについてどう思いますか、また何をフォローしますか?

187
surajs

すべては良いコーディングスタイルに関係していると思います。もちろん、多くのfinal修飾子をどこにも使用せずに、優れた堅牢なプログラムを作成できますが、考えてみると...

するべきではない変更するすべてのものにfinalを追加すると、あなた(またはコードに取り組んでいる次のプログラマー)がコードをもたらした思考プロセスを誤って解釈または誤用する可能性を単純に絞り込みます。少なくとも、以前不変のものを変更したい場合は、少なくともベルを鳴らしてください。

最初は、コード内に多くのfinalキーワードが表示されるのはちょっと不自然に見えますが、すぐにWord自体に気付くのをやめて、単純に考えるようになりますthat-thing-will-never -change-from-this-point-on(あなたは私からそれを取ることができます;-)

良い習慣だと思います。私はいつもそれを使用しているわけではありませんが、可能な場合、何かにラベルを付けることは理にかなっていますfinal.

174
Johan Pelgrim

取りつかれている:

  • 最終フィールド-フィールドを最終としてマークすると、構築の終わりまでにフィールドが設定され、そのフィールド参照が不変になります。これにより、フィールドの安全な発行が可能になり、後の読み取りでの同期の必要性を回避できます。 (オブジェクト参照の場合、フィールド参照のみが不変であることに注意してください。オブジェクト参照が参照するものは、変更可能であり、不変に影響します。)
  • 最終的な静的フィールド-静的な最終フィールドを使用していた多くの場合に列挙型を使用しています。

考慮しますが、慎重に使用してください。

  • 最終クラス-フレームワーク/ API設計は、私が検討する唯一のケースです。
  • 最終メソッド-基本的に最終クラスと同じです。クレイジーのようなテンプレートメソッドパターンを使用し、最終的なものをマークしている場合、おそらく継承に頼りすぎており、委任に十分ではありません。

肛門を感じない限り無視:

  • メソッドのパラメーターとローカル変数-私は怠け者でコードが乱雑だと思うので、これを行うことはめったにありません。変更しないパラメーターとローカル変数のマーキングが「正しい」ことを完全に認めます。それがデフォルトだったらいいのに。しかし、そうではなく、決勝戦ではコードを理解するのが難しくなります。私が他の誰かのコードにいる場合、私はそれらを引き出すつもりはありませんが、新しいコードを書いている場合、私はそれらを入れません。1つの例外は、アクセスできるように何かを最終的にマークする必要がある場合です匿名の内部クラス内から。
182
Alex Miller

使用する前に、finalキーワードの完全な使用を本当に理解する必要があります。変数、フィールド、メソッド、クラスに適用でき、異なる影響を与えます。

詳細については、以下にリンクされている記事をご覧になることをお勧めします。

最終キーワードの最終単語

32
HowardSP

final修飾子(特に変数の場合)は、コンパイラーに一般的に賢明な規則を強制させる手段です。(ローカルまたはインスタンス)変数が必ず1回(これ以上)割り当てられるようにします。変数が使用される前に確実に割り当てられるようにすることで、NullPointerExceptionの一般的なケースを回避できます。

final FileInputStream in;
if(test)
  in = new FileInputStream("foo.txt");
else
  System.out.println("test failed");
in.read(); // Compiler error because variable 'in' might be unassigned

変数が複数回割り当てられるのを防ぐことで、広範囲にわたるスコープを避けることができます。これの代わりに:

 String msg = null;
 for(int i = 0; i < 10; i++) {
     msg = "We are at position " + i;
     System.out.println(msg);
 }
 msg = null;

これを使用することをお勧めします。

 for(int i = 0; i < 10; i++) {
     final String msg = "We are at position " + i;
     System.out.println(msg);
 }

いくつかのリンク:

29
Bruno De Fraine

可能なすべての変数finalの宣言については、非常に独断的です。これには、メソッドパラメータ、ローカル変数、およびまれに値オブジェクトフィールドが含まれます。どこでも最終変数を宣言する主な理由は3つあります。

  1. 意図の宣言:最終変数を宣言することにより、この変数は一度だけ書き込まれることを意図していると述べています。他の開発者にとっては微妙なヒントであり、コンパイラにとっては大きなヒントです。
  2. 使い捨ての変数の強制:私は、各変数は人生でただ1つの目的を持つべきだという考えを信じています。各変数に1つの目的のみを与えることにより、デバッグ中にその特定の変数の目的を理解するのにかかる時間を短縮できます。
  3. 最適化の許可:コンパイラーは、変数参照の不変性に特に依存するパフォーマンス強化のトリックを使用していたことを知っています。これらの古いパフォーマンストリック(または新しいトリック)のいくつかがコンパイラで使用されると思います。

ただし、最終的なクラスとメソッドは、最終的な変数参照ほど有用ではないと思います。 finalキーワードをこれらの宣言とともに使用すると、自動テストおよび予期しない方法でのコードの使用への障害を単に提供します。

20
Ryan Ransford

Effective Javaには「不変オブジェクトを優先する」という項目があります。フィールドをfinalとして宣言すると、これに向けて小さな一歩を踏み出すことができますが、真に不変オブジェクトにはもちろんそれ以上のものがあります。

オブジェクトが不変であることがわかっている場合、それらは同期の心配なしに多くのスレッド/クライアント間で読み取りのために共有でき、プログラムの実行方法について推論するのは簡単です。

17
Lars Westergren

変数に最終キーワードを設定したことで間違いを防ぐことができたことが一度もなかったので、今のところは時間の浪費だと思います。

それを行う本当の理由がない限り(その変数が最終的なものであるという特定のポイントを作りたい場合)、コードを読みにくくするので、私はそれをやめたほうがいいでしょう。

ただし、コードが読みにくくなったり、書き込みが長くなったりしない場合は、ぜひ行ってください。

編集:明確化(およびダウン票を取り戻す試み)として、定数を最終としてマークしないと言っているのではなく、次のようなことをしないと言っています:

public String doSomething() {
  final String first = someReallyComplicatedExpressionToGetTheString();
  final String second = anotherReallyComplicatedExpressionToGetAnother();

  return first+second;
}

それはコードを(私の意見では)読みにくくするだけです。

all finalは、変数の再割り当てを防ぐこと、それを不変にしない、またはそのようなことをしないことを覚えておく価値があります。

10
SCdF

定数には常にfinalを使用する必要があります。変数を定義するためのルールが複雑な場合、短命の変数(単一のメソッド内)に対しても役立ちます。

例えば:

final int foo;
if (a)
    foo = 1;
else if (b)
    foo = 2;
else if (c)
    foo = 3;
if (d)        // Compile error:  forgot the 'else'
    foo = 4;
else
    foo = -1;
8
David Leppik

最大の引数の1つと思われるagainst finalキーワードを使用することは、「不要」であり、「スペースを無駄にする」ということです。

ここで多くの素晴らしい投稿で指摘されているように、「ファイナル」の多くの利点を認めれば、より多くの入力とスペースが必要であることを認めながら、Javaデフォルトであり、コーダーがそれを望んでいる場合は、「可変」とマークする必要があります。

5
RAY

オブジェクト属性には常にfinalを使用します。

finalキーワードは、オブジェクト属性で使用される場合に可視性のセマンティクスを持ちます。基本的に、コンストラクターが戻る前に、最終オブジェクト属性の値を設定します。これは、this参照がコンストラクターをエスケープせず、all属性にfinalを使用する限り、オブジェクトは(Java 5セマンティクス)が適切に構築されることを保証します。また、不変であるため、他のスレッドに安全に公開できます。

不変オブジェクトは、スレッドセーフだけではありません。 can changeのスペースは意図的に、一貫して使用する場合はshould変更。

メソッドを最終的にすることもありますが、それほど頻繁ではありません。クラスを最終的にすることはめったにありません。必要性がほとんどないため、通常これを行います。通常、継承はあまり使用しません。私は代わりにインターフェイスとオブジェクト構成を使用することを好みます-これはまた、私がテストするのがより簡単であることが多い設計に役立ちます。具象クラスの代わりにインターフェイスにコーディングする場合、jMockなどのフレームワークでテストするときにそのまま継承を使用するためにneedをしないでください。インターフェイスでモックオブジェクトを作成する方がはるかに簡単です具体的なクラスです。

クラスの大部分を決勝にする必要があると思いますが、まだ習慣になっていません。

5
Chris Vest

私は仕事のために多くのコードを読まなければなりません。インスタンス変数のfinalが欠落していることは、私を悩ます最も重要なことの1つであり、コードを不必要に理解するのを難しくしています。私のお金のために、ローカル変数のfinalは、明確さよりも混乱を引き起こします。言語はそれをデフォルトにするように設計されるべきでしたが、私たちは間違いに耐えなければなりません。ループやif-elseツリーを使用した明確な割り当てでは特に便利ですが、ほとんどの場合、メソッドが複雑すぎることを示す傾向があります。

finalは明らかに定数で使用され、不変性を強制する必要がありますが、メソッドには別の重要な用途があります。

有効なJavaには、意図しない継承の落とし穴を指摘するこの項目(項目15)全体の項目があります。継承のためにクラスを設計および文書化していない場合、事実上、クラスから継承すると予期しない問題が発生する可能性があります(項目に良い例を示します)。そのため、継承を意図していないクラスやメソッドでfinalを使用することをお勧めします。

それは厳しいと思われるかもしれませんが、それは理にかなっています。他の人が使用するためにクラスライブラリを作成する場合、そのために設計されていないものから継承したくない-後方互換性のためにクラスの特定の実装にロックされます。チームでコーディングしている場合、チームの他のメンバーがfinalを削除するのを止めるものは何もありません。しかし、このキーワードは、彼らが何をしているのかを考えさせ、継承元のクラスがそのために設計されていないことを警告するため、特に注意が必要です。

3
DJClayworth

もう1つの注意点は、多くの人がfinalを混同して、参照が変更できないのではなく、インスタンス変数の内容が変更できないことを意味していることです。

3
Uri

各メソッドの各パラメーターにfinalを入力することを選択すると、コーダーとコードリーダーの両方に非常に苛立ちが生じます。

刺激がScalaへの合理的な切り替えを超えると、引数はデフォルトで最終です。

または、自動的にそれを行うコードスタイリングツールをいつでも使用できます。すべてのIDEには、プラグインまたはプラグインが実装されています。

2
Oleg Mikheev

ローカル変数であっても、それがfinalと宣言されていることを知っていれば、後で参照が変更されることを心配する必要はありません。これは、デバッグ時に後でその変数を見たときに、同じオブジェクトを参照していると確信していることを意味します。これは、バグを探すときに心配する必要のあるものの1つです。ボーナスは、変数の99%が最終的に宣言されている場合、実際に変数であるいくつかの変数がより際立つことです。また、ファイナルでは、コンパイラは、見過ごされてしまう可能性のある、より多くの愚かな間違いを見つけることができます。

2
Diastrophism

私は今しばらくコーディングしており、可能な限りfinalを使用しています。これをしばらく(変数、メソッドパラメーター、およびクラス属性に対して)行った後、変数の90%(またはそれ以上)が実際に最終的なものであると言えます。したくないときに変数を変更しないことの利点は(前に見たことがあり、時々苦痛です)、コード内の余分な入力と余分な「最終」キーワードの代価を払うと思います。

つまり、言語を設計する場合、他のキーワードによって変更されない限り、すべての変数を最終的にします。

クラスやメソッドにfinalをあまり使わない、と思った。クラスがユーティリティクラスである場合を除き、これは多かれ少なかれ複雑な設計の選択肢です(この場合、プライベートコンストラクターは1つだけにする必要があります)。

また、必要に応じてCollections.unmodifiable ...を使用して、変更不可能なリストを作成します。

1
Ravi Wallau

引数については、それらは必要ないと思います。ほとんどの場合、彼らは読みやすさを損ないます。引数変数の再割り当ては非常にばかげているので、とにかく定数として扱うことができると確信しています。

Eclipseが最終的な赤に色付けするという事実により、コード内の変数宣言を見つけやすくなり、ほとんどの場合、readbillityが向上すると思います。

私は、すべての変数が最終的なものでなければならないというルールを実施しようとします。 「この変数とは」と答える方がずっと簡単です。初期化を見つけて、それだけであることを確信しなければならないかどうか疑問に思います。

私は実際に、非最終的な変数について、今ではかなり緊張しています。それは、頭の上にナイフを吊るすことと、キッチンの引き出しを持っていることとの違いのようなものです...

最終的な変数は、値をラベル付けする良い方法です。

非最終変数は、バグが発生しやすいアルゴリズムの一部にバインドされています。

ナイス機能の1つは、アルゴリズムの問​​題外で変数を使用するオプションがほとんどの場合、解決策が代わりにメソッドを記述することであり、通常はコードが大幅に改善されることです。

1
John Nilsson

Eclipseをセットアップして、変更されていないすべてのフィールドと属性にfinalを追加します。これは、ファイルを保存するときに(特に)これらの最終的な修飾子を追加するEclipseの「アクションを保存する」を使用するとうまく機能します。

強くお勧めします。

Eclipse Save Actionsの 私のブログ投稿 をご覧ください。

1
zvikico

ローカル変数でこれらを使用することはありません。冗長性を追加する意味はほとんどありません。変数を再割り当てする必要があると思わない場合でも、そうでないと考えるコードを変更する次の人にはほとんど違いがありません。また、コードが変更されているため、最終的なものにするための元の目的が無効になる可能性があります。明確にするためだけであれば、冗長性のマイナス効果のために失敗すると思います。

メンバー変数にもほとんど同じことが当てはまります。定数の場合を除いて、メンバー変数にはほとんど利点がありません。

また、不変とは関係ありません。不変であることの最良の指標は、そのように文書化されているか、オブジェクトを変更できるメソッドがないことです(これは、クラスをfinalにすることを保証する唯一の方法です不変です)。

しかし、ちょっと、それは私の意見です:-)

1
Robin

メソッドやクラスでfinalを使用することはほとんどありません。なぜなら、人々がそれらをオーバーライドできるようにするためです。

それ以外の場合は、public/private static final type SOME_CONSTANT;

1
jjnguy

Javaで変数を使用すると、FinalはC++の定数の代替となります。したがって、変数にfinalとstaticを使用すると、不変になります。同時に、移行したC++プログラマは)

オブジェクトを操作することはできますが、参照変数とともに使用すると、オブジェクトを再参照することはできません。

メソッドでfinalを使用する場合、サブクラスによってメソッドをオーバーライドすることはできません。

使用法が非常に明確になったら、慎重に使用する必要があります。メソッドでfinalを使用してもポリモーフィズムは改善されないため、主に設計に依存します。

変数の値が決して変更されないことを確信している場合にのみ、変数に使用する必要があります。また、Sunが推奨するコーディング規則に従っていることを確認してください。例:final int COLOR_RED = 1; (大文字がアンダースコアで区切られている)

参照変数では、特定のオブジェクトへの不変の参照が必要な場合にのみ使用します。

可読性の部分については、最終修飾子を使用するときにコメントが非常に重要な役割を果たすことになります。

1
Omnipotent

クラスをfinalにマークすると、実行時ではなくコンパイル時にメソッドバインディングが発生する場合があります。以下の「v2.foo()」を考慮してください-コンパイラはBがサブクラスを持つことができないことを知っているため、foo()をオーバーライドできないため、呼び出す実装はコンパイル時にわかります。クラスBがfinalとマークされていない場合、v2の実際のタイプはBを拡張し、foo()をオーバーライドするクラスである可能性があります。

class A {
    void foo() {
        //do something
    }
}
final class B extends A {
    void foo() {
    }
}
class Test {
    public void t(A v1, B v2) {
        v1.foo();
        v2.foo();
    }
}
0
Eugene

イベントリスナーなどに匿名ローカルクラスを使用することは、Javaの一般的なパターンです。 finalキーワードの最も一般的な使用法は、スコープ内の変数に偶数リスナーがアクセスできるようにすることです。

ただし、コードに多くの最終ステートメントを入れる必要がある場合は。それはあなたが何か間違ったことをしている良いヒントかもしれません。

上記の記事はこの例を示しています。

public void doSomething(int i, int j) {
    final int n = i + j; // must be declared final

    Comparator comp = new Comparator() {
        public int compare(Object left, Object right) {
            return n; // return copy of a local variable
        }
    };
}
0
Hans Sjunnesson

メソッドの内部および外部の定数に使用します。

サブクラスが(何らかの理由で)与えられたメソッドをオーバーライドしたくないかどうかわからないので、私は時々それをメソッドにのみ使用します。

クラスに関しては、一部のインフラストラクチャクラスについてのみ、最終クラスを使用しました。

IntelliJ IDEAは、関数のパラメーターが関数内に書き込まれた場合に警告します。したがって、関数の引数にfinalを使用することを停止しました。Javaランタイムライブラリも。

0
anjanb