首页 > 解决方案 > 标准化跨不同对象的 lambda 操作

问题描述

在下面的代码中,您可以看到针对具有不同对象的多个映射发生的常见 lambda 操作。我想知道我是否可以在调用时定义一个执行相同操作的通用函数。

Map<Int, Object1> map1.entrySet()
                      .stream()
                      .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getDisplayName()))

Map<Int, Object2> map2.entrySet()
                      .stream()
                      .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getDisplayName()))

Map<Int, Object3> map2.entrySet()
                      .stream()
                      .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getDisplayName()))

在上面,object1、object2 和 object3 是不同的类型(类)。

假设所有对象 obj1、obj2、obj3 都具有共同的属性 displayName。

标签: functionlambdafunctional-programming

解决方案


没有反射你能做的最好的事情是传递一个 lambda 来获取属性:

public <K, T1, T2> Map<K, T2> mapValues(Map<K, T1> source, Function<T1, T2> function) {
    return source.entrySet()
                 .stream()
                 .collect(Collectors.toMap(Map.Entry::getKey, e -> function.apply(e.getValue())));
}

// use
mapValues(map1, Object1::getDisplayName)
mapValues(map2, Object2::getDisplayName)

(Kotlin 在标准库中有这个方法的等价物)

通过反射,你可以做到

public <K, T> Map<K, String> mapDisplayName(Map<K, T> source, Class<T> clazz) {
    Method m = clazz.getMethod("getDisplayName");
    return source.entrySet()
                 .stream()
                 .collect(Collectors.toMap(Map.Entry::getKey, e -> (String) m.invoke(e.getValue())));
}

// use
mapValues(map1, Object1.class)
mapValues(map2, Object2.class)

但它不太安全,也不太有用,以换取……不是那么方便。


推荐阅读