業界で「最終」キーワードがほとんど使用されないのはなぜですか?[閉まっている]


14

final数年前にJavaでキーワードのパワーを発見したので、読み取り専用の変数を簡単に確認できるため、コードをより読みやすくするのに役立ちました。また、JITを少し強化することもありますが、これは非常に限定的なものですが、特にAndroidプラットフォームなどの組み込みデバイスを対象とする場合は害はありません。

しかし、何よりも、変更に対する設計の堅牢性を高め、コードベースを変更する必要がある場合に他のコミッターを導くことに貢献します。

ただし、JDKソースコードの一部を参照しているときに、クラス、メソッド、または変数のいずれについても、このキーワードにつまずくことはありませんでした。私がレビューしなければならなかったさまざまなシステムにも同じことが当てはまります。

理由はありますか?内部からすべてを可変にするのは一般的な設計パラダイムですか?


ミクロの最適化では、設定finalフィールドは、書き込みと同じ意味があるvolatileフィールドをし、後でそれを読んだことは揮発性の読み取り意味を持っている必要があり、これは必ずしもあなたが望むもの
ラチェットフリーク

5
@ratchet:これは、関数型プログラミングの場合のように、クラスを不変にすることに関するものだと思います。
ジョナス

@Kwebble:おそらくもっと重要なのは、個々のString インスタンスが不変であることです。
MatrixFrog

回答:


9

表示されない理由は、JDKが拡張されるように設計されているためであると思われます(これは、すべてのプログラムが構築される基盤です)。アプリケーションコードがそれを利用することは珍しくありません。また、ライブラリコードにも多くのコードが表示されることは期待していません(ライブラリは拡張用に設計されていることが多いため)。

いくつかの優れたオープンソースプロジェクトを見てみてください。もっと見つけられると思います。

あなたがJavaで見ているものとは対照的に、.NETの世界ではsealed、クラスがデフォルトで(クラスに適用されるfinalに似ている)、開発者が明示的に開封するべきであるという議論を何度も聞いたことがありますそれ。


2
私は、明らかに「一度生成され、オーバーライドしない」オブジェクト変数であるいくつかのJDKクラスの多くのプライベートまたは保護されたメンバーについても言及していました。特にスイングパッケージで。これらは、コンポーネントを使用するときにエラーを引き起こす可能性があるため、「最終」の完璧な候補です。
オーレリアンリボン

1
@Aurélien:気分が良くなると、.NET Frameworkのクラスの多くが封印され、独自の機能を使用してフレームワーククラスを拡張したい一部のユーザーを驚かせます。ただし、この制限は、拡張メソッド
ロバートハーベイ

1
これは、拡張を避けることよりも不変性に関することだと思います。言い換えれば、finalメソッドではなくフィールドでの使用。不変クラスは、拡張するように設計することもできます。
ジョナス

15

final何かが読み取り専用であることを伝えるために使用する際の問題はintcharなどのプリミティブ型に対してのみ実際に機能することです。Javaのすべてのオブジェクトは、実際には(種類の)ポインターを使用して参照されます。その結果、finalオブジェクトでキーワードを使用する場合、参照は読み取り専用であり、オブジェクト自体はまだ変更可能であると言っているだけです。

実際にオブジェクトを読み取り専用にした場合は、さらに使用されている可能性があります。C ++ではまさにconstそれが行われ、その結果、はるかに便利で頻繁に使用されるキーワードになります。

finalキーワードを頻繁に使用する1つの場所は、次のようなことによって生じる混乱を避けるためのパラメーターの使用です。

public void someMethod(FancyObject myObject) {
    myObject = new FancyObject();
    myObject.setProperty(7);
}
...
public static void main(final String[] args) {
    ...
    FancyObject myObject = new FancyObject();
    someOtherObject.someMethod(myObject);
    myObject.getProperty(); // Not 7!
}

この例では、なぜこれが機能しないのかが明らかなように思えsomeMethod(FancyObject)ますが、それが大きく複雑な混乱が発生する可能性がある。避けてみませんか?

また、Sun(または、現在ではOracleと思われる)コーディング標準の一部でもあります。


1
finalJava APIクラスでさらに使用されている場合、ほとんどのオブジェクトは多くのScalaライブラリと同様に不変でした。次に、オブジェクトフィールドをfinal作成すると、多くの場合クラスが不変になります。このデザインは、BigDecimalとですでに使用されていStringます。
ジョナス

@Jonas私はschmmdの答えのポイント4についての質問を読んだので、彼は「人々は読み取り専用変数を簡単に見ることができるので」と言っていたので、それに応じて答えました。たぶん私は答えにその仮定を含めるべきだった。
ギャン別名ゲイリー

パラメーターを再割り当てする時間があることに注意してください。例として、文字列パラメーターのトリミングがあります。
スティーブクオ

@Steve私は通常、そのような状況で割り当てられる新しい変数を作成します。
ギャン別名ゲイリー

1
@Gary、少なくとも私にとっては、パラメーターの再割り当てによってバグ/混乱が引き起こされることは非常にまれです。私はむしろ混乱のないコードを持ち、バグを引き起こすパラメータを再割り当てするリモートチャンスを受け入れたいです。コードを記述/変更するときは注意してください。
スティーブクオ

4

finalキーワードが読みやすさを向上させることに同意します。これにより、オブジェクトが不変であることを理解しやすくなります。ただし、Javaでは、特に(私の意見では)パラメーターで使用すると、非常に冗長になります。これは、ユーザーが冗長であるために使用すべきではないと言うことではなく、冗長であるため使用しないことです。

