我正在设计一个实体类,它有一个名为“documentYear”的字段,可能有无符号整数值,如1999,2006等。同时,这个字段也可能是“未知”,也就是说,不确定哪一年文档已创建。
因此,C#中可以为空的 int 类型将非常适合。但是,Java没有像C#那样可以为空的特性。
我有两个选择,但我不喜欢它们:
java.lang.Integer
代替原始类型int
; 有没有人有更好的选择或想法?
更新:我的实体类将拥有数万个实例;因此,java.lang.Integer的开销可能对系统的整体性能来说太重了。
答案 0 :(得分:32)
这里使用Integer类可能就是你想要做的。与对象相关的开销很可能(尽管不一定)对应用程序的整体响应和性能微不足道。
答案 1 :(得分:27)
您将不得不抛弃原始类型或使用一些任意的int值作为“无效年份”。
负值实际上是一个不错的选择,因为有一个有效年份的可能性很小,导致整数溢出并且没有有效的负面年份。
答案 2 :(得分:15)
成千上万的Integer实例并不是很多。考虑花费几百千字节而不是过早优化。支付正确性是一个很小的代价。
谨防使用null
或0
之类的标记值。这基本上等于说谎,因为0
不是一年,null
不是整数。一个常见的错误来源,特别是如果你在某些时候并不是软件的唯一维护者。
考虑使用类似Option
的类型安全空,有时称为Maybe
。在Scala和Haskell等语言中很流行,这就像一个有一个或零个元素的容器。您的字段将具有类型Option<Integer>
,它将年份字段的可选性质通告给类型系统,并强制其他代码处理可能缺少的年份。
Here's a library that includes the Option type.
以下是您使用它时如何调用代码:
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.
}
答案 3 :(得分:2)
另一种选择是使用关联的boolean
标志来指示您的年份值是否有效。这个标志为false
,意味着这一年“未知”。这意味着您必须检查一个基元(布尔值)以了解您是否有值,如果有,则检查另一个基元(整数)。
Sentinel值通常会导致代码很脆弱,因此除非您非常确定它永远不会成为用例,否则值得努力避免使用sentinel值。
答案 4 :(得分:1)
您可以使用常规int,但使用定义常量的Integer.MAX_VALUE
或Integer.MIN_VALUE
等值作为无效日期。更明显的是-1或低负值它是无效的,它肯定看起来不像我们习惯看到的4位数日期。
答案 5 :(得分:1)
如果你有一个整数并且担心null的任意值可能与实际值混淆,你可以使用long。它比使用Integer和Long更有效.MIN_VALUE在任何有效的int值附近都没有。
答案 6 :(得分:1)
为了完整性,另一个选项(绝对不是最有效的)是使用包装类Year
。
class Year {
public int year;
public Year(int year) { this.year = year; }
}
Year documentYear = null;
documentYear = new Year(2013);
或者,如果它更具语义,或者你想要多种类型的可为空的int(除了Years),你可以像这样模仿C#Nullable原语:
class Int {
public int value;
public Int(int value) { this.value = value; }
@Override
public String toString() { return value; }
}
答案 7 :(得分:1)
使用 int 原语与整数类型是过早优化的完美示例。
如果你做数学运算:
因此,对于10,000英镑,它将花费40,000字节或40k。对于10,000英镑,它将花费160,000字节或160K。如果您考虑处理图像/照片/视频数据所需的内存量几乎可以忽略不计。
我的建议是,退出浪费时间过早地根据变量类型进行优化,并寻找一个好的数据结构,这样可以轻松处理所有数据。无论你做什么,除非你单独定义10K原始变量,否则它最终会在堆上结束。
答案 8 :(得分:0)
java.lang.Integer有什么问题?这是一个合理的解决方案,除非您存储非常大量的此值。
如果你想使用基元,那么-1值也是一个很好的解决方案。你唯一的另一个选择是使用一个单独的布尔标志,就像有人建议的那样。选择你的毒药:)
PS:该死的,我试图在物体与结构上留下一点白色的谎言。我的观点是它使用了更多的内存,类似于布尔标志方法,尽管语法上可空类型当然更好。此外,我不确定具有Java背景的人是否会知道我对 struct 的含义。答案 9 :(得分:0)
java.lang.Integer对于这种情况是合理的。它已经实现了Serializable,因此您只需将年份字段保存到HDD并加载回来。
答案 10 :(得分:0)
另一种选择可能是在内部使用特殊值(-1或Integer.MIN_VALUE或类似值),但将整数公开为两种方法:
hasValue() {
return (internalValue != -1);
}
getValue() {
if (internalValue == -1) {
throw new IllegalStateException(
"Check hasValue() before calling getValue().");
}
return internalValue;
}
答案 11 :(得分:0)
如果您要节省内存,我建议您在一个int
内打包几年。因此0
是nil
。然后你可以做出假设以便优化。如果您只使用当前日期,例如1970-2014年,您可以从所有日期中减去1969并进入1—55
范围。这些值只能用6位编码。因此,您可以将总是32位的int
划分为4个区域,其中包含一年。通过这种方式,您可以将1970-2226范围内的4年打包成一个int
。您的范围越窄,例如只有2000-2014(4位),您可以在一个int
中打包的年数就越多。
答案 12 :(得分:0)
如果使用java 7
,可以使用@Nullable注释