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

时间:2022-04-24 16:28:36

I am designing an entity class which has a field named "documentYear", which might have unsigned integer values such as 1999, 2006, etc. Meanwhile, this field might also be "unknown", that is, not sure which year the document is created.

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

Therefore, a nullable int type as in C# will be well suited. However, Java does not have a nullable feature as C# has.

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

I have two options but I don't like them both:

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

  1. Use java.lang.Integer instead of the primitive type int;
  2. 使用java.lang.Integer而不是基本类型int;

  3. Use -1 to present the "unknown" value
  4. 使用-1表示“未知”值

Does anyone have better options or ideas?

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

Update: My entity class will have tens of thousands of instances; therefore the overhead of java.lang.Integer might be too heavy for overall performance of the system.

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

13 个解决方案

#1


27  

You're going to have to either ditch the primitive type or use some arbitrary int value as your "invalid year".

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

A negative value is actually a good choice since there is little chance of having a valid year that would cause an integer overflow and there is no valid negative year.

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

#2


32  

Using the Integer class here is probably what you want to do. The overhead associated with the object is most likely (though not necessarily) trivial to your applications overall responsiveness and performance.

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

#3


15  

Tens of thousands of instances of Integer is not a lot. Consider expending a few hundred kilobytes rather than optimise prematurely. It's a small price to pay for correctness.

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

Beware of using sentinel values like null or 0. This basically amounts to lying, since 0 is not a year, and null is not an integer. A common source of bugs, especially if you at some point are not the only maintainer of the software.

注意使用像null或0这样的标记值。这基本上等于说谎,因为0不是一年,而null不是整数。一个常见的错误来源,特别是如果你在某些时候并不是软件的唯一维护者。

Consider using a type-safe null like Option, sometimes known as Maybe. Popular in languages like Scala and Haskell, this is like a container that has one or zero elements. Your field would have the type Option<Integer>, which advertises the optional nature of your year field to the type system and forces other code to deal with possibly missing years.

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

Here's a library that includes the Option type.

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

Here's how you would call your code if you were using it:

以下是您使用它时如何调用代码:

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.
}

#4


2  

Another option is to have an associated boolean flag that indicates whether or not your year value is valid. This flag being false would mean the year is "unknown." This means you have to check one primitive (boolean) to know if you have a value, and if you do, check another primitive (integer).

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

Sentinel values often result in fragile code, so it's worth making the effort to avoid the sentinel value unless you are very sure that it will never be a use case.

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

#5


1  

You can use a regular int, but use a value such as Integer.MAX_VALUE or Integer.MIN_VALUE which are defined constants as your invalid date. It is also more obvious that -1 or a low negative value that it is invalid, it will certainly not look like a 4 digit date that we are used to seeing.

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

#6


1  

If you have an integer and are concerned that an arbitrary value for null might be confused with a real value, you could use long instead. It is more efficient than using an Integer and Long.MIN_VALUE is no where near any valid int value.

如果你有一个整数并且担心null的任意值可能与实际值混淆,你可以使用long。它比使用Integer和Long更有效.MIN_VALUE在任何有效的int值附近都没有。

#7


1  

For completeness, another option (definitely not the most efficient), is to use a wrapper class Year.

为了完整性,另一个选项(绝对不是最有效的)是使用包装类Year。

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

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

Or, if it is more semantic, or you want multiple types of nullable ints (Other than Years), you can imitate C# Nullable primitives like so:

或者,如果它更具语义,或者您想要多种类型的可空内注(除了Years),您可以模仿C#Nullable原语,如下所示:

class Int {
    public int value;
    public Int(int value) { this.value = value; }
    @Override 
    public String toString() { return value; }
}

#8


1  

Using the int primitive vs the Integer type is a perfect example of premature optimization.

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

If you do the math:

如果你做数学:

  • int = N(4)
  • int = N(4)

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

So for 10,000 ints it'll cost 40,000 bytes or 40k. For 10,000 ints it'll cost 160,000 bytes or 160K. If you consider the amount of memory required to process images/photos/video data that's practically negligible.

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

