私は、「documentYear」という名前のフィールドを持つエンティティクラスを設計しています。このフィールドには、1999、2006などの符号なし整数値が含まれている可能性があります。一方、このフィールドも「不明」である可能性があります。つまり、ドキュメントの年が不明です。作成した。
したがって、C#のようなnullable intタイプが適しています。ただし、Javaには、C#のようにnull許容機能はありません。
私には2つのオプションがありますが、どちらも好きではありません。
Java.lang.Integer
プリミティブ型の代わりにint
;誰かがより良いオプションやアイデアを持っていますか?
更新:私のエンティティクラスには数万のインスタンスがあります。したがって、Java.lang.Integerのオーバーヘッドは、システム全体のパフォーマンスにとって重すぎる可能性があります。
プリミティブ型を破棄するか、「無効な年」として任意のint値を使用する必要があります。
整数のオーバーフローを引き起こす有効な年がある可能性がほとんどなく、有効な負の年がないため、負の値は実際には適切な選択です。
ここでのIntegerクラスの使用は、おそらくあなたがしたいことです。オブジェクトに関連するオーバーヘッドは、アプリケーションの全体的な応答性とパフォーマンスにとって(必ずしもそうとは限りませんが)取るに足らないものです。
Integerの数万のインスタンスは多くありません。時期尚早に最適化するのではなく、数百キロバイトを費やすことを検討してください。それは正確さのために支払うための小さな価格です。
null
や0
などのセンチネル値の使用に注意してください。 0
は年ではなく、null
は整数ではないため、これは基本的に嘘をつくことになります。バグの一般的な原因。特に、ある時点でソフトウェアの管理者があなただけではない場合。
Option
とも呼ばれる、Maybe
のようなタイプセーフなnullの使用を検討してください。 ScalaやHaskellなどの言語で人気があります。これは1つまたは0つの要素を持つコンテナのようなものです。フィールドのタイプはOption<Integer>
で、これは年フィールドのオプションの性質を通知します型システムに追加し、他のコードが不足している可能性のある年を処理するように強制します。
使用している場合にコードを呼び出す方法は次のとおりです。
partyLikeIts.setDocumentYear(Option.some(1999));
Option<Integer> y = doc.getDocumentYear();
if (y.isSome())
// This doc has a year
else
// This doc has no year
for (Integer year: y) {
// This code only executed if the document has a year.
}
もう1つのオプションは、年の値が有効かどうかを示すboolean
フラグを関連付けることです。このフラグがfalse
であることは、その年が「不明」であることを意味します。つまり、値があるかどうかを知るために1つのプリミティブ(ブール値)をチェックする必要があり、値がある場合は別のプリミティブ(整数)をチェックする必要があります。
センチネル値はしばしば脆弱なコードをもたらすので、それがユースケースにならないことが非常に確実でない限り、センチネル値を回避する努力をする価値があります。
通常のintを使用できますが、Integer.MAX_VALUE
やInteger.MIN_VALUE
などの定数を無効な日付として定義した値を使用します。また、-1またはそれが無効である低い負の値であることはより明白です。これは、私たちが慣れている4桁の日付のようには見えません。
完全を期すために、別のオプション(間違いなく最も効率的ではありません)は、ラッパークラスYear
を使用することです。
class Year {
public int year;
public Year(int year) { this.year = year; }
}
Year documentYear = null;
documentYear = new Year(2013);
または、よりセマンティックである場合、または複数のタイプのnull可能整数(年以外)が必要な場合は、次のようにC#Nullableプリミティブを模倣できます。
class Int {
public int value;
public Int(int value) { this.value = value; }
@Override
public String toString() { return value; }
}
intプリミティブとIntegerタイプの使用は、時期尚早の最適化の完璧な例です。
あなたが数学をするなら:
したがって、10,000整数の場合、40,000バイトまたは40kのコストがかかります。 10,000整数の場合、160,000バイトまたは160Kかかります。画像/写真/ビデオデータを処理するために必要なメモリの量を考慮すると、ほとんど無視できます。
私の提案は、変数型に基づいて時期尚早に最適化することで時間を無駄にするのをやめて、そのすべてのデータを簡単に処理できるようにする適切なデータ構造を探すことです。それを行うかどうかに関係なく、10Kのプリミティブ変数を個別に定義しない限り、とにかくヒープに到達することになります。
整数があり、nullの任意の値が実際の値と混同されることが懸念される場合は、代わりにlongを使用できます。 Integerを使用するよりも効率的で、Long.MIN_VALUEは有効なint値の近くにはありません。
この場合、Java.lang.Integerが妥当です。また、Serializableがすでに実装されているため、年フィールドのみをHDDに保存して、再度読み込むことができます。
別のオプションは、内部的に特別な値(-1またはInteger.MIN_VALUEまたは同様のもの)を使用することですが、整数を2つのメソッドとして公開します。
hasValue() {
return (internalValue != -1);
}
getValue() {
if (internalValue == -1) {
throw new IllegalStateException(
"Check hasValue() before calling getValue().");
}
return internalValue;
}
Java.lang.Integerの何が問題になっていますか?この値を非常に大量に保存しているのでない限り、これは合理的な解決策です。
プリミティブを使用したい場合は、-1の値も良い解決策です。あなたが持っている唯一の他のオプションは、すでに提案されている誰かのように、別個のブールフラグを使用することです。あなたの毒を選択してください:)
PS:くそー、私はオブジェクトと構造体の小さな白い嘘で逃げようとしていました。私の要点は、ブールフラグメソッドと同様に、より多くのメモリを使用するということでしたが、構文的にはnull許容型の方がより優れています。また、Javaバックグラウンドを持っている人がstructを使用して私が何を意味しているのかを知っているかどうかもわかりませんでした。
メモリを節約する場合は、数年分を1つのint
にパックすることをお勧めします。したがって、0
はnil
です。次に、最適化するために仮定を行うことができます。 1970年から2014年のように現在の日付だけで作業している場合は、それらすべてから1969を引いて1—55
の範囲に入ることができます。このような値は、6ビットのみでコード化できます。したがって、常に32ビットであるint
を、1つの年を含む4つのゾーンに分割できます。このようにして、1970〜2226の範囲の4年を1つのint
にパックできます。 2000-2014(4ビット)のように範囲が狭いほど、1つのint
にパックできる年数が多くなります。
Java 7を使用する場合、@ Nullableアノテーションを使用できます