为什么我们不能像编写函数一样构成函数和消费者?
Function<Integer, String> a = Object::toString;
Consumer<String> b = x -> System.out.println(x);
Consumer<Integer> composed = a.andThen(b);
这似乎是对现有Function接口的明显即兴创作。是否有任何理由在Java 8中避免使用此功能?
此外,通常的做法是使用函数的扩展实现,如下所示?
interface FunctionImproved<T, R> extends Function<T, R> {
default Consumer<T> andThen(Consumer<R> consumer) {
return x -> consumer.accept(apply(x));
}
}
答案 0 :(得分:2)
andThen
个实例上的Function<A0, A1>
方法需要Function<A1, A2>
,而不是Consumer<A1>
:
a.andThen(string -> {
b.accept(string);
return string;
});
由于我们的消费者&#34;它有副作用。 (实际上,它是Function<A1, A1>
)将从之前的Function<Integer, String> a
函数返回一个被忽略的值。这不是我们想要的。
撰写Function<A0, A1>
和Consumer<A1>
:
Consumer<Integer> c = i -> b.accept(a.apply(i));
可以推广到实用方法:
<A0, A1> Consumer<A0> functionAndThenConsumer(Function<A0, A1> f, Consumer<A1> c) {
return i -> c.accept(f.apply(i));
}
使用
Function
的扩展实现是否是一种常见做法?
有两种选择:
使用静态方法在功能接口之间进行一些转换(就像我一样)。
使用默认方法扩展这些标准功能接口(就像您一样)。只需选择一个正确有意义的名称,而不是FunctionImproved
。
答案 1 :(得分:1)
Function
和Consumer
为两位不同的主人服务(在某种意义上)。
BiFunction
个)类型并生成第三个类型,可以是第一个或第二个类型。BiConsumer
个)类型,并生成 no 输出。在两个案例中,应该执行离散和单操作,这样可以更轻松地推理操作&# 39; s线程安全。
它看起来就像你正在尝试将一种类型的简单映射到另一种类型(String to Integer),然后在其上调用一个操作。如果您的元素位于Stream
,则可以写为:
elements.map(Objects::toString).forEach(System.out::println);
...如果它在集合或IntStream
中,您可以改为使用它:
elements.forEach(System.out::println);
最终,您尝试的可能是寻找问题的解决方案。一旦你对功能和消费者实际扮演的角色更加清楚,那么对上述作品的尝试就变得不那么必要了。