可能な限り使用することを提案するいくつかの参照 (たとえばfinal
) を見つけましたが、それがどれほど重要か疑問に思っています。これは主に、最終的なメソッドやクラスではなく、メソッド パラメーターとローカル変数のコンテキストにあります。定数の場合、それは明らかに理にかなっています。
一方では、コンパイラーはいくつかの最適化を行うことができ、プログラマーの意図をより明確にします。一方、冗長性が追加され、最適化は簡単になる場合があります。
それは私が覚えておくために努力すべきことですか?
以下にこだわる:
考慮しますが、慎重に使用してください。
アナルを感じない限り無視:
メソッドのパラメーターとローカル変数 - 私は怠け者で、コードが乱雑になるため、これを行うことはめったにありません。変更するつもりのないパラメーターとローカル変数をマークする方が「正しい」ことは十分に認めます。デフォルトになればいいのに。しかし、そうではなく、ファイナル全体でコードを理解するのがより難しくなっています。私が他の誰かのコードにいる場合、それらを引き出すつもりはありませんが、新しいコードを書いている場合は、それらを入れません.1つの例外は、アクセスできるように何かを最終的にマークする必要がある場合です.匿名の内部クラス内から。
編集: @adam-gentで言及されているように、最終的なローカル変数が実際に非常に役立つユースケースの 1 つは、値がif
/else
ブランチの var に割り当てられる場合です。
それは私が忘れないように努力すべきことですか?
いいえ、Eclipseを使用している場合は、これらの最終修飾子を自動的に追加するように保存アクションを構成できるためです。そうすれば、少ない労力でメリットを得ることができます。
「最終」の開発時のメリットは、少なくとも実行時のメリットと同じくらい重要です。それはあなたの意図についてコードの将来の編集者に何かを伝えます。
クラスを「final」とマークすることは、クラスの設計または実装中に、拡張機能を適切に処理するための努力をしていないことを示します。読者がクラスに変更を加えることができ、「final」修飾子を削除したい場合は、自己責任で行うことができます。クラスが拡張をうまく処理することを確認するのは彼ら次第です。
変数を「final」とマークする(そしてコンストラクターで割り当てる)ことは、依存性注入で役立ちます。これは、変数の「コラボレーター」の性質を示しています。
メソッドを「final」とマークすると、抽象クラスで役立ちます。これは、拡張ポイントがどこにあるかを明確に示しています。
まあ、これはすべてあなたのスタイルに依存します...変数を変更しないときにファイナルを見るのが好きなら、それを使用してください。あなたがそれを見るのが好きでないなら...それからそれを省いてください。
個人的には冗長性をできるだけ少なくするのが好きなので、実際には必要のない余分なキーワードは使用しない傾向があります。
しかし、私は動的言語を好むので、冗長性を避けたいのは当然のことです。
ですから、私はあなたが傾いている方向を選んで、それに沿って進むと言います(いずれにせよ、一貫性を保つようにしてください)。
ちなみに、私はそのようなパターンを使用するプロジェクトと使用しないプロジェクトの両方に取り組んできましたが、バグやエラーの量に違いは見られませんでした...それが大きくなるパターンではないと思いますバグ数などを改善しますが、これもスタイルです。変更しないという意図を表現したい場合は、先に進んで使用してください。
final
問題のメソッドが数ページの長さの理解できない混乱である場合、リファクタリングの支援として役立つメソッドパラメーターとローカルをマークすることがわかりました。惜しみなく振りかけfinal
て、コンパイラ (または IDE) がスローする「最終変数に割り当てられません」というエラーを確認してください。いくつかの (古い) コメントが誓うにもかかわらず、「データ」と呼ばれる変数が null になる理由がわかるかもしれません。起こりません。
次に、再利用された変数を使用ポイントに近い場所で宣言された新しい変数に置き換えることで、いくつかのエラーを修正できます。次に、メソッドのすべての部分をスコーピング ブレースでラップできることがわかり、突然、"Extract Method" から IDE キーを 1 回押すだけになり、モンスターがよりわかりやすくなりました。
あなたの方法がまだ保守不可能な難破船ではない場合、人々がそれを難破船に変えるのを思いとどまらせるために、ものを最終的なものにすることに価値があると思います。しかし、それが短いメソッドである場合 (保守不可能でないことを参照)、多くの冗長性を追加するリスクがあります。特に、Java 関数の署名は、引数ごとにさらに 6 文字を追加しなくても、そのまま 80 文字に収まるほど困難です!
誤ってパラメータ値を変更して微妙なバグを導入するのを避けるために、パラメータで役立ちます。私はこの推奨事項を無視していましたが、4時間ほど費やした後. 恐ろしい方法 (何百行ものコードと複数の for、ネストされた if、あらゆる種類の悪い慣行) でそれを行うことをお勧めします。
public int processSomethingCritical( final int x, final int y ){
// hundreds of lines here
// for loop here...
int x2 = 0;
x++; // bug aarrgg...
// hundreds of lines there
// if( x == 0 ) { ...
}
もちろん、完璧な世界ではこれは起こりませんが..まあ..時には他のコードをサポートしなければならないこともあります。:(
たとえば、1年後に誰かがコードを読み取らなければならないアプリケーションを作成している場合は、そうです。常に変更してはならない変数に対してfinalを使用します。これを行うことで、コードはより「自己文書化」され、ローカル定数をローカル一時変数として使用するなど、他の開発者が愚かなことをする可能性も低くなります。
使い捨てのコードを書いているのなら、いや、わざわざすべての定数を識別して最終的なものにする必要はありません。
できる限りファイナルを使います。これを行うと、意図せずにフィールドを変更した場合にフラグが立てられます。また、メソッドパラメータをfinalに設定しました。そうすることで、Javaが値を渡すことを忘れてパラメーターを「設定」しようとしたときに、引き継いだコードからいくつかのバグを見つけました。
これが自明かどうかは質問から明らかではありませんが、メソッドのパラメータを final にすることは、メソッドの本体のみに影響します。メソッドの意図に関する興味深い情報を呼び出し元に伝えません。渡されるオブジェクトはメソッド内で変更することができ (finals は const ではありません)、変数のスコープはメソッド内にあります。
あなたの正確な質問に答えるために、インスタンスまたはローカル変数 (メソッドパラメーターを含む) を final にすることは気にしません。
たとえば、変数が論理的に定数である場合は、それらを final にします。
変数には多くの用途がありますfinal
。ここにいくつかあります
最終定数
public static class CircleToolsBetter {
public final static double PI = 3.141;
public double getCircleArea(final double radius) {
return (Math.pow(radius, 2) * PI);
}
}
これは、コードの他の部分に使用したり、他のクラスからアクセスしたりできます。値を変更する場合は、1 つずつ変更する必要はありません。
最終変数
public static String someMethod(final String environmentKey) {
final String key = "env." + environmentKey;
System.out.println("Key is: " + key);
return (System.getProperty(key));
}
}
このクラスでは、パラメーター environmentKey にプレフィックスを追加するスコープ付き最終変数を作成します。この場合、final 変数は実行スコープ内でのみ final であり、メソッドの実行ごとに異なります。メソッドが入力されるたびに、最終が再構築されます。構築されるとすぐに、メソッド実行のスコープ中に変更することはできません。これにより、メソッドの実行中にメソッド内の変数を修正できます。下記参照:
public class FinalVariables {
public final static void main(final String[] args) {
System.out.println("Note how the key variable is changed.");
someMethod("JAVA_HOME");
someMethod("ANT_HOME");
}
}
最終定数
public double equation2Better(final double inputValue) {
final double K = 1.414;
final double X = 45.0;
double result = (((Math.pow(inputValue, 3.0d) * K) + X) * M);
double powInputValue = 0;
if (result > 360) {
powInputValue = X * Math.sin(result);
} else {
inputValue = K * Math.sin(result); // <= Compiler error
}
これらは、非常に長いコード行がある場合に特に役立ち、コンパイラ エラーが生成されるため、変更してはならない変数を誰かが誤って変更した場合に、ロジック/ビジネス エラーに遭遇することはありません。
最終コレクション
コレクションについて話しているときは別のケースですが、コレクションを変更不可として設定する必要があります。
public final static Set VALID_COLORS;
static {
Set temp = new HashSet( );
temp.add(Color.red);
temp.add(Color.orange);
temp.add(Color.yellow);
temp.add(Color.green);
temp.add(Color.blue);
temp.add(Color.decode("#4B0082")); // indigo
temp.add(Color.decode("#8A2BE2")); // violet
VALID_COLORS = Collections.unmodifiableSet(temp);
}
それ以外の場合、変更不可として設定しない場合:
Set colors = Rainbow.VALID_COLORS;
colors.add(Color.black); // <= logic error but allowed by compiler
最終クラスと最終メソッドは、それぞれ拡張または上書きできません。
編集:カプセル化に関する最終クラスの問題に対処するには:
クラスを final にする方法は 2 つあります。1 つ目は、クラス宣言でキーワード final を使用することです。
public final class SomeClass {
// . . . Class contents
}
クラスを final にする 2 つ目の方法は、すべてのコンストラクターをプライベートとして宣言することです。
public class SomeClass {
public final static SOME_INSTANCE = new SomeClass(5);
private SomeClass(final int value) {
}
final とマークすると、実際に final であることがわかった場合に、この Test クラスを見てデモンストレーションする手間が省けます。一見公に見えます。
public class Test{
private Test(Class beanClass, Class stopClass, int flags)
throws Exception{
// . . . snip . . .
}
}
残念ながら、このクラスの唯一のコンストラクターはプライベートであるため、このクラスを拡張することはできません。Test クラスの場合、クラスを final にする必要はありません。Test クラスは、暗黙の最終クラスがどのように問題を引き起こすかを示す良い例です。
そのため、クラスのコンストラクターを非公開にすることでクラスを暗黙的に final にする場合は、それを final としてマークする必要があります。
内部 (匿名) クラスがあり、メソッドがそれを含むメソッドの変数にアクセスする必要がある場合は、その変数を final にする必要があります。
それ以外は、あなたの言っていることは正しいです。
あなたが言及したように、多少のトレードオフがありますが、暗黙の使用よりも明示的な使用を好みます。これは、コードの将来のメンテナーにとって、あいまいさを取り除くのに役立ちます-たとえそれがあなただけであっても。
final
その変数を次のように作成する場合は、変数にキーワードを使用しますimmutable
変数を final として宣言することにより、開発者は高度なマルチスレッド環境での変数の変更に関する問題を排除できます。
Java 8 リリースでは、「effectively final variable
」という概念がもう 1 つあります。非最終変数は、最終変数としてヒーブできます。
ラムダ式から参照されるローカル変数は final または実質的に final でなければなりません
変数は、ローカル ブロックでの初期化後に変更されていない場合、有効な finalと見なされます。これは、実質的に final でなければならない場合、匿名クラスまたはラムダ式内で final キーワードなしでローカル変数を使用できるようになったことを意味します。
Java 7 までは、匿名クラス内で非 final ローカル変数を使用できませんでしたが、Java 8 以降では使用できます。