My suggestion is, quit wasting time prematurely optimizing based on variable types and look for a good data structure that'll make it easy to process all that data. Regardless of that you do, unless you define 10K primitive variables individually, it's going to end up on the heap anyway.

我的建议是,不要浪费时间过早地根据变量类型进行优化,并寻找一个好的数据结构,这样可以很容易地处理所有数据。无论你做什么,除非你单独定义10K原始变量,否则它最终会在堆上结束。

#9


0  

What's wrong with java.lang.Integer? It's a reasonable solution, unless you're storing very large amounts of this value maybe.

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

If you wanted to use primitives, a -1 value would be a good solution as well. The only other option you have is using a separate boolean flag, like someone already suggested. Choose your poison :)

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

PS: damn you, I was trying to get away with a little white lie on the objects vs structs. My point was that it uses more memory, similar to the boolean flag method, although syntactically the nullable type is is nicer of course. Also, I wasn't sure someone with a Java background would know what I meant with a struct.

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

#10


0  

java.lang.Integer is reasonable for this case. And it already implemented Serializable, so you can save just only the year field down to the HDD and load it back.

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

#11


0  

Another option might be to use a special value internally (-1 or Integer.MIN_VALUE or similar), but expose the integer as two methods:

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

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

getValue() {
    if (internalValue == -1) {
        throw new IllegalStateException(
            "Check hasValue() before calling getValue().");
    }
    return internalValue;
}

#12


0  

If you're going to save memory, I would suggest packing several years in a single int. Thus 0 is nil. Then you can make assumptions in order to optimize. If you are working only with the current dates, like years 1970—2014, you can subtract 1969 from all of them and get into 1—55 range. Such values can be coded with only 6 bits. So you can divide your int which is always 32 bit, into 4 zones, with a year in there. This way you can pack 4 years in the range 1970—2226 into a single int. The more narrow your range is, like only 2000—2014 (4 bits), the more years you can pack in a single int.

如果你要节省内存,我建议在一个int中打包几年。因此0是零。然后你可以做出假设以便优化。如果您只使用当前日期,例如1970-2014年,您可以从所有这些日期中减去1969并进入1-55范围。这些值只能用6位编码。因此,您可以将总是32位的int分成4个区域,其中有一年。通过这种方式,您可以将1970-2226范围内的4年打包成一个整数。你的范围越窄,比如2000-2014(4位),你可以在一个int中打包的年数越多。

#13


0  

You could use the @Nullable annotation if using java 7

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

#1


27  

You're going to have to either ditch the primitive type or use some arbitrary int value as your "invalid year".

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

A negative value is actually a good choice since there is little chance of having a valid year that would cause an integer overflow and there is no valid negative year.

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

#2


32  

Using the Integer class here is probably what you want to do. The overhead associated with the object is most likely (though not necessarily) trivial to your applications overall responsiveness and performance.

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

#3


15  

Tens of thousands of instances of Integer is not a lot. Consider expending a few hundred kilobytes rather than optimise prematurely. It's a small price to pay for correctness.

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

Beware of using sentinel values like null or 0. This basically amounts to lying, since 0 is not a year, and null is not an integer. A common source of bugs, especially if you at some point are not the only maintainer of the software.

注意使用像null或0这样的标记值。这基本上等于说谎,因为0不是一年,而null不是整数。一个常见的错误来源,特别是如果你在某些时候并不是软件的唯一维护者。

Consider using a type-safe null like Option, sometimes known as Maybe. Popular in languages like Scala and Haskell, this is like a container that has one or zero elements. Your field would have the type Option<Integer>, which advertises the optional nature of your year field to the type system and forces other code to deal with possibly missing years.

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

Here's a library that includes the Option type.

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

Here's how you would call your code if you were using it:

以下是您使用它时如何调用代码:

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.
}

#4


2  

Another option is to have an associated boolean flag that indicates whether or not your year value is valid. This flag being false would mean the year is "unknown." This means you have to check one primitive (boolean) to know if you have a value, and if you do, check another primitive (integer).

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

Sentinel values often result in fragile code, so it's worth making the effort to avoid the sentinel value unless you are very sure that it will never be a use case.

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

