9

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

... 在 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());
}

我想通用解决方案。

4

2 回答 2

9

问题来自您使用的是通用通配符这一事实?。您想要的是有一个参数化类型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());
}

这编译得很好:给定的映射器正确地map接受 aT并返回 a T。但是,如果函数返回的类型与其输入不同,那么您将无法保持类型安全,并且必须求助于 using List<Function<Object, Object>>


请注意,我们可以使用 aUnaryOperator<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());
}
于 2016-03-18T23:03:19.063 回答
4

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

您的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);

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

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 ;)

于 2016-03-19T01:25:13.173 回答