B.1 集合

Collection API在Java 8中最重大的更新就是引入了流,我们已经在第4~6章进行了介绍。当然,除此之外,第9章还讨论了Collection API的其他更新,本附录会再做一些补充。

B.1.1 其他新增的方法

Java API的设计者们充分利用默认方法,为集合接口和类新增了多个新的方法。这些新增的方法已经列在表B-1中了。

表 B-1 集合类和接口中新增的方法

类/接口 新方法
Map getOrDefault, forEach, compute, computeIfAbsent, computeIfPresent, merge, putIfAbsent, remove(key, value), replace, replaceAll, of, ofEntries
Iterable forEach, spliterator
Iterator forEachRemaining
Collection removeIf, stream, parallelStream
List replaceAll, sort, of
BitSet Stream
Set of
  • Map

Map接口的变化最大,它增加了多个新方法。比如,getOrDefault方法就可以替换现在检测Map中是否包含给定键映射的惯用方法。如果Map中不存在这样的键映射,你可以提供一个默认值,方法会返回该默认值。使用之前版本的Java,要实现这一目的,你可能会编写如下这段代码:

  1. Map<String, Integer> carInventory = new HashMap<>();
  2. Integer count = 0;
  3. if(map.containsKey("Aston Martin")){
  4. count = map.get("Aston Martin");
  5. }

使用新的Map接口之后,你只需要简单地编写一行代码就能实现这一功能,代码如下:

  1. Integer count = map.getOrDefault("Aston Martin", 0);

注意,这一方法仅在没有映射时才生效。比如,如果键被显式地映射到了空值,那么该方法是不会返回你设定的默认值的。

另一个特别有用的方法是computeIfAbsent,这个方法在第19章解释记忆表时曾经简要地提到过。它能帮助你非常方便地使用缓存模式。比如,假设你需要从不同的网站抓取和处理数据。这种场景下,如果能够缓存数据是非常有帮助的,这样你就不需要每次都执行(代价极高的)数据抓取操作了:

  1. public String getData(String url){
  2. String data = cache.get(url);
  3. if(data == null){ ←---- 检查数据是否已经缓存
  4. data = getData(url);
  5. cache.put(url, data); ←---- 如果数据没有缓存,那就访问网站抓取数据,紧接着对Map 中的数据进行缓存,以备将来使用之需
  6. }
  7. return data;
  8. }

这段代码,你现在可以通过computeIfAbsent用更加精炼的方式实现,代码如下所示:

  1. public String getData(String url){
  2. return cache.computeIfAbsent(url, this::getData);
  3. }

上面介绍的这些方法,其更详细的内容都能在Java API的官方文档中找到。注意,ConcurrentHashMap也进行了更新,提供了新的方法。B.2节会讨论。

  • 集合

removeIf方法可以移除集合中满足某个谓词的所有元素。注意,这一方法与在介绍Stream API时提到的filter方法不大一样。Stream API中的filter方法会产生一个新的流,不会对当前作为数据源的流做任何变更。

  • 列表

replaceAll方法会对列表中的每一个元素执行特定的操作,并用处理的结果替换该元素。它的功能和Stream中的map方法非常相似,不过replaceAll会修改列表中的元素。与此相反,map方法会生成新的元素。

比如,下面这段代码会打印输出[2,4,6,8,10],因为列表中的元素被原地修改了:

  1. List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
  2. numbers.replaceAll(x -> x * 2);
  3. System.out.println(numbers); ←---- 打印输出[246810]

B.1.2 Collections

Collections类已经存在了很长的时间,它的主要功能是操作或者返回集合。Java 8中它又新增了一个方法,该方法可以返回不可修改的、同步的、受检查的或者是空的NavigableMapNavigableSet。除此之外,它还引入了checkedQueue方法,该方法返回一个队列视图,可以扩展进行动态类型检查。

B.1.3 Comparator

Comparator接口现在同时包含了默认方法和静态方法。你可以使用第3章中介绍的静态方法Comparator.comparing返回一个Comparator对象,该对象提供了一个可以提取排序关键字的函数。

新的实例方法如下。

  • reversed——对当前的Comparator对象进行逆序排序,并返回排序之后新的Comparator对象。
  • thenComparing——当两个对象相同时,返回使用另一个Comparator进行比较的Comparator对象。
  • thenComparingIntthenComparingDoublethenComparingLong——这些方法的工作方式和thenComparing方法类似,不过它们的处理函数是特别针对某些基本数据类型(分别对应ToIntFunctionToDoubleFunctionToLongFunction)的。

新的静态方法如下。

  • comparingIntcomparingDoublecomparingLong——它们的工作方式和comparing类似,但接受的函数特别针对某些基本数据类型(分别对应于ToIntFunctionToDoubleFunctionToLongFunction)。
  • naturalOrder——对Comparable对象进行自然排序,返回一个Comparator对象。
  • nullsFirstnullsLast——对空对象和非空对象进行比较,你可以指定空对象(null)比非空对象(non-null)小或者比非空对象大,返回值是一个Comparator对象。
  • reverseOrder——和naturalOrder().reversed()方法类似。