我不应该再次使用原始类型吗?

时间:2008-09-23 21:53:01

标签: java types

在Java中混合使用原始数据类型及其各自的包装类可能会导致很多错误。以下示例说明了此问题:

int i = 4;
...
if (i == 10)
  doStuff();

稍后您想要将变量 i 定义或未定义,因此您将上述实例化更改为:

Integer i = null;

现在等式检查失败。

始终使用原始包装类是不是很好的Java实践?显然它会早点出现一些错误,但这有什么缺点?它是否会影响性能或应用程序的内存占用?有没有偷偷摸摸的陷阱?

8 个答案:

答案 0 :(得分:18)

使用盒装类型 会产生性能和内存问题。

在进行比较时(例如(i == 10)),java必须在进行比较之前取消打包该类型。即使使用i.equals(TEN)也会使用方法调用,这种方法调用比==语法更昂贵,而且(IMO)更加丑陋。

重新启动内存,对象必须存储在堆上(这也会影响性能)以及存储值本身。

鬼鬼祟祟的骗局?我是i.equals(j)null

我总是使用原语,除非它可能 null,但在这些情况下,在比较之前总是检查null

答案 1 :(得分:8)

首先,从使用原语切换到使用对象只是为了将其设置为null可能是一个糟糕的设计决策。我经常与我的同事讨论null是否是一个哨兵价值,我的意见通常是它不是(因此不应该像哨兵价值那样被禁止),但在这种特殊情况下你会去用它作为哨兵价值。请不要。创建一个布尔值,指示您的整数是否有效,或者创建一个将布尔值和整数包装在一起的新类型。

通常,当使用较新版本的Java时,我发现我不需要显式创建或转换为基元的对象版本,因为自动装箱支持在1.5中添加了一些时间(可能是1.5本身)。

答案 2 :(得分:3)

我建议一直使用原语,除非你真的有“null”的概念。

是的,虚拟机会自动进行自动装箱以及所有这一切,但它可能会导致一些非常奇怪的情况,你会在你真正不想要的代码行中得到一个空指针异常,你必须开始对每个数学运算进行空检查。如果您开始混合类型并获得奇怪的自动装箱行为,您也可以开始获得一些非显而易见的行为。

对于float / double,你可以将NaN视为null,但请记住NaN!= NaN,所以你仍然需要特殊的检查,比如!Float.isNaN(x)。

如果有支持原始类型的集合而不必浪费拳击的时间/开销,那将是非常好的。

答案 3 :(得分:1)

在您的示例中,if语句将一直运行直到超过127(因为Integer自动装箱会将值缓存到127并为每个数字返回相同的实例,直到达到此值)

所以它比你呈现它更糟糕......

if( i == 10 )

将像以前一样工作,但

if( i == 128 )

会失败。出于这样的原因,我总是在需要时明确地创建对象,并且如果可能的话,往往会坚持原始变量

答案 4 :(得分:0)

你的Java POD类型是有原因的。除了开销之外,您无法对对象进行正常操作。整数是一个对象,需要进行分配和垃圾回收。 int不是。

答案 5 :(得分:0)

如果该值可以为空,您可能会发现在您的设计中您需要其他东西。

有两种可能性 - 要么值只是数据(如果填写或不填写代码将不会有任何不同的行为),或者它实际上表明你在这里有两种不同类型的对象(代码行为不同)如果有一个值而不是null)

如果它只是用于显示/存储的数据,您可以考虑使用真正的DTO - 根本不具备它作为头等成员的DTO。这些通常会有一种方法来检查是否已设置值。

如果在某些时候检查null,则可能需要使用子类,因为当存在一个差异时,通常会有更多。至少你想要一个更好的方式来表明你的差异,而不是“如果primitiveIntValue == null”,这并不意味着什么。

答案 6 :(得分:0)

请勿切换到非原语才能获得此功能。使用布尔值指示值是否已设置。如果您不喜欢该解决方案并且您知道您的整数将处于某个合理的限制(或者不关心偶尔的失败),请使用特定值来指示“未初始化”,例如Integer.MIN_VALUE。但这是一个比布尔值安全得多的解决方案。

答案 7 :(得分:0)

当你进入'后期'点时,在重构过程中需要完成更多的工作。尽可能使用原语。 (资本期)如果需要更多功能,则制作POJO。在我看来,原始的包装类最适合需要通过网络传输的数据,这意味着网络应用程序。允许空值作为可接受的值会导致系统“增长”时出现问题。要浪费或错过很多代码,保护应该进行简单比较的内容。