Преобразование потребителей в функции
Много лямбд для 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, которые я пропустил, что делает мой метод избыточным?
2 ответа
Есть много потенциально полезных методов, которые могут быть добавлены к Function
, Consumer
а также Supplier
интерфейсы. Вы даете хороший пример (преобразование Consumer
к Function
) но есть много других потенциальных преобразований или утилит, которые можно добавить. Например, используя Function
как Consumer
(игнорируя возвращаемое значение) или как Supplier
(путем предоставления входного значения). Или преобразовать BiFunction
к Function
предоставляя любое значение. Все это, конечно, может быть сделано вручную в коде или предоставлено с помощью служебных функций, как вы показали, но было бы полезно иметь стандартизированные механизмы в API, как это существует во многих других языках.
Это спекуляция с моей стороны, но я думаю, это отражает желание разработчиков языка оставить API как можно более чистым. Однако я заинтригован контрастом (в качестве примера) с очень богатым набором Comparator
Утилиты, предоставляемые языком для изменения порядка, сравнения по нескольким критериям, работы с нулевыми значениями и т. д. Они также легко могут быть оставлены пользователю, но предоставлены API. Мне было бы интересно услышать от одного из разработчиков языка, почему подходы к этим интерфейсам кажутся такими противоречивыми.
Я думаю, что Apache commons collection 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
,