Преобразование пользователей в функции
Многие lambdas для интерфейса Function
принимают форму
t -> {
// do something to t
return t;
}
Я делаю это так часто, что написал для него такой метод.
static <T> Function<T, T> consumeThenReturn(Consumer<T> consumer) {
return t -> {
consumer.accept(t);
return t;
};
}
Это позволяет мне делать действительно приятные вещи, такие как:
IntStream.rangeClosed('A', 'Z')
.mapToObj(a -> (char) a)
.collect(Collectors.collectingAndThen(Collectors.toList(), consumeThenReturn(Collections::shuffle)))
.forEach(System.out::print);
Есть ли другой способ сделать такие преобразования, не полагаясь на мой собственный метод? Есть ли что-нибудь в новых API, которые я пропустил, что делает мой метод избыточным?
Ответы
Ответ 1
Существует много потенциально полезных методов, которые могут быть добавлены в интерфейсы Function
, Consumer
и Supplier
. Вы даете хороший пример (преобразование Consumer
в Function
), но есть много других возможных конверсий или утилит, которые можно было бы добавить. Например, используя Function
как Consumer
(игнорируя возвращаемое значение) или как Supplier
(путем предоставления входного значения). Или преобразование a BiFunction
в Function
путем подачи значения. Разумеется, все это можно сделать вручную в коде или предоставить через полезные функции, как вы показали, но, возможно, было бы полезно иметь стандартизированные механизмы в API, как это существует на многих других языках.
Это спекуляция с моей стороны, но я предполагаю, что это отражает желание дизайнеров языка оставить API как можно более чистым. Однако я заинтригован контрастом (как пример) очень богатым набором Comparator
утилит, предоставляемых языком для отмены заказов, сравнения по нескольким критериям, обработки нулевых значений и т.д. Этим также может быть легко оставлено пользователь, но был предоставлен API. Мне было бы интересно услышать от одного из разработчиков языка, почему подходы к этим интерфейсам кажутся настолько непоследовательными.
Ответ 2
Коллекции коллекционеров Apache 4.x имеет то, что вы ищете, я думаю. Его эквиваленты для Function
и Consumer
равны соответственно Transformer
и Closure
, и он обеспечивает способ их компоновки с использованием ClosureTransformer
Тривиально преобразовать между эквивалентными функциональными типами, вызывая SAM одного и присваивая его другому. Объединяя все это, вы можете получить Java 8 Function
следующим образом:
Consumer<String> c = System.out::println;
Function<String,String> f = ClosureTransformer.closureTransformer(c::accept)::transform;
c::accept
преобразует Java 8 Consumer
в эквивалентный Apache Commons 4 Closure
, а окончательный ::transform
преобразует Apache Commons 4 Transformer
в эквивалентный Java 8 Function
.