scalaなどの他の言語を使用すると、最終宣言(val)がはるかに簡単になります。これらの言語では、変数よりも最終的な宣言が一般的です。

finalキーワードにはさまざまな用途があることに注意してください。あなたの投稿は主にアイテム2と3をカバーしています。

  1. 最終クラス(JLS 8.1.1.2)
  2. 最終フィールド(JLS 8.3.1.2)
  3. 最終メソッド(JLS 8.4.3.3)
  4. 最終変数(JLS 4.12.4)

2

そもそも、公式のJava Code Conventionsは、の特定の使用を支持も禁止もしていませんfinal。つまり、JDK開発者は好みの方法を自由に選択できます。

私は彼らの心を読むことはできませんが、私にとって、使用するかどうかの好みfinalは焦点の問題でした。コードに完全に集中するのに十分な時間があるかどうかの問題。

  • たとえば、私のプロジェクトの1つでは、100行程度のコードに1 平均で費やすことができます。このプロジェクトでfinalは、コード内で既に十分に明確に表現されているものを不明瞭にするだけのごみとしての明確な認識がありました。JDK開発者もそのカテゴリに分類されるようです。
     
    一方、別のプロジェクトではまったく反対で、100行のコードに平均1時間を費やしました。そこで、私は自分final自身や他のコードでマシンガンのように射撃していることを発見しました-それは単にそれが私の前に書いた人の意図を検出する最も簡単な方法であり、同様に、私自身の意図を後で私のコードに取り組む人。

また、JITを少し強化することもありますが、それは非常に限定的なものですが、害はありません

上記のような推論は滑りやすいです。時期尚早な最適化は害を及ぼす可能性があります。ドナルド・クヌースはそれを「すべての悪の根」と呼んでいます。それはあなたを閉じ込めてはいけません。ダムコードを書いてください


2

最近、私はEclipse IDEの「アクションを保存」機能の喜びを発見しました。コードを再フォーマットし、欠落している@Override注釈を挿入し、式の不要な括弧を削除したり、finalヒットするたびに自動的にキーワードをすべての場所に配置するなど、気の利いたことを行うことができctrl + Sます。私はそれらのトリガーのいくつかをアクティブにしました、そして、少年、それは大いに役立ちます!

これらのトリガーの多くは、私のコードの簡単な健全性チェックのように機能することが判明しました。

  • メソッドをオーバーライドするつもりでしたが、ヒットしたときに注釈が表示されませんでしたctrl + sか?-おそらくどこかでパラメーターの種類を台無しにしたのでしょう!
  • 保存時にコードから括弧が削除されましたか?-多分その論理式は、プログラマーがすぐに動き回るには難しすぎる。さもなければ、なぜそれらの括弧を最初に追加するのでしょうか?
  • そのパラメーターまたはローカル変数はfinalです。それはありません持って、その値を変更するには?

変数が少ないほど、デバッグ時のトラブルが少なくなることがわかりました。変数の値をたどって5から7に何らかの形で変化することを見つけるためだけに、変数の値を何回たどりましたか?「なんてこった!」自問自答し、数時間かけて数え切れないほど多くのメソッドに出入りして、ロジックに誤りがあることを確認します。そして、それを修正するために、もう1つのフラグ、いくつかの条件を追加し、いくつかの値をあちこちで慎重に変更する必要があります。

ああ、私はデバッグが嫌いです!私は私が私の時間のように感じるデバッガを実行するたびに出て実行されていると私は必死に少なくとも作るためにその時必要ないくつかの真になるために私の子供の頃の夢のを!デバッグで地獄に!finalsは、神秘的な価​​値の変化がこれ以上ないことを意味します。より多くfinalのs =>コード内の薄っぺらい部分が少ない=>バグが少ない=>良いことをするためのより多くの時間!

finalクラスとメソッド私は本当に気にしません。ポリモーフィズムが大好きです。多態性とは、再利用とは、コードの削減とバグの削減のことです。とにかく、JVMは仮想化とメソッドのインライン化でかなり良い仕事をするので、不当なパフォーマンスの利点のためにコードを再利用する可能性を殺すことに価値がありません。


finalコード内のこれらすべてを見ると、最初は多少気が散り、慣れるのにも時間がかかります。私のチームメイトの中には、非常に多くのfinalキーワードを見るとまだ非常に驚いています。IDEに特別な構文の色付けの設定があればいいのにと思います。コードを読むときに邪魔にならないように、グレーのシェード(注釈など)に切り替えていただければ幸いです。現在、Eclipseにはreturnとのすべてのキーワードに対して個別の色がありますが、はありませんfinal


1
OCamlやF#などの関数型言語を検討することを検討できます。これらの言語では、必要なデバッグがはるかに少なくなる傾向があります。これは、デフォルトではすべてが読み取り専用であるためです。関数型言語の変数は、一度割り当てられると変更されません。
アベル

1
ええ、私はそれを知っていて、実際に時々MLコードをいくつか書いています-それは私がインスピレーションを得たところです:)それはあなたが使用する言語ではなく、あなたが適用する原則と技術に関するものです Haskellとdo表記法ですべての命令を実行できます:)確かに、Javaは機能的なスタイルで書くのに最適な言語ではありませんが、少なくとも堅牢なコードを書くことができます-そしてそれは私が本当に気にしていることです。
アンドリューАндрейЛисточкин11年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.