繁体   English   中英

使用Java流将列表转换为映射

[英]Transform list to mapping using java streams

我在整个代码中都重复了以下模式:

class X<T, V>
{
    V doTransform(T t) {
        return null; // dummy implementation
    }

    Map<T, V> transform(List<T> item) {
        return item.stream().map(x->new AbstractMap.SimpleEntry<>(x, doTransform(x))).collect(toMap(x->x.getKey(), x->x.getValue()));
    }
}

要求使用AbstractMap.SimpleEntry既麻烦又笨拙。 Linqs使用匿名类型更为优雅。

是否有使用流实现此目的的更简单方法?

提前谢谢。

您可以在值映射器中调用doTransform

Map<T, V> transform(List<T> item) {
    return item.stream().collect(toMap(x -> x, x -> doTransform(x)));
}

不幸的是,Java没有C#的匿名类型的完全等效。

在这种情况下,您不需要@Jorn Vernee建议的中间map操作。 相反,您可以在toMap收集器中执行键和值提取。

但是,在涉及到您认为需要C#匿名类型之类的情况时,您可以考虑:

  1. 匿名对象 (取决于用例,可能不一定总是您想要的)
  2. Arrays.asList(...)List.of(...) (根据用例可能并不总是您想要的)
  3. 数组(取决于用例,不一定总是您想要的)

最终,如果您确实需要映射到可以包含两种不同类型元素的对象,那么我将坚持使用AbstractMap.SimpleEntry

也就是说,您当前的示例可以简化为:

Map<T, V> transform(List<T> items) {
    return items.stream().collect(toMap(Function.identity(),this::doTransform));
}

在此特定示例中,根本不需要进行中间存储:

Map<T, V> transform(List<T> item) {
    return item.stream().collect(toMap(x -> x, x -> doTransform(x)));
}

但是如果需要,Java 9提供了一种更简单的工厂方法,

Map<T, V> transform(List<T> item) {
    return item.stream()
               .map(x -> Map.entry(x, doTransform(x)))
               .collect(toMap(x -> x.getKey(), x -> x.getValue()));
}

只要您不必处理null

您可以在此处使用匿名内部类,

Map<T, V> transform(List<T> item) {
    return item.stream()
               .map(x -> new Object(){ T t = x; V v = doTransform(x); })
               .collect(toMap(x -> x.t, x -> x.v));
}

但效率较低。 这是一个内部类捕捉到周围的引用this ,也它捕捉x ,让你有两个字段, t和合成一个用于捕捉x ,同样的事情。

后者可以通过使用一种方法来规避,例如

Map<T, V> transform(List<T> item) {
    return item.stream()
               .map(x -> new Object(){ T getKey() { return x; } V v = doTransform(x); })
               .collect(toMap(x -> x.getKey(), x -> x.v));
}

但这并没有增加可读性。

唯一真正的匿名类型是为lambda表达式生成的类型,可用于通过高阶函数存储信息:

Map<T, V> transform(List<T> item) {
    return item.stream()
               .map(x -> capture(x, doTransform(x)))
               .collect(HashMap::new, (m,f) -> f.accept(m::put), HashMap::putAll);
}
public static <A,B> Consumer<BiConsumer<A,B>> capture(A a, B b) {
    return f -> f.accept(a, b);
}

但是如果您在更复杂的场景中尝试使用Java类型系统(它仍然不是一种功能编程语言),您很快就会遇到限制。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM