将消费者转换为函数

2022-09-02 13:58:00

接口的许多 lambda 采用以下形式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

有许多可能有用的方法可以添加到 和 接口中。您给出了一个很好的例子(将a转换为a),但是可以添加许多其他潜在的转换或实用程序。例如,使用 as(通过忽略返回值)或用作 as(通过提供输入值)。或者通过提供任一值将 a 转换为 a。当然,所有这些都可以在代码中手动完成,也可以像您所展示的那样通过实用程序函数提供,但是在API中具有标准化机制可以说是有价值的,就像在许多其他语言中一样。FunctionConsumerSupplierConsumerFunctionFunctionConsumerSupplierBiFunctionFunction

这是我的推测,但我想这反映了语言设计人员希望尽可能保持API干净的愿望。然而,我对这种对比(作为一个例子)与语言提供的非常丰富的实用程序集的对比很感兴趣,这些实用程序可以反转顺序,通过几个标准进行比较,处理空值等。这些也很容易留给用户,但已经由API提供。我很想听听其中一位语言设计师为什么这些接口的方法似乎如此不一致。Comparator


答案 2

我认为Apache commons collections 4.x有你想要的东西。它的等价物分别是 和 和 ,它提供了一种使用FunctionConsumerTransformerClosureClosureTransformer

通过调用一个函数类型的 SAM 并将其分配给另一个函数类型,在等效函数类型之间进行转换是微不足道的。把它们放在一起,你可以以这种方式得到Java 8:Function

Consumer<String> c = System.out::println;
Function<String,String> f = ClosureTransformer.closureTransformer(c::accept)::transform;

c::accept将Java 8转换为等效的Apache Commons 4,最终将Apache Commons 4转换为等效的Java 8。ConsumerClosure::transformTransformerFunction


推荐