Javaでは、すべての変数(ローカルまたはクラス)を宣言する慣行があり、実際にそうである場合はパラメーターfinalがあります。
これにより、コードは非常に冗長になりますが、コードの読み取り/把握が容易になり、意図が明確に示されているため、ミスも防止されます。
これについてどう思いますか、また何をフォローしますか?
すべては良いコーディングスタイルに関係していると思います。もちろん、多くのfinal
修飾子をどこにも使用せずに、優れた堅牢なプログラムを作成できますが、考えてみると...
するべきではない変更するすべてのものにfinal
を追加すると、あなた(またはコードに取り組んでいる次のプログラマー)がコードをもたらした思考プロセスを誤って解釈または誤用する可能性を単純に絞り込みます。少なくとも、以前不変のものを変更したい場合は、少なくともベルを鳴らしてください。
最初は、コード内に多くのfinal
キーワードが表示されるのはちょっと不自然に見えますが、すぐにWord自体に気付くのをやめて、単純に考えるようになりますthat-thing-will-never -change-from-this-point-on(あなたは私からそれを取ることができます;-)
良い習慣だと思います。私はいつもそれを使用しているわけではありませんが、可能な場合、何かにラベルを付けることは理にかなっていますfinal
.
取りつかれている:
考慮しますが、慎重に使用してください。
肛門を感じない限り無視:
使用する前に、finalキーワードの完全な使用を本当に理解する必要があります。変数、フィールド、メソッド、クラスに適用でき、異なる影響を与えます。
詳細については、以下にリンクされている記事をご覧になることをお勧めします。
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);
}
いくつかのリンク:
可能なすべての変数final
の宣言については、非常に独断的です。これには、メソッドパラメータ、ローカル変数、およびまれに値オブジェクトフィールドが含まれます。どこでも最終変数を宣言する主な理由は3つあります。
ただし、最終的なクラスとメソッドは、最終的な変数参照ほど有用ではないと思います。 final
キーワードをこれらの宣言とともに使用すると、自動テストおよび予期しない方法でのコードの使用への障害を単に提供します。
Effective Javaには「不変オブジェクトを優先する」という項目があります。フィールドをfinalとして宣言すると、これに向けて小さな一歩を踏み出すことができますが、真に不変オブジェクトにはもちろんそれ以上のものがあります。
オブジェクトが不変であることがわかっている場合、それらは同期の心配なしに多くのスレッド/クライアント間で読み取りのために共有でき、プログラムの実行方法について推論するのは簡単です。
変数に最終キーワードを設定したことで間違いを防ぐことができたことが一度もなかったので、今のところは時間の浪費だと思います。
それを行う本当の理由がない限り(その変数が最終的なものであるという特定のポイントを作りたい場合)、コードを読みにくくするので、私はそれをやめたほうがいいでしょう。
ただし、コードが読みにくくなったり、書き込みが長くなったりしない場合は、ぜひ行ってください。
編集:明確化(およびダウン票を取り戻す試み)として、定数を最終としてマークしないと言っているのではなく、次のようなことをしないと言っています:
public String doSomething() {
final String first = someReallyComplicatedExpressionToGetTheString();
final String second = anotherReallyComplicatedExpressionToGetAnother();
return first+second;
}
それはコードを(私の意見では)読みにくくするだけです。
all finalは、変数の再割り当てを防ぐこと、それを不変にしない、またはそのようなことをしないことを覚えておく価値があります。
定数には常に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;
最大の引数の1つと思われるagainst finalキーワードを使用することは、「不要」であり、「スペースを無駄にする」ということです。
ここで多くの素晴らしい投稿で指摘されているように、「ファイナル」の多くの利点を認めれば、より多くの入力とスペースが必要であることを認めながら、Javaデフォルトであり、コーダーがそれを望んでいる場合は、「可変」とマークする必要があります。
オブジェクト属性には常にfinal
を使用します。
final
キーワードは、オブジェクト属性で使用される場合に可視性のセマンティクスを持ちます。基本的に、コンストラクターが戻る前に、最終オブジェクト属性の値を設定します。これは、this
参照がコンストラクターをエスケープせず、all属性にfinal
を使用する限り、オブジェクトは(Java 5セマンティクス)が適切に構築されることを保証します。また、不変であるため、他のスレッドに安全に公開できます。
不変オブジェクトは、スレッドセーフだけではありません。 can changeのスペースは意図的に、一貫して使用する場合はshould変更。
メソッドを最終的にすることもありますが、それほど頻繁ではありません。クラスを最終的にすることはめったにありません。必要性がほとんどないため、通常これを行います。通常、継承はあまり使用しません。私は代わりにインターフェイスとオブジェクト構成を使用することを好みます-これはまた、私がテストするのがより簡単であることが多い設計に役立ちます。具象クラスの代わりにインターフェイスにコーディングする場合、jMockなどのフレームワークでテストするときにそのまま継承を使用するためにneedをしないでください。インターフェイスでモックオブジェクトを作成する方がはるかに簡単です具体的なクラスです。
クラスの大部分を決勝にする必要があると思いますが、まだ習慣になっていません。
私は仕事のために多くのコードを読まなければなりません。インスタンス変数のfinalが欠落していることは、私を悩ます最も重要なことの1つであり、コードを不必要に理解するのを難しくしています。私のお金のために、ローカル変数のfinalは、明確さよりも混乱を引き起こします。言語はそれをデフォルトにするように設計されるべきでしたが、私たちは間違いに耐えなければなりません。ループやif-elseツリーを使用した明確な割り当てでは特に便利ですが、ほとんどの場合、メソッドが複雑すぎることを示す傾向があります。
finalは明らかに定数で使用され、不変性を強制する必要がありますが、メソッドには別の重要な用途があります。
有効なJavaには、意図しない継承の落とし穴を指摘するこの項目(項目15)全体の項目があります。継承のためにクラスを設計および文書化していない場合、事実上、クラスから継承すると予期しない問題が発生する可能性があります(項目に良い例を示します)。そのため、継承を意図していないクラスやメソッドでfinalを使用することをお勧めします。
それは厳しいと思われるかもしれませんが、それは理にかなっています。他の人が使用するためにクラスライブラリを作成する場合、そのために設計されていないものから継承したくない-後方互換性のためにクラスの特定の実装にロックされます。チームでコーディングしている場合、チームの他のメンバーがfinalを削除するのを止めるものは何もありません。しかし、このキーワードは、彼らが何をしているのかを考えさせ、継承元のクラスがそのために設計されていないことを警告するため、特に注意が必要です。
もう1つの注意点は、多くの人がfinalを混同して、参照が変更できないのではなく、インスタンス変数の内容が変更できないことを意味していることです。
各メソッドの各パラメーターにfinal
を入力することを選択すると、コーダーとコードリーダーの両方に非常に苛立ちが生じます。
刺激がScalaへの合理的な切り替えを超えると、引数はデフォルトで最終です。
または、自動的にそれを行うコードスタイリングツールをいつでも使用できます。すべてのIDEには、プラグインまたはプラグインが実装されています。
ローカル変数であっても、それがfinalと宣言されていることを知っていれば、後で参照が変更されることを心配する必要はありません。これは、デバッグ時に後でその変数を見たときに、同じオブジェクトを参照していると確信していることを意味します。これは、バグを探すときに心配する必要のあるものの1つです。ボーナスは、変数の99%が最終的に宣言されている場合、実際に変数であるいくつかの変数がより際立つことです。また、ファイナルでは、コンパイラは、見過ごされてしまう可能性のある、より多くの愚かな間違いを見つけることができます。
私は今しばらくコーディングしており、可能な限りfinalを使用しています。これをしばらく(変数、メソッドパラメーター、およびクラス属性に対して)行った後、変数の90%(またはそれ以上)が実際に最終的なものであると言えます。したくないときに変数を変更しないことの利点は(前に見たことがあり、時々苦痛です)、コード内の余分な入力と余分な「最終」キーワードの代価を払うと思います。
つまり、言語を設計する場合、他のキーワードによって変更されない限り、すべての変数を最終的にします。
クラスやメソッドにfinalをあまり使わない、と思った。クラスがユーティリティクラスである場合を除き、これは多かれ少なかれ複雑な設計の選択肢です(この場合、プライベートコンストラクターは1つだけにする必要があります)。
また、必要に応じてCollections.unmodifiable ...を使用して、変更不可能なリストを作成します。
引数については、それらは必要ないと思います。ほとんどの場合、彼らは読みやすさを損ないます。引数変数の再割り当ては非常にばかげているので、とにかく定数として扱うことができると確信しています。
Eclipseが最終的な赤に色付けするという事実により、コード内の変数宣言を見つけやすくなり、ほとんどの場合、readbillityが向上すると思います。
私は、すべての変数が最終的なものでなければならないというルールを実施しようとします。 「この変数とは」と答える方がずっと簡単です。初期化を見つけて、それだけであることを確信しなければならないかどうか疑問に思います。
私は実際に、非最終的な変数について、今ではかなり緊張しています。それは、頭の上にナイフを吊るすことと、キッチンの引き出しを持っていることとの違いのようなものです...
最終的な変数は、値をラベル付けする良い方法です。
非最終変数は、バグが発生しやすいアルゴリズムの一部にバインドされています。
ナイス機能の1つは、アルゴリズムの問題外で変数を使用するオプションがほとんどの場合、解決策が代わりにメソッドを記述することであり、通常はコードが大幅に改善されることです。
Eclipseをセットアップして、変更されていないすべてのフィールドと属性にfinalを追加します。これは、ファイルを保存するときに(特に)これらの最終的な修飾子を追加するEclipseの「アクションを保存する」を使用するとうまく機能します。
強くお勧めします。
Eclipse Save Actionsの 私のブログ投稿 をご覧ください。
ローカル変数でこれらを使用することはありません。冗長性を追加する意味はほとんどありません。変数を再割り当てする必要があると思わない場合でも、そうでないと考えるコードを変更する次の人にはほとんど違いがありません。また、コードが変更されているため、最終的なものにするための元の目的が無効になる可能性があります。明確にするためだけであれば、冗長性のマイナス効果のために失敗すると思います。
メンバー変数にもほとんど同じことが当てはまります。定数の場合を除いて、メンバー変数にはほとんど利点がありません。
また、不変とは関係ありません。不変であることの最良の指標は、そのように文書化されているか、オブジェクトを変更できるメソッドがないことです(これは、クラスをfinalにすることを保証する唯一の方法です不変です)。
しかし、ちょっと、それは私の意見です:-)
メソッドやクラスでfinalを使用することはほとんどありません。なぜなら、人々がそれらをオーバーライドできるようにするためです。
それ以外の場合は、public/private static final type SOME_CONSTANT;
Javaで変数を使用すると、FinalはC++の定数の代替となります。したがって、変数にfinalとstaticを使用すると、不変になります。同時に、移行したC++プログラマは)
オブジェクトを操作することはできますが、参照変数とともに使用すると、オブジェクトを再参照することはできません。
メソッドでfinalを使用する場合、サブクラスによってメソッドをオーバーライドすることはできません。
使用法が非常に明確になったら、慎重に使用する必要があります。メソッドでfinalを使用してもポリモーフィズムは改善されないため、主に設計に依存します。
変数の値が決して変更されないことを確信している場合にのみ、変数に使用する必要があります。また、Sunが推奨するコーディング規則に従っていることを確認してください。例:final int COLOR_RED = 1; (大文字がアンダースコアで区切られている)
参照変数では、特定のオブジェクトへの不変の参照が必要な場合にのみ使用します。
可読性の部分については、最終修飾子を使用するときにコメントが非常に重要な役割を果たすことになります。
クラスを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();
}
}
イベントリスナーなどに匿名ローカルクラスを使用することは、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
}
};
}
メソッドの内部および外部の定数に使用します。
サブクラスが(何らかの理由で)与えられたメソッドをオーバーライドしたくないかどうかわからないので、私は時々それをメソッドにのみ使用します。
クラスに関しては、一部のインフラストラクチャクラスについてのみ、最終クラスを使用しました。
IntelliJ IDEAは、関数のパラメーターが関数内に書き込まれた場合に警告します。したがって、関数の引数にfinalを使用することを停止しました。Javaランタイムライブラリも。