如何在Java8中为void(不是Void)方法指定函数types?

我正在玩Java 8,以了解如何作为一stream的公民function。 我有以下代码片段:

package test; import java.util.*; import java.util.function.*; public class Test { public static void myForEach(List<Integer> list, Function<Integer, Void> myFunction) { list.forEach(functionToBlock(myFunction)); } public static void displayInt(Integer i) { System.out.println(i); } public static void main(String[] args) { List<Integer> theList = new ArrayList<>(); theList.add(1); theList.add(2); theList.add(3); theList.add(4); theList.add(5); theList.add(6); myForEach(theList, Test::displayInt); } } 

我想要做的是传递方法displayInt方法myForEach使用方法引用。 要编译器产生以下错误:

 src/test/Test.java:9: error: cannot find symbol list.forEach(functionToBlock(myFunction)); ^ symbol: method functionToBlock(Function<Integer,Void>) location: class Test src/test/Test.java:25: error: method myForEach in class Test cannot be applied to given ty pes; myForEach(theList, Test::displayInt); ^ required: List<Integer>,Function<Integer,Void> found: List<Integer>,Test::displayInt reason: argument mismatch; bad return type in method reference void cannot be converted to Void 

编译器抱怨void cannot be converted to Void 。 我不知道如何在myForEach的签名中指定函数接口的types,以便代码编译。 我知道我可以简单地改变displayInt的返回types为Void ,然后返回null 。 但是,在某些情况下,不可能改变我想要通过别处的方法。 有没有一种简单的方法重用displayInt

您正试图使用​​错误的接口types。 在这种情况下, 函数types不合适,因为它接收参数并具有返回值。 相反,你应该使用消费者 (以前称为块)

函数types被声明为

 interface Function<T,R> { R apply(T t); } 

但是,消费者types与您正在寻找的兼容:

 interface Consumer<T> { void accept(T t); } 

因此,消费者与接收T并且什么也不返回(void)的方法兼容。 这就是你想要的。

例如,如果我想显示列表中的所有元素,我可以简单地用lambdaexpression式创build一个消费者:

 List<String> allJedi = asList("Luke","Obiwan","Quigon"); allJedi.forEach( jedi -> System.out.println(jedi) ); 

你可以在上面看到,在这种情况下,lambdaexpression式接收一个参数并且没有返回值。

现在,如果我想使用方法引用而不是lambdaexpression式来创build这种types的消耗,那么我需要一个方法来接收一个string并返回void,对吗?

我可以使用不同types的方法引用,但在这种情况下,我们通过使用System.out对象中的println方法来利用对象方法引用,如下所示:

 Consumer<String> block = System.out::println 

或者我可以简单地做

 allJedi.forEach(System.out::println); 

println方法是合适的,因为它接收一个值并具有返回typesvoid,就像Consumer中的accept方法一样。

因此,在您的代码中,您需要将您的方法签名更改为:

 public static void myForEach(List<Integer> list, Consumer<Integer> myBlock) { list.forEach(myBlock); } 

然后你应该可以创build一个使用静态方法引用的消费者:

 myForEach(theList, Test::displayInt); 

最终,你甚至可以完全摆脱你的myForEach方法,简单地做:

 theList.forEach(Test::displayInt); 

作为一等公民的职能

所有人都说,事实是,Java 8将不具有作为一等公民的function,因为结构functiontypes不会被添加到语言中。 Java将简单地提供语法糖来创buildlambdaexpression式和方法引用的function接口的实现。 最终,lambdaexpression式和方法引用将被绑定到对象引用,因此我们所有的对象都是一等公民。 重要的是function在那里,因为我们可以传递对象作为参数,将它们绑定到variables引用,并将它们作为其他方法的值返回,然后它们几乎可以达到类似的目的。

当你需要接受一个函数作为不带参数的参数,并且返回没有结果(void)的时候,在我看来,最好还是有一些像

  private interface Thunk { void apply(); } 

在你的代码的某处。 在我的function性编程课程中,“thunk”这个词被用来描述这样的function。 为什么它不在java.util.function中超出我的理解。

在其他情况下,我发现即使java.util.function确实有某些符合我想要的签名的东西 – 当接口的命名与我的代码中的函数的使用不匹配时,它仍然不总是感觉正确。 我猜这是关于'Runnable'(这是与Thread类有关的术语)在其他地方提出的类似点,所以虽然它可能具有我需要的签名,但它仍然可能使读者混淆。