JavaにはBoolean(クラス)とboolean(プリミティブ)があります。同様に、Integer(クラス)とint(プリミティブ)があります。プリミティブバージョンvsを使用する場合のベストプラクティスは何ですかクラス?特定の(パフォーマンス?)理由がない限り、基本的に常にクラスバージョンを使用する必要がありますか?それぞれを使用する最も一般的に受け入れられている方法は何ですか?
Joshua Blochは、Effective JavaのItem 5で次のように述べています。
レッスンは明確です:ボックス化されたプリミティブよりもプリミティブを優先し、意図しない自動ボクシングに注意してください。
クラスの1つの有効な使用法は、それらをジェネリックタイプとして使用する場合(リストやマップなどのコレクションクラスを含む)、または暗黙的なキャストなしで他のタイプに変換する場合です(たとえば、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
がLong sum
に追加されるたびに)。 sumの宣言をLong
からlong
に変更すると、私のマシンのランタイムが43秒から6.8秒に短縮されます。
ジェネリックを扱っていない限り、標準的な方法はプリミティブを使用することです( autoboxing&unboxing !に注意してください)。
規約に従う理由はいくつかあります。
1。あなたは簡単な間違いを避けます:
初心者によく気付かれない、いくつかの微妙で直感的でないケースがあります。経験豊富なコーダーでさえ、時々失敗してこれらのミスを犯します(うまくいけば、コードをデバッグしてエラーを見つけたときに、これに誓うことができます!)。
最もよくある間違いは、a.equals(b)
ではなくa == b
を使用することです。人々はプリミティブを使用してa == b
を実行することに慣れているため、Objectラッパーを使用すると簡単に実行できます。
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に同意する場合、これはコードを複雑にする最適化ですless!
4。それは慣習です:
他のJavaプログラマーの99%に対して異なるスタイルの選択を行う場合、2つの欠点があります。
通常、私はいくつかの対抗点を挙げますが、正直に言って、ここでの慣習を採用しない理由はありません。
通常、プリミティブを使用します。ただし、Integer
やBoolean
などのクラスを使用する場合の1つの特徴は、null
をこれらの変数に割り当てる可能性です。もちろん、これは常にnull
チェックを実行する必要があることを意味しますが、int
またはboolean
を使用するために論理エラーが発生するよりも、NullPointerExceptionを取得する方が適切です。正しく初期化されていない変数。
もちろん、Java 8なので、次のステップに進むことができます(おそらくそうすべきです)。たとえば、Integer
の代わりにOptional<Integer>
は、値が含まれる場合と含まれない場合があります。
さらに、null
を使用してこれらの変数に "unknown"または "wildcard "値。これは、たとえば Ternary Logic の場合など、状況によっては便利です。または、特定のオブジェクトがテンプレートと一致するかどうかを確認することもできます。この場合、オブジェクトの任意の値を持つことができるテンプレートの変数にnull
を使用できます。
素人の言葉で:
コレクションに何かを追加する必要がある場合は、ラッパーを使用します。
コレクションはプリミティブを保持できません。
M3th0dmanが指摘したように、Javaはオートボクシングを備えています。可能な限り低いレベルで考えてみると、プリミティブ値のオートボクシング(インまたはアウト)は、アプリケーションの周りでネイティブデータ型を操作している場合、不要なタスクで費やされるクロックサイクルを意味することがわかります。
原則として、可能な限りネイティブデータ型を使用するようにしてください。