方法调用了低效的new Integer(int)构造函数,应该使用Integer.valueOf(int)函数替代。

5

我的目标是优化我的应用程序代码。我的代码如下所示:

int a = 10;
Map<String , Integer> myMap = new TreeMap<>();

myMap.put("first" , new Integer(a)); //[FindBugs] Method com.abc.xyz.Test.main(String[]) invokes inefficient new Integer(int) constructor; use Integer.valueOf(int) instead 

当我在Netbeans中使用Findbugs进行静态分析时,它显示了一个警告/缺陷,如“Method invokes inefficient new Integer(int) constructor; use Integer.valueOf(int) instead”。
我知道new Integer(int)Integer.valueOf(int)之间的区别。
其中一个会创建一个额外的对象,而另一个则不会。另外一个不进行缓存,而另一个则进行缓存。
因此,我已经修改了我的代码,像这样...
m.put("first" , Integer.valueOf(a)); // Unnecessary boxing to Integer

但由于编辑器(而不是FindBugs)的警告“将Integer装箱没有必要”,我又进行了修改。
因此,我将其再次更改为以下形式...
m.put("first" , a); //No warning at all...

最终不会给出任何警告

我的问题:

1.)这个链接表明在编译器内部,m.put("first", a);被转换为m.put("first", Integer.valueOf(a));。(在该示例中使用了List-ArrayList,在此处我们使用Map-TreeMap...请注意)。那么为什么编辑器会发出警告?我应该怎么做?哪种方式是最优的?

2.)如果不是使用Map而是使用类似于HashTable的数据结构呢?

3.)为什么编辑器会提示Unnecessary boxing to Integer(不必要的将基本类型包装成Integer)?

4.)为什么m.put("first", a)有效?因为我传递了基本变量,而map的put()只接受对象。所以这是因为自动装箱吗?


1
是的,这是由于自动装箱引起的。 - user1935024
好的,谢谢...那么优化的好方法是什么?最后一个吗? - Manan Shah
我认为你无法进行优化,自动装箱会为您完成相同的工作,因此您不需要明确地执行valueOf(a) - user1935024
2个回答

4

1.) 这个链接表明编译器内部将m.put("first" , a)转换为m.put("first" , Integer.valueOf(a))。

(在那个例子中,有一个List-ArrayList,这里有一个Map-TreeMap...FYI)。那么为什么编辑器会给出警告呢?我该怎么做?什么是最优化的方式?

是的,编译器知道m.put("first", a)只接受对象,因此应用了自动装箱。在性能方面,使用自动装箱或写Integer.valueOf(a)没有任何区别。

另一方面,new Integer(a)与Integer.valueOf(a)并没有真正的速度差异。区别在于对于小的绝对值(默认为-128到127),Integer.valueOf(a)将使用缓存,即不会一直创建新对象。对于所有其他值,它都会调用new Integer(a)。

例如:

Integer.valueOf(1) == Integer.valueOf(1) 将返回true
Integer.valueOf(1000) == Integer.valueOf(1000) 将返回false
new Integer(1) == new Integer(1) 将返回false,因为这里不使用缓存

2.) 如果不是Map,而是类似HashTable这样的数据结构,那么呢?

为什么要问那个?有HashTable,但由于它是同步的,这意味着比HashMap更多的开销,因此除非需要同步,否则坚持使用HashMap或TreeMap(如果需要排序)。

3.) 为什么编辑器会提示Integer不必要的装箱?

可能只是因为可读性(a比Integer.valueOf(a)短)。

4.) 为什么m.put("first" , a)有效?因为我传递了原始变量,而map的put()只接受Object。所以是因为自动装箱吗?

见1


谢谢Thomas...你解决了我的疑惑。我也是这么想的,但不确定它们是否相同...是的,在阅读过程中,我了解到了-128到127的缓存范围...对于等式的加1点赞... - Manan Shah
所以我们不能盲目地进行优化。如果出现某些引用比较或equals()的情况,更改为Integer.valueOf(int)可能会导致问题,对吧? - Manan Shah
1
@MananShah 是的,盲目优化几乎从来不是一个好主意。:) equals() 应该不会有问题,因为它应该总是产生相同的结果,但对象相等性(即 == )可能会有问题。通常只有在确实需要时才应小心使用 ==。 - Thomas

1

4.) 为什么 m.put("first", a) 起作用?因为我传递了原始变量,而 map 的 put() 只接受 Object。

自动装箱。int 会自动转换为 Integer,反之亦然(在这种情况下可能会出现 NullPointerException)。

3.) 为什么编辑器给 Integer 进行不必要的装箱。

因为你不需要编写这段代码。编译器会为你完成它。

通常更易读。

2.) 如果不是 Map,而是类似 HashTable 的任何数据结构,情况是否相同?

是的,在 JDK 集合中只能使用对象。这意味着基本类型必须被装箱。它具有较小的运行时成本和巨大的内存开销。一个 Integer 占用的内存比 int 多约 300%。

你无法避免它。避免装箱开销的唯一方法是使用专门的集合,如 GNU trove,它为每种原始类型提供一个类。只有在计划将数百万个原始元素存储到集合中时才有用。

最后,永远不要编写 new Integer(x)。Integer.valueOf(x) 执行相同的操作,但它维护一个内部缓存,以避免为某些常用值创建新实例。


感谢您关注NullPointerException和代码可读性。我不知道GNU Trove是什么...我肯定会去了解它...而且我也不知道Integer = int的300%在内存方面的含义.... :) 很好,再次感谢。 - Manan Shah
因为问题1,我已经接受了Thomas的答案...很抱歉,我们只能接受一个答案。 - Manan Shah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接