你还在使用Guava的Lists.newArrayList()吗

你还在使用Guava的Lists.newArrayList()吗

经验文章nimo972025-05-11 18:41:452A+A-

Guava

说起Guava,做Java开发的应该没人不知道吧,毕竟“google出品,必属精品”。虽然应该没有Spring那样让Javaer无法避开,但是其中很多工具类的封装还是让人欲罢不能。

而我们今天要说的就是Guava中对集合类型构造方法的封装,拿Lists.newArrayList()举例。

源码

事情的起因其实是某次Code Review中同事说到的一句话,他问“你们为什么不直接用new ArrayList(),却喜欢用Lists.newArrayList()?”。多么朴实无华的问题,我当然要趁此机会推销一波,“使用Lists.newArrayList()多有逼格啊”,“内部其实就是new了个List,性能没区别的”。然后他慢悠悠地说了后半句:“源码注释写着不建议使用”。

说实话,源码我肯定是看过的,毕竟很简单,只要你点进去过,你就敢说自己看过源码。这就是我之前视角中的源码,除了方法调用栈深了一层,跟new ArrayList()有半毛钱区别吗?

public static <E> ArrayList<E> newArrayList() {
  return new ArrayList<>();
}

但其实完整地带注释的方法源码长这样,版本是28.1-jre。

/**
 * Creates a <i>mutable</i>, empty {@code ArrayList} instance (for Java 6 and earlier).
 *
 * <p><b>Note:</b> if mutability is not required, use {@link ImmutableList#of()} instead.
 *
 * <p><b>Note for Java 7 and later:</b> this method is now unnecessary and should be treated as
 * deprecated. Instead, use the {@code ArrayList} {@linkplain ArrayList#ArrayList() constructor}
 * directly, taking advantage of the new <a href="http://goo.gl/iz2Wi">"diamond" syntax</a>.
 */
@GwtCompatible(serializable = true)
public static <E> ArrayList<E> newArrayList() {
  return new ArrayList<>();
}

重点是注释的后半部分,对于Java7以及之后的版本,本方法不必要且应被弃用,建议直接使用ArrayList的构造方法,可以利用新的“菱形语法”的优势。

一开始看到菱形语法这个新名词我是懵逼的,还好注释里很贴心地贴了个链接,其实就是泛型中的<>,这玩意儿就叫菱形语法。那为啥两个看上去没啥区别的方法又和这个扯上关系了呢?

泛型实例创建时的类型推断

泛型是JDK1.5推出的一个语法糖,但其实我本人觉得还是挺有用的,可以在编译期帮助我们提前发现代码的问题。平时我们泛型见得最多的地方应该就是集合了,比如List<String>就代表这个列表只能存放String类型的变量,如果放错了,我相信你的ide就会友好地提醒你,除非你用记事本编程。

在idea中新建一个ArrayList试试,为了直观地显示idea的提示,我这边使用截图。

  • 第一行不加菱形有一个警告,提示你应该使用泛型
  • 第二行,perfect
  • 第三行,提示String多余

我这边使用的是JDK8,按照Oracle的官方说明,在JDK7其实就有这种现象了:

In Java SE 7, you can substitute the parameterized type of the constructor with an empty set of type parameters (<>):

Map<String, List<String>> myMap = new HashMap<>();

还有一句比较关键的话

Note that to take advantage of automatic type inference during generic class instantiation, you must specify the diamond.

这就是为啥第一行会报警告的原因,因为不加这个菱形就不做类型推断。

为啥不推荐用

看到这里是不是还是一脸懵逼,不知道Guava为啥不推荐使用,因为Lists.newArrayList()的内部就是new ArrayList<>(),带菱形的,完全符合JDK7及以上版本的要求。所以我只好把Oracle的解释全文看了一遍,并且找到了关键点:

List<String> list = new ArrayList<>();
list.add("A");

  // The following statement should fail since addAll expects
  // Collection<? extends String>

list.addAll(new ArrayList<>());

In comparison, the following example compiles:

// The following statements compile:

List<? extends String> list2 = new ArrayList<>();
list.addAll(list2);

是的,如果不明确在构造方法指明泛型类型,也就是单纯的一个菱形,那类型推断功能是受限的。拿上面的举例,new ArrayList<>()并不能根据上上下推断出想要构造的集合是一个List<? extends String>。所以按照官方的意思,在这种情况下用Lists.newArrayList()就搞不定了。

上面的例子是Oracle的官方说法,那到底是不是呢?idea中试一把。

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("A");

    // The following statement should fail since addAll expects
    // Collection<? extends String>

    list.addAll(new ArrayList<>());
}

跑起来完全没问题。。。当然,将allAll方法中的new ArrayList<>()替换为Lists.newArrayList()也是没问题的。

写在最后

从我个人观点来看,我觉得这应该不是idea做的优化,这么看来,官方的说法还是有待考证。

就算官方的说法是对的,那么也只是限制了某些编译期就会报错的场景,似乎问题不大,所以到底用不用Guava的集合创建方法,还是看大家的个人喜好吧。

点击这里复制本文地址 以上内容由nimo97整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

尼墨宝库 © All Rights Reserved.  蜀ICP备2024111239号-7