33

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

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

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

  1. 使用java.lang.Integer代替原始类型int
  2. 使用 -1 表示“未知”值

有没有人有更好的选择或想法?

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

4

13 回答 13

33

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

于 2009-06-12T05:32:46.550 回答
27

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

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

于 2009-06-12T05:36:25.060 回答
16

数以万计的 Integer 实例并不是很多。考虑花费几百千字节而不是过早地优化。为正确性付出的代价很小。

谨防使用类似nullor的标记值0。这基本上等于说谎,因为0不是一年,null也不是整数。常见的错误来源,特别是如果您在某些时候不是软件的唯一维护者。

考虑使用类型安全的 null,例如Option,有时称为Maybe. 在 Scala 和 Haskell 等语言中很流行,这就像一个包含一个或零个元素的容器。您的字段将具有 type Option<Integer>,它将您的 year 字段的可选性质通告给类型系统,并强制其他代码处理可能丢失的年份。

这是一个包含 Option 类型的库。

如果您使用它,以下是调用代码的方式:

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.
}
于 2009-06-12T06:15:48.380 回答
2

另一种选择是有一个相关的boolean标志来指示您的年份值是否有效。这个标志false意味着年份是“未知的”。这意味着您必须检查一个基元(布尔值)以了解您是否有值,如果有,请检查另一个基元(整数)。

哨兵值通常会导致代码脆弱,因此值得努力避免哨兵值,除非您非常确定它永远不会成为用例。

于 2009-06-12T05:32:01.560 回答
1

您可以使用常规 int,但使用诸如Integer.MAX_VALUEInteger.MIN_VALUE定义为常量的值作为无效日期。更明显的是-1或者低负值是无效的,肯定不会像我们习惯看到的4位数的日期。

于 2009-06-12T06:06:48.747 回答
1

如果您有一个整数并且担心 null 的任意值可能会与实际值混淆,您可以使用 long 来代替。它比使用 Integer 更有效,并且 Long.MIN_VALUE 不接近任何有效的 int 值。

于 2009-06-12T06:26:57.200 回答
1

为了完整起见,另一种选择(绝对不是最有效的)是使用包装类Year

class Year {
    public int year;
    public Year(int year) { this.year = year; }
}

Year documentYear = null;
documentYear = new Year(2013);

或者,如果它更具语义性,或者您想要多种类型的可空整数(除年份),您可以模仿 C# 可空原语,如下所示:

class Int {
    public int value;
    public Int(int value) { this.value = value; }
    @Override 
    public String toString() { return value; }
}
于 2013-04-15T06:06:30.510 回答
1

使用int原语与Integer类型是过早优化的完美示例。

如果你做数学:

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

因此,对于 10,000 个整数,它将花费 40,000 字节或 40k。对于 10,000 个整数,它将花费 160,000 字节或 160K。如果您考虑处理图像/照片/视频数据所需的内存量,这实际上可以忽略不计。

我的建议是,不要浪费时间过早地基于变量类型进行优化,而是寻找一种可以轻松处理所有数据的良好数据结构。不管你怎么做,除非你单独定义 10K 个原始变量,否则无论如何它都会在堆上结束。

于 2014-02-22T10:48:01.293 回答
0

java.lang.Integer 有什么问题?这是一个合理的解决方案,除非您可能要存储大量此值。

如果您想使用原语,-1 值也是一个很好的解决方案。您唯一的其他选择是使用单独的布尔标志,就像有人已经建议的那样。选择你的毒药:)

PS:该死的,我试图在对象与结构上撒一点善意的谎言。我的观点是它使用更多的内存,类似于布尔标志方法,尽管在语法上可空类型当然更好。另外,我不确定具有 Java 背景的人是否知道我对struct的含义。

于 2009-06-12T05:35:55.233 回答
0

java.lang.Integer 对于这种情况是合理的。而且它已经实现了可序列化,因此您只能将年份字段保存到 HDD 并将其加载回来。

于 2010-07-23T02:22:25.317 回答
0

另一种选择可能是在内部使用特殊值(-1 或 Integer.MIN_VALUE 或类似),但将整数公开为两种方法:

hasValue() {
    return (internalValue != -1);
}

getValue() {
    if (internalValue == -1) {
        throw new IllegalStateException(
            "Check hasValue() before calling getValue().");
    }
    return internalValue;
}
于 2011-11-22T11:31:40.557 回答
0

如果你要节省内存,我建议在一个int. 因此0nil。然后您可以做出假设以进行优化。如果您只使用当前日期,例如 1970-2014 年,您可以从所有这些日期中减去 1969 年并进入1—55范围。这样的值只能用 6 位编码。因此,您可以将int始终为 32 位的数据划分为 4 个区域,其中包含一年。这样,您可以将 1970-2226 范围内的 4 年打包到一个int. 您的范围越窄,例如只有 2000-2014 年(4 位),您可以在单个int.

于 2014-02-22T11:35:31.097 回答
0

如果使用 java 7,您可以使用 @Nullable 注释

于 2015-01-07T06:44:43.780 回答