如何在Java中呈现可空的原始类型int?

时间:2009-06-12 05:28:42

标签: java nullable

我正在设计一个实体类,它有一个名为“documentYear”的字段,可能有无符号整数值,如1999,2006等。同时,这个字段也可能是“未知”,也就是说,不确定哪一年文档已创建。

因此,C#中可以为空的 int 类型将非常适合。但是,Java没有像C#那样可以为空的特性。

我有两个选择,但我不喜欢它们:

  1. 使用java.lang.Integer代替原始类型int;
  2. 使用-1表示“未知”值
  3. 有没有人有更好的选择或想法?

    更新:我的实体类将拥有数万个实例;因此,java.lang.Integer的开销可能对系统的整体性能来说太重了。

13 个答案:

答案 0 :(得分:32)

这里使用Integer类可能就是你想要做的。与对象相关的开销很可能(尽管不一定)对应用程序的整体响应和性能微不足道。

答案 1 :(得分:27)

您将不得不抛弃原始类型或使用一些任意的int值作为“无效年份”。

负值实际上是一个不错的选择,因为有一个有效年份的可能性很小,导致整数溢出并且没有有效的负面年份。

答案 2 :(得分:15)

成千上万的Integer实例并不是很多。考虑花费几百千字节而不是过早优化。支付正确性是一个很小的代价。

谨防使用null0之类的标记值。这基本上等于说谎,因为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_VALUEInteger.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 原语与整数类型是过早优化的完美示例。

如果你做数学运算:

  • int = N(4)
  • 整数= N(16)

因此,对于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内打包几年。因此0nil。然后你可以做出假设以便优化。如果您只使用当前日期,例如1970-2014年,您可以从所有日期中减去1969并进入1—55范围。这些值只能用6位编码。因此,您可以将总是32位的int划分为4个区域,其中包含一年。通过这种方式,您可以将1970-2226范围内的4年打包成一个int。您的范围越窄,例如只有2000-2014(4位),您可以在一个int中打包的年数就越多。

答案 12 :(得分:0)

如果使用java 7

,可以使用@Nullable注释