当我尝试使用带有两个void方法的函数组合时,我遇到了一个奇怪的(对我而言)行为。我写了一个简单的例子来说明问题:
debug_response
当我尝试编译第一个解决方案时,在andThe调用之前说“')'期望”。
当我明确地说这是“消费者”时,代码已编译并且可以按预期工作。
有人可以向我解释为什么会这样吗,还有使用Java 8进行void方法的函数组合的另一种方式吗?
答案 0 :(得分:4)
这与Java推断,转换和检测lambda中的类型的方式有关。如上面的评论中所述,尚未进行到Consumer<Foo>
的转换,这意味着编译器不知道这是Consumer
,因此以后可以链接andThen()
。< / p>
将其显式转换为Consumer
并正确使用括号将使您获得所需的效果:
List<Foo> foos = new ArrayList<>();
foos.forEach(((Consumer<Foo>) Null::doSomething).andThen(Null::doSomething2));
我猜想如果您随便摆弄它,可以使用类型见证人实现相同的行为,但是我不确定100%是否可以达到预期的结果。
我第一次注意到这是使用链接比较器,它们可能表现出相同的行为。对此进行在线搜索将向您显示有关其工作原理的更多复杂细节。
答案 1 :(得分:4)
让我们变得更简单:
private static boolean test(String input){
return input.equals("123");
}
Predicate<String> predicate = YourClass::test;
Function<String, Boolean> function = YourClass::test;
因此,方法引用是 poly 表达式(例如,类似于泛型),它们取决于使用它们的上下文。因此,您的Startup::doSomething
方法引用可以是符合该方法的 any @FunctionalInterface
。在这种情况下,您可能会发现它是Consumer
,但对于编译器来说却是另一回事。
答案 2 :(得分:1)
就像Consumer所述:
这是一个功能接口,因此可以用作lambda表达式或方法引用的分配目标。
功能接口为我们提供了两种方法:
void accept(T t)
default Consumer<T> andThen(Consumer<? super T> after)
关于andThen(...)
:
返回一个组成的使用者,该使用者依次执行此操作,然后执行after操作。
功能接口是Java 8提供的语法糖,我们可以只传递lambda
或method reference
,我们可以获得更多有用/辅助的功能,我们经常需要(默认行为)。
在这里,我们可以使用andThen
对于您的情况,您可以尝试以下操作:
public class CastToFunctionalInterface {
public static void main(String... args) {
((Consumer<Integer>) CastToFunctionalInterface::consumeInteger)
.andThen(CastToFunctionalInterface::consumeAnotherInteger)
.accept(10);
}
private static void consumeInteger(Integer a) {
System.out.println("I'm an Integer: " + a);
}
private static void consumeAnotherInteger(Integer b) {
System.out.println("I'm another integer: " + b);
}
}
输出:
I'm an Integer: 10
I'm another integer: 10