Java 8 множественное сопоставление

возможно ли выполнить несколько сопоставлений в коллекции? Следующая ошибка компиляции кода:

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

Я хотел бы общее решение.

2 ответов


если у вас есть несколько функций (например, если вы можете записать их), то я предлагаю вам не добавить их в список. Вместо этого составьте их в одну функцию, а затем примените эту функцию к каждому элементу данной коллекции.

код 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);

таким образом мы превратили наш список кандидатов в список баллов, явно составляя новую функцию из четырех различных функций и применяя эту составленную функцию к каждому кандидату.

если вы хотите знать, кто выиграет выборы, вы можете проверить, какой кандидат имеет самый высокий балл, но я позволю это в качестве упражнения для тех, кто заинтересован в политике ;)


проблема возникает из-за того, что вы используете общий подстановочный знак ?. Вы хотите иметь параметризованный тип 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 correcly принимает T и возвращает 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());
}