Java 8多重映射

Art*_*tur 9 java java-8 functional-interface

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

...在Stream中无法应用 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());
}
Run Code Online (Sandbox Code Playgroud)

我想通用的解决方案.

Tun*_*aki 8

问题来自于您使用通用通配符的事实?.你想要的是有一个参数化类型T,它将代表Stream元素的类型.假设函数将返回与其输入相同的类型,您可以:

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());
}
Run Code Online (Sandbox Code Playgroud)

编译好了:给出的mapper正确map接受a T并返回a T.但是,如果功能不返还相同种类作为它们的输入,那么你将不能够保持类型安全,将不得不求助于使用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());
}
Run Code Online (Sandbox Code Playgroud)


Fed*_*ner 4

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

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

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

    return collection.stream()
            .map(function)
            .collect(Collectors.toList());
}
Run Code Online (Sandbox Code Playgroud)

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

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

List<String> candidates = Arrays.asList(
        "Hillary", "Donald",
        "Bernie", "Ted", "John");
Run Code Online (Sandbox Code Playgroud)

还有四个功能:

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;
Run Code Online (Sandbox Code Playgroud)

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

Function<String, Integer> function = f1.andThen(f2).andThen(f3).andThen(f4);
Run Code Online (Sandbox Code Playgroud)

或者也可以这样:

Function<String, Integer> composed = f4.compose(f3).compose(f2).compose(f1);
Run Code Online (Sandbox Code Playgroud)

现在,您可以multipleMapping()使用候选列表和组合调用您的方法function

List<Integer> scores = multipleMapping(candidates, function);
Run Code Online (Sandbox Code Playgroud)

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

如果你想知道谁会赢得选举,你可以检查哪位候选人得分最高,但我会将其作为对政治感兴趣的人的练习;)