Преобразование потребителей в функции

Много лямбд для 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,

Другие вопросы по тегам