Javaにはブール(クラス)対ブール(プリミティブ)があることがわかります。同様に、整数(クラス)対int(プリミティブ)があります。クラスに対してプリミティブバージョンを使用する場合のベストプラクティスは何ですか?特定の(パフォーマンス?)理由がない限り、基本的に常にクラスバージョンを使用する必要がありますか?それぞれを使用する最も一般的で受け入れられている方法は何ですか?
Javaにはブール(クラス)対ブール(プリミティブ)があることがわかります。同様に、整数(クラス)対int(プリミティブ)があります。クラスに対してプリミティブバージョンを使用する場合のベストプラクティスは何ですか?特定の(パフォーマンス?)理由がない限り、基本的に常にクラスバージョンを使用する必要がありますか?それぞれを使用する最も一般的で受け入れられている方法は何ですか?
回答:
効果的なJavaの項目5で、Joshua Blochは言います
教訓は明確です。ボックス化されたプリミティブよりもプリミティブを優先し、意図しないオートボクシングに注意してください。
クラスの良い使用法の1つは、それらをジェネリック型(リストやマップなどのCollectionクラスを含む)として使用する場合、または暗黙のキャストなしで他の型に変換する場合(Integer
クラスにメソッドdoubleValue()
またはがある場合など)byteValue()
です。
編集:ジョシュアブロッホの理由:
// Hideously slow program! Can you spot the object creation? public static void main(String[] args) { Long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum); }
このプログラムは正しい答えを取得しますが、1文字の誤植により、本来よりもはるかに遅いです。変数
sum
はのLong
代わりにとして宣言されますlong
。これは、プログラムが約2 ^ 31個の不要なLong
インスタンス(long i
がに追加されるたびに1つ)を構築することを意味しますLong sum
。合計の宣言をからLong
に変更するlong
と、マシンのランタイムが43秒から6.8秒に短縮されます。
標準的な方法は、ジェネリックを扱う場合を除き、プリミティブを使用することです(オートボックス化とボックス化解除に注意してください!)。
規則に従うことには、いくつかの正当な理由があります。
1.単純な間違いを避けます。
多くの場合、初心者をキャッチするいくつかの微妙な、非直感的なケースがあります。経験豊富なコーダーでさえ、時折スリップしてこれらの間違いを犯します(コードをデバッグしてエラーを見つけたときに宣誓が続くことを願っています!)。
最も一般的な間違いは、のa == b
代わりに使用することですa.equals(b)
。人々はa == b
プリミティブを使用することに慣れているため、オブジェクトラッパーを使用しているときに簡単に実行できます。
Integer a = new Integer(2);
Integer b = new Integer(2);
if (a == b) { // Should be a.equals(b)
// This never gets executed.
}
Integer c = Integer.valueOf(2);
Integer d = Integer.valueOf(2);
if (c == d) { // Should be a.equals(b), but happens to work with these particular values!
// This will get executed
}
Integer e = 1000;
Integer f = 1000;
if (e == f) { // Should be a.equals(b)
// Whether this gets executed depends on which compiler you use!
}
2.読みやすさ:
次の2つの例を考えてみましょう。ほとんどの人は、2番目の方が読みやすいと言います。
Integer a = 2;
Integer b = 2;
if (!a.equals(b)) {
// ...
}
int c = 2;
int d = 2;
if (c != d) {
// ...
}
3.パフォーマンス:
事実は、プリミティブを使用するよりも、プリミティブにオブジェクトラッパーを使用する方が遅いということです。あらゆる場所で使用するものに、オブジェクトのインスタンス化、メソッド呼び出しなどのコストを追加しています。
Knuthの「...約97%の時間:早すぎる最適化がすべての悪の根源である」という引用は、ここでは実際には当てはまりません。彼は、コード(またはシステム)をより複雑にする最適化について話していました-もしあなたがポイント#2に同意するなら、これはコードをより単純にする最適化です!
4.慣例です:
他のJavaプログラマの99%に対して異なるスタイルの選択を行う場合、2つの欠点があります。
通常、私はいくつかの反論点をリストしますが、正直なところ、ここでコンベンションに参加しない理由は考えられません!
==
。オブジェクトはと比較する必要がありequals()
ます。
equals()
...オブジェクトを比較すると==
期待される結果が得られるように回避策を与えます。
equals()
2番目のコードスニペットに追加し、投票を変更しました。
通常、プリミティブを使用します。ただし、Integer
とのようなクラスを使用する1つの特性Boolean
は、null
これらの変数に割り当てる可能性です。もちろん、これはnull
常にチェックを行う必要があることを意味しますが、NullPointerExceptionを取得する方が、正しく初期化されていない変数int
またはboolean
変数を使用するために論理エラーが発生するよりも優れています。
もちろん、Java 8からさらに一歩進むことができ(おそらくそうすべきです)、代わりに、たとえば値を持っているか持っていない変数にInteger
使用することができOptional<Integer>
ます。
さらに、null
これらの変数に「不明」または「ワイルドカード」値を割り当てるために使用する可能性が導入されます。これは、Ternary Logicなどのいくつかの状況で便利です。または、特定のオブジェクトがテンプレートに一致するかどうかを確認することもできます。この場合null
、オブジェクト内の任意の値を持つことができるテンプレート内の変数に使用できます。
null
、デフォルトとして割り当てる機能から多くを得ることはありません。それどころか、変数を「初期化」しない方がいいでしょう。デフォルト値さえ設定null
すると、コンパイラーがシャットダウンしますが、すべてのコードパスに沿った有用な割り当ての欠如を検出できなくなります。したがって、コンパイラーがキャッチした可能性のあるエラーは、ランタイムにスリップします。
0.0
、または-1
、またはInteger.MAX_VALUE
、またはFalse
に設定できますが、最終的にそれがデフォルト値であるか、その変数に割り当てられた実際の値であるかはわかりません。これが重要な場合、null
値を設定することでより明確になる可能性があります。
null
は、nullパラノイアを含む多くの問題があります。)関数内では、使用時に実際に初期化されていない可能性がある変数は、通常、カバーされていないケースを示します。(明確な割り当て分析は単純化されているため、
素人の言葉で:
コレクションに物事を追加する必要がある場合は、ラッパーを使用します。
コレクションはプリミティブを保持できません。