我想找到一种简单的方法来用Java 8流式传输Map 。猜猜是什么? 没有!
为了方便起见,我期望的是以下方法:
public interface Map<K, V> {default Stream<Entry<K, V>> stream() {return entrySet().stream();}
}
但是没有这种方法。 不应使用这种方法的原因可能多种多样,例如:
- 没有选择
keySet()
或values()
作为流源的entrySet()
“明确”首选项 -
Map
并不是真正的收藏。 它甚至都不是可Iterable
- 那不是设计目标
- EG没有足够的时间
好吧,对于Map
进行改型以提供entrySet().stream()
并最终实现Iterable<Entry<K, V>>
,这是一个非常令人信服的理由。 那就是我们现在有了Map.forEach()
的事实:
default void forEach(BiConsumer<? super K, ? super V> action) {Objects.requireNonNull(action);for (Map.Entry<K, V> entry : entrySet()) {K k;V v;try {k = entry.getKey();v = entry.getValue();} catch(IllegalStateException ise) {// this usually means the entry is no longer in the map.throw new ConcurrentModificationException(ise);}action.accept(k, v);}
}
在这种情况下, forEach()
接受BiConsumer
,该BiConsumer
实际上消耗了映射中的条目。 如果您搜索JDK源代码,则Map.forEach()
之外的BiConsumer
类型的引用实际上很少,也许还有几个CompletableFuture
方法和几个流收集方法。
因此,几乎可以假定BiConsumer
受到此forEach()
方法的强烈驱动,这对于使Map.Entry
在整个collection API中成为更重要的类型是一个很好的情况(我们更倾向于使用Tuple2类型,课程)。
让我们继续这种思路。 还有Iterable.forEach()
:
public interface Iterable<T> {default void forEach(Consumer<? super T> action) {Objects.requireNonNull(action);for (T t : this) {action.accept(t);}}
}
尽管有细微的差别,但Map.forEach()
和Iterable.forEach()
直观地迭代了各自收集模型的“条目”。
-
Iterable.forEach()
期望Consumer
获得单个值 -
Map.forEach()
期望BiConsumer
两个值:键和值( 不是Map.Entry
!)
这样考虑:
这使得这两种方法在“鸭子键入意义上”不兼容,这使得这两种类型更加不同
mm!
用jOOλ改善地图
我们发现这很古怪且违反直觉。 实际上, forEach()
并不是Map
遍历和转换的唯一用例。 我们希望有一个Stream<Entry<K, V>>
甚至更好的是Stream<Tuple2<T1, T2>>
。 因此,我们在jOOλ中实现了该功能 ,这是我们为jOOQ的集成测试开发的库。 使用jOOλ,您现在可以将Map
封装为Seq
类型(“ Seq”表示顺序流,即具有更多功能特征的流):
Map<Integer, String> map = new LinkedHashMap<>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");assertEquals(Arrays.asList(tuple(1, "a"), tuple(2, "b"), tuple(3, "c")),Seq.seq(map).toList()
);
你能用它做什么? 如何创建一个新的Map
,一次性交换键和值:
System.out.println(Seq.seq(map).map(Tuple2::swap).toMap(Tuple2::v1, Tuple2::v2)
);System.out.println(Seq.seq(map).toMap(Tuple2::v2, Tuple2::v1)
);
以上两种都会产生:
{a=1, b=2, c=3}
仅作记录,以下是使用标准JDK API交换键和值的方法:
System.out.println(map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey))
);
可以做到,但是每天标准Java API的冗长性使事情变得很难读/写。
翻译自: https://www.javacodegeeks.com/2014/10/lets-stream-a-map-in-java-8-with-jooλ.html