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,要实现这一目的,你可能会编写如下这段代码:
Map<String, Integer> carInventory = new HashMap<>();Integer count = 0;if(map.containsKey("Aston Martin")){count = map.get("Aston Martin");}
使用新的Map接口之后,你只需要简单地编写一行代码就能实现这一功能,代码如下:
Integer count = map.getOrDefault("Aston Martin", 0);
注意,这一方法仅在没有映射时才生效。比如,如果键被显式地映射到了空值,那么该方法是不会返回你设定的默认值的。
另一个特别有用的方法是computeIfAbsent,这个方法在第19章解释记忆表时曾经简要地提到过。它能帮助你非常方便地使用缓存模式。比如,假设你需要从不同的网站抓取和处理数据。这种场景下,如果能够缓存数据是非常有帮助的,这样你就不需要每次都执行(代价极高的)数据抓取操作了:
public String getData(String url){String data = cache.get(url);if(data == null){ ←---- 检查数据是否已经缓存data = getData(url);cache.put(url, data); ←---- 如果数据没有缓存,那就访问网站抓取数据,紧接着对Map 中的数据进行缓存,以备将来使用之需}return data;}
这段代码,你现在可以通过computeIfAbsent用更加精炼的方式实现,代码如下所示:
public String getData(String url){return cache.computeIfAbsent(url, this::getData);}
上面介绍的这些方法,其更详细的内容都能在Java API的官方文档中找到。注意,ConcurrentHashMap也进行了更新,提供了新的方法。B.2节会讨论。
- 集合
removeIf方法可以移除集合中满足某个谓词的所有元素。注意,这一方法与在介绍Stream API时提到的filter方法不大一样。Stream API中的filter方法会产生一个新的流,不会对当前作为数据源的流做任何变更。
- 列表
replaceAll方法会对列表中的每一个元素执行特定的操作,并用处理的结果替换该元素。它的功能和Stream中的map方法非常相似,不过replaceAll会修改列表中的元素。与此相反,map方法会生成新的元素。
比如,下面这段代码会打印输出[2,4,6,8,10],因为列表中的元素被原地修改了:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);numbers.replaceAll(x -> x * 2);System.out.println(numbers); ←---- 打印输出[2,4,6,8,10]
B.1.2 Collections类
Collections类已经存在了很长的时间,它的主要功能是操作或者返回集合。Java 8中它又新增了一个方法,该方法可以返回不可修改的、同步的、受检查的或者是空的NavigableMap或NavigableSet。除此之外,它还引入了checkedQueue方法,该方法返回一个队列视图,可以扩展进行动态类型检查。
B.1.3 Comparator
Comparator接口现在同时包含了默认方法和静态方法。你可以使用第3章中介绍的静态方法Comparator.comparing返回一个Comparator对象,该对象提供了一个可以提取排序关键字的函数。
新的实例方法如下。
reversed——对当前的Comparator对象进行逆序排序,并返回排序之后新的Comparator对象。thenComparing——当两个对象相同时,返回使用另一个Comparator进行比较的Comparator对象。thenComparingInt、thenComparingDouble、thenComparingLong——这些方法的工作方式和thenComparing方法类似,不过它们的处理函数是特别针对某些基本数据类型(分别对应ToIntFunction、ToDoubleFunction和ToLongFunction)的。
新的静态方法如下。
comparingInt、comparingDouble、comparingLong——它们的工作方式和comparing类似,但接受的函数特别针对某些基本数据类型(分别对应于ToIntFunction、ToDoubleFunction和ToLongFunction)。naturalOrder——对Comparable对象进行自然排序,返回一个Comparator对象。nullsFirst、nullsLast——对空对象和非空对象进行比较,你可以指定空对象(null)比非空对象(non-null)小或者比非空对象大,返回值是一个Comparator对象。reverseOrder——和naturalOrder().reversed()方法类似。
