Java 8个多重映射

Java 8 multiple mapping

是否可以对集合进行多重映射? 以下代码编译错误:

... in Stream cannot be applied to java.util.function.Function<capture<?>,capture<?>>

private static List<?> multipleMapping(final Collection<?> collection, final List<Function<?, ?>> functions) {
    Stream<?> stream = collection.stream();
    for (Function<?, ?> function : functions) {
        stream = stream.map(function);
    }
    return stream.collect(Collectors.toList());
}

我想要通用解决方案。

问题出在您使用的是通用通配符 ?。您想要的是有一个参数化类型 T,它将表示 Stream 元素的类型。假设该函数 return 与输入的类型相同,您可以:

private static <T> List<T> multipleMapping(final Collection<T> collection, final List<Function<T, T>> functions) {
    Stream<T> stream = collection.stream();
    for (Function<T, T> function : functions) {
        stream = stream.map(function);
    }
    return stream.collect(Collectors.toList());
}

这编译得很好:给 map 的映射器正确地接受 T 和 returns T。但是,如果函数 return 的类型与其输入不同,那么您将无法保持类型安全,将不得不求助于使用 List<Function<Object, Object>>.


请注意,我们可以使用 UnaryOperator<T> 而不是 Function<T, T>

此外,您可以避免 for 循环并使用 andThen:

将所有函数简化为一个函数
private static <T> List<T> multipleMapping(final Collection<T> collection, final List<Function<T, T>> functions) {
    return collection.stream()
                     .map(functions.stream().reduce(Function.identity(), Function::andThen))
                     .collect(Collectors.toList());
}

如果你的功能很少(即如果你能把它们写下来),那么我建议你不要将它们添加到列表中。相反,将它们组合成一个函数,然后将该函数应用于给定集合的每个元素。

您的 multipleMapping() 方法现在将接收一个函数:

public static <T, R> List<R> multipleMapping(
    Collection<T> collection, Function<T, R> function) {

    return collection.stream()
            .map(function)
            .collect(Collectors.toList());
}

然后,在调用代码中,您可以创建一个由许多函数组成的函数(无论如何您将拥有所有函数)并使用该函数调用 multipleMapping() 方法。

例如,假设我们有一个候选人列表:

List<String> candidates = Arrays.asList(
        "Hillary", "Donald",
        "Bernie", "Ted", "John");

还有四个函数:

Function<String, Integer> f1 = String::length;

Function<Integer, Long> f2 = i -> i * 10_000L;

Function<Long, LocalDate> f3 = LocalDate::ofEpochDay;

Function<LocalDate, Integer> f4 = LocalDate::getYear;

这些函数可以用来组合一个新的函数,如下:

Function<String, Integer> function = f1.andThen(f2).andThen(f3).andThen(f4);

或者这样:

Function<String, Integer> composed = f4.compose(f3).compose(f2).compose(f1);

现在,您可以使用候选人列表和组合 function:

调用您的 multipleMapping() 方法
List<Integer> scores = multipleMapping(candidates, function);

因此,我们通过从四个不同的函数显式组合一个新函数并将这个组合函数应用于每个候选函数,将候选列表转换为分数列表。

If you want to know who will win the election, you could check which candidate has the highest score, but I will let that as an exercise for whoever is interested in politics ;)