#5


1  

You can use a regular int, but use a value such as Integer.MAX_VALUE or Integer.MIN_VALUE which are defined constants as your invalid date. It is also more obvious that -1 or a low negative value that it is invalid, it will certainly not look like a 4 digit date that we are used to seeing.

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

#6


1  

If you have an integer and are concerned that an arbitrary value for null might be confused with a real value, you could use long instead. It is more efficient than using an Integer and Long.MIN_VALUE is no where near any valid int value.

如果你有一个整数并且担心null的任意值可能与实际值混淆,你可以使用long。它比使用Integer和Long更有效.MIN_VALUE在任何有效的int值附近都没有。

#7


1  

For completeness, another option (definitely not the most efficient), is to use a wrapper class Year.

为了完整性,另一个选项(绝对不是最有效的)是使用包装类Year。

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

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

Or, if it is more semantic, or you want multiple types of nullable ints (Other than Years), you can imitate C# Nullable primitives like so:

或者,如果它更具语义,或者您想要多种类型的可空内注(除了Years),您可以模仿C#Nullable原语,如下所示:

class Int {
    public int value;
    public Int(int value) { this.value = value; }
    @Override 
    public String toString() { return value; }
}

#8


1  

Using the int primitive vs the Integer type is a perfect example of premature optimization.

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

If you do the math:

如果你做数学:

  • int = N(4)
  • int = N(4)

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

So for 10,000 ints it'll cost 40,000 bytes or 40k. For 10,000 ints it'll cost 160,000 bytes or 160K. If you consider the amount of memory required to process images/photos/video data that's practically negligible.

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

My suggestion is, quit wasting time prematurely optimizing based on variable types and look for a good data structure that'll make it easy to process all that data. Regardless of that you do, unless you define 10K primitive variables individually, it's going to end up on the heap anyway.

我的建议是,不要浪费时间过早地根据变量类型进行优化,并寻找一个好的数据结构,这样可以很容易地处理所有数据。无论你做什么,除非你单独定义10K原始变量,否则它最终会在堆上结束。

#9


0  

What's wrong with java.lang.Integer? It's a reasonable solution, unless you're storing very large amounts of this value maybe.

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

If you wanted to use primitives, a -1 value would be a good solution as well. The only other option you have is using a separate boolean flag, like someone already suggested. Choose your poison :)

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

PS: damn you, I was trying to get away with a little white lie on the objects vs structs. My point was that it uses more memory, similar to the boolean flag method, although syntactically the nullable type is is nicer of course. Also, I wasn't sure someone with a Java background would know what I meant with a struct.

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

#10


0  

java.lang.Integer is reasonable for this case. And it already implemented Serializable, so you can save just only the year field down to the HDD and load it back.

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

#11


0  

Another option might be to use a special value internally (-1 or Integer.MIN_VALUE or similar), but expose the integer as two methods:

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

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

getValue() {
    if (internalValue == -1) {
        throw new IllegalStateException(
            "Check hasValue() before calling getValue().");
    }
    return internalValue;
}

#12


0  

If you're going to save memory, I would suggest packing several years in a single int. Thus 0 is nil. Then you can make assumptions in order to optimize. If you are working only with the current dates, like years 1970—2014, you can subtract 1969 from all of them and get into 1—55 range. Such values can be coded with only 6 bits. So you can divide your int which is always 32 bit, into 4 zones, with a year in there. This way you can pack 4 years in the range 1970—2226 into a single int. The more narrow your range is, like only 2000—2014 (4 bits), the more years you can pack in a single int.

如果你要节省内存,我建议在一个int中打包几年。因此0是零。然后你可以做出假设以便优化。如果您只使用当前日期,例如1970-2014年,您可以从所有这些日期中减去1969并进入1-55范围。这些值只能用6位编码。因此,您可以将总是32位的int分成4个区域,其中有一年。通过这种方式,您可以将1970-2226范围内的4年打包成一个整数。你的范围越窄,比如2000-2014(4位),你可以在一个int中打包的年数越多。

#13


0  

You could use the @Nullable annotation if using java 7

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