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