如何在Java8中组合函数<T,R>和消费者<R>?
为什么我们不能像编写函数一样编写函数和消费者呢
Function<Integer, String> a = Object::toString;
Consumer<String> b = x -> System.out.println(x);
Consumer<Integer> composed = a.andThen(b);
这似乎是对现有功能界面的一种明显的即兴创作。有什么原因可以解释为什么在Java8中避免使用这种功能
此外,使用如下函数的扩展实现是否是一种常见做法
interface FunctionImproved<T, R> extends Function<T, R> {
default Consumer<T> andThen(Consumer<R> consumer) {
return x -> consumer.accept(apply(x));
}
}
# 1 楼答案
在
Function<A0, A1>
实例上的andThen
方法需要Function<A1, A2>
,而不是Consumer<A1>
:它有一个副作用,因为我们的“消费者”(实际上,它是一个
Function<A1, A1>
)将从上一个Function<Integer, String> a
函数返回一个被忽略的值。这不是我们想要的有一种不同的方式来组成
Function<A0, A1>
和Consumer<A1>
:这可以概括为一种实用方法:
有两种选择:
拥有在函数接口之间进行一些转换的静态方法(就像我做的那样)
使用默认方法扩展这些标准功能接口(就像您所做的那样)。只要选择一个正确的有意义的名字,而不是像
FunctionImproved
# 2 楼答案
这都是关于Java的类型系统。
Function.andThen
方法接受类型为Function
(不是类型为Consumer
)的参数。Java中的Consumer
和Function
之间没有关系,即一个不扩展另一个,因此不能将Consumer
传递给Function
的andThen
方法不过,也有解决办法。一种是使用默认方法,如您所示,而另一种方法是使用静态方法,如Andrew's answer所示
另一种方法是使用高阶函数:
你可以这样使用它:
# 3 楼答案
Function
和Consumer
服务于两个不同的主人(在某种意义上)BiFunction
的情况下是两种),并生成第三种类型,可以是第一种类型,也可以是第二种类型李>BiConsumer
类型,则接受两种),并产生无输出李>在和两种情况下,都应该执行离散的和单一的操作,这将更容易推断操作的线程安全性
它看起来像是在尝试将一种类型映射到另一种类型(字符串到整数),然后对其调用一个操作。如果您的元素位于
Stream
中,可以这样写:。。。如果它在一个集合或
IntStream
中,你可以用这个来代替:最终,你所尝试的可能是寻找问题的解决方案。一旦你对功能和消费者实际扮演的角色有了更清晰的认识,尝试像上面这样的组合就变得不那么必要了
# 4 楼答案
没有理由不将此组合作为函数API的一部分存在。Java8的设计者根本没有预见到所有可能的组合和用例:这就是为什么Java9添加了一些更方便的方法,我们可能会在即将发布的版本中看到更多
关于“改进”功能,我不敢仅仅为此创建一个新接口,尤其是考虑到接口名称的选择。后缀“Improved”和所有“util”、“Helpers”等一样,不具备自我解释的语义,应该避免使用。更好的解决方案是创建一个功能名称空间,如下所示: