如你所见,我们首先通过 entrySet
方法取得了 map 的 entry 集合,然后在上面调用 removeIf,提供了一个Predicate
来检测 deleteKeys
的集合中是否包含这个 entry 的键值。如果检测返回的是 true,entry 就会被移除。因为 Predicate
被加上了@FunctionalInterface
注解, 因此,根据 Javadoc 的说明, 它也可以被当做是一个 lambda 表达式,一个方法引用,或者是一个构造器引用。因此,首先让我们先将这个匿名内部类转换成一个 lambda 表达式:
1 2 3 4 | public void deleteFromCache(Set<String> deleteKeys) {
dataCache.entrySet().removeIf((Map.Entry<String, Object> entry) ->
deleteKeys.contains(entry.getKey()));
}
|
在上述代码中,我们用一个 lambda 表达式替换了匿名类,它会接收一个Map.Entry
作为参数。不过 Java 8 可以自己对 lambda 表达式的参数类型进行推断,所以我们可以将明确(且有点啰嗦)的类型声明去掉了, 剩下的就是下面这样更加干净的代码:
1 2 3 | public void deleteFromCache(Set<String> deleteKeys) {
dataCache.entrySet().removeIf(entry -> deleteKeys.contains(entry.getKey()));
}
|
这段代码比原来使用 Iterator
的那段看起来好了很多。但如果是把它同使用了一个简单的for
循环来遍历键值,然后调用remove
来移除每一个元素的第二段代码做比较会如何呢?代码的行与行之间真的是没啥不同,因此假定它们在功能上是对等的,那么也许区别仅仅只是风格外表上面的。看上起比较明确的 for
循环是一种传统的命令式的风格,而removeIf
则有一种功能上更加强大的意味。如果你查看 Collection
接口中 removeIf
的实际实现,就会发现它实际就是使用的Iterator
,就跟本文的第一个示例一样。
所以实际上在功能方面是没有区别的。不过 removeIf
在理论上可以针对特定类型的集合执行并行操作来进行实现, 而也许只会对特定大小的集合才能显示其并行操作具备优势。不过这里的示例实际上更多的是关于关注点分离的,例如将决定一个元素是否应该被删除的业务逻辑中同集合的遍历逻辑分离。