プリミティブ型は二度と使用しないほうがよいでしょうか?

StackOverflow https://stackoverflow.com/questions/124148

  •  02-07-2019
  •  | 
  •  

質問

Java でプリミティブ データ型とそれぞれのラッパー クラスを混在して使用すると、多くのバグが発生する可能性があります。次の例は、この問題を示しています。

int i = 4;
...
if (i == 10)
  doStuff();

後で、変数が必要であることがわかりました 定義済みまたは未定義のいずれかになるため、上記のインスタンス化を次のように変更します。

Integer i = null;

ここで、等価性チェックは失敗します。

常にプリミティブ ラッパー クラスを使用するのは Java の良い習慣ですか?明らかにいくつかのバグを早期に取り除くことができますが、これにはどのような欠点があるのでしょうか?パフォーマンスやアプリケーションのメモリ使用量に影響しますか?何か卑劣な落とし穴はありますか?

役に立ちましたか?

解決

ボックスタイプを使用する する パフォーマンスとメモリの両方の問題があります。

比較を行うとき(例: (i == 10) )、Java は比較を行う前に型をボックス化解除する必要があります。使っても i.equals(TEN) == 構文よりもコストが高く、(IMO) 醜いメソッド呼び出しを使用します。

メモリに関しては、値自体を保存するだけでなく、オブジェクトもヒープに保存する必要があります (パフォーマンスにも影響します)。

卑劣な落とし穴? i.equals(j) 私がいるとき null.

私は、次の場合を除いて、常にプリミティブを使用します。 5月 なれ null, 、ただし常にチェックしてください null そのような場合は比較する前に。

他のヒント

まず、null に設定する機能を得るために、プリミティブの使用からオブジェクトの使用に切り替えるのは、おそらく設計上の決定としては間違っています。私は、null がセンチネル値であるかどうかについてよく同僚と議論します。私の意見は通常、null はそうではありません (したがって、センチネル値のように禁止すべきではない) ですが、この特定のケースでは、次のようになります。それをセンチネル値として使用するのは邪魔になりません。やめてください。整数が有効かどうかを示すブール値を作成するか、ブール値と整数を一緒にラップする新しい型を作成します。

通常、新しいバージョンの Java を使用する場合、1.5 (おそらく 1.5 自体) で追加されたオートボックス化サポートのおかげで、プリミティブのオブジェクト バージョンを明示的に作成したり、オブジェクト バージョンにキャストしたりする必要はありません。

本当に「null」の概念がない限り、常にプリミティブを使用することをお勧めします。

はい、VM はオートボックス化などを実行しますが、実際には予期しないコード行で null ポインター例外が発生し、null チェックを開始しなければならないという非常に奇妙なケースが発生する可能性があります。あらゆる数学的演算について。また、タイプを混合し始めて、奇妙なオートボックス動作が発生すると、いくつかの明らかではない動作が発生し始める可能性があります。

float/double の場合、NaN を null として扱うことができますが、NaN != NaN であるため、!Float.isNaN(x) のような特別なチェックが必要であることに注意してください。

ボクシングの時間/オーバーヘッドを無駄にする代わりに、プリミティブ型をサポートするコレクションがあれば本当に素晴らしいでしょう。

あなたの例では、if ステートメントは 127 を超えるまでは問題ありません (整数オートボクシングは 127 までの値をキャッシュし、この値までの各数値に対して同じインスタンスを返すため)。

つまり、あなたが提示したものよりも悪いものです...

if( i == 10 )

以前と同じように動作しますが、

if( i == 128 )

失敗します。このような理由から、私はオブジェクトが必要なときに常に明示的にオブジェクトを作成し、可能な限りプリミティブ変数にこだわる傾向があります。

これら 3 つの Java POD タイプには理由があります。オーバーヘッドのほかに、オブジェクトに対して通常の操作を行うことはできません。整数はオブジェクトであり、割り当てとガベージ コレクションが必要です。intはそうではありません。

その値が空である可能性がある場合は、設計に何か他のものが必要であることがわかるかもしれません。

可能性は 2 つあります。値が単なるデータであるか (値が入力されているかどうかでコードの動作は変わりません)、または実際にここに 2 つの異なるタイプのオブジェクトがあることを示しています (値が入力されているかどうかでコードの動作が異なります)。 null よりも値)

それが表示/保存用の単なるデータである場合は、実際の DTO (ファーストクラス メンバーとしてデータをまったく持たない DTO) の使用を検討することをお勧めします。これらには通常、値が設定されているかどうかを確認する方法があります。

ある時点で null をチェックする場合は、違いが 1 つあっても、通常はさらに多くの違いがあるため、サブクラスを使用することをお勧めします。少なくとも、「if primitiveIntValue == null」よりも違いを示すより良い方法が必要ですが、実際には何の意味もありません。

この機能を利用するためだけに非プリミティブに切り替えないでください。値が設定されているかどうかを示すにはブール値を使用します。この解決策が気に入らず、整数がある程度の妥当な制限内にあることがわかっている (または、時折発生する失敗を気にしない) 場合は、Integer.MIN_VALUE など、「初期化されていない」ことを示す特定の値を使用します。しかし、これはブール値よりもはるかに安全性の低い解決策です。

「後で」という時点に到達すると、リファクタリング中にもう少し作業を行う必要があります。可能な場合はプリミティブを使用してください。(Capital period) その後、さらに多くの機能が必要な場合は POJO を作成します。私の意見では、プリミティブ ラッパー クラスは、ネットワーク経由で移動する必要があるデータ、つまりネットワーク アプリに使用するのが最適です。許容値として null を許可すると、システムが「成長」するにつれて頭痛の種が生じます。単純な比較であるべきものを保護するために、非常に多くのコードが無駄になったり、見落とされたりしていました。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top