让我们用jOOλ在Java 8中流式传输地图

我想找到一种简单的方法来用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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值