web-dev-qa-db-ja.com

Javaでプリミティブとクラスを使用する場合

JavaにはBoolean(クラス)とboolean(プリミティブ)があります。同様に、Integer(クラス)とint(プリミティブ)があります。プリミティブバージョンvsを使用する場合のベストプラクティスは何ですかクラス?特定の(パフォーマンス?)理由がない限り、基本的に常にクラスバージョンを使用する必要がありますか?それぞれを使用する最も一般的に受け入れられている方法は何ですか?

56
Casey Patton

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 iLong sumに追加されるたびに)。 sumの宣言をLongからlongに変更すると、私のマシンのランタイムが43秒から6.8秒に短縮されます。

49
m3th0dman

ジェネリックを扱っていない限り、標準的な方法はプリミティブを使用することです( 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つの欠点があります。

  • 他の人のコードは読みにくくなります。そこにある例/チュートリアルなどの99%はプリミティブを使用します。あなたがそれを読むときはいつでも、あなたが慣れているスタイルでそれがどのように見えるかについて考えることの余分な認知オーバーヘッドがあります。
  • 他の人はあなたのコードを読みにくくするでしょう。 Stack Overflowで質問をするときはいつでも、「プリミティブを使用していないのはなぜですか」と尋ねる回答/コメントをふるいにかける必要があります。あなたが私を信じていないなら、生成されたコードにさえ影響を与えないブラケット配置のようなものに関して人々が持っている戦いを見てください!

通常、私はいくつかの対抗点を挙げますが、正直に言って、ここでの慣習を採用しない理由はありません。

30
vaughandroid

通常、プリミティブを使用します。ただし、IntegerBooleanなどのクラスを使用する場合の1つの特徴は、nullをこれらの変数に割り当てる可能性です。もちろん、これは常にnullチェックを実行する必要があることを意味しますが、intまたはbooleanを使用するために論理エラーが発生するよりも、NullPointerExceptionを取得する方が適切です。正しく初期化されていない変数。

もちろん、Java 8なので、次のステップに進むことができます(おそらくそうすべきです)。たとえば、Integerの代わりにOptional<Integer>は、値が含まれる場合と含まれない場合があります。

さらに、nullを使用してこれらの変数に "unknown"または "wildcard "値。これは、たとえば Ternary Logic の場合など、状況によっては便利です。または、特定のオブジェクトがテンプレートと一致するかどうかを確認することもできます。この場合、オブジェクトの任意の値を持つことができるテンプレートの変数にnullを使用できます。

12
tobias_k

素人の言葉で:

コレクションに何かを追加する必要がある場合は、ラッパーを使用します。

コレクションはプリミティブを保持できません。

2

M3th0dmanが指摘したように、Javaはオートボクシングを備えています。可能な限り低いレベルで考えてみると、プリミティブ値のオートボクシング(インまたはアウト)は、アプリケーションの周りでネイティブデータ型を操作している場合、不要なタスクで費やされるクロックサイクルを意味することがわかります。

原則として、可能な限りネイティブデータ型を使用するようにしてください。

0
Silvarion