我正在使用 Java 8 来了解如何作为一等公民发挥作用。我有以下片段:
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编译器会产生以下错误:
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在代码编译的签名中指定函数接口的类型。我知道我可以简单地更改 to 的返回类型,displayInt然后Void返回null。但是,可能存在无法更改我想在其他地方传递的方法的情况。有没有一种简单的方法可以displayInt按原样重复使用?
void cannot be converted to Void
Void
null
您正在尝试使用错误的接口类型。在这种情况下, Function类型不合适,因为它接收参数并具有返回值。相反,您应该使用Consumer(以前称为 Block)
函数类型声明为
interface Function<T,R> { R apply(T t); }
但是,消费者类型与您正在寻找的类型兼容:
interface Consumer<T> { void accept(T t); }
因此,Consumer 与接收 T 且不返回任何内容 (void) 的方法兼容。这就是你想要的。
例如,如果我想显示列表中的所有元素,我可以简单地使用 lambda 表达式为其创建消费者:
List<String> allJedi = asList("Luke","Obiwan","Quigon"); allJedi.forEach( jedi -> System.out.println(jedi) );
您可以在上面看到,在这种情况下,lambda 表达式接收一个参数并且没有返回值。
现在,如果我想使用方法引用而不是 lambda 表达式来创建这种类型的消费,那么我需要一个接收 String 并返回 void 的方法,对吧?
println我可以使用不同类型的方法引用,但在这种情况下,让我们通过使用对象中的方法来利用对象方法引用System.out,如下所示:
println
System.out
Consumer<String> block = System.out::println
或者我可以简单地做
allJedi.forEach(System.out::println);
该println方法是合适的,因为它接收一个值并且返回类型为 void,就像acceptConsumer 中的方法一样。
accept
因此,在您的代码中,您需要将方法签名更改为:
public static void myForEach(List<Integer> list, Consumer<Integer> myBlock) { list.forEach(myBlock); }
然后您应该能够使用静态方法引用创建消费者,在您的情况下,通过执行以下操作:
myForEach(theList, Test::displayInt);
最终,您甚至可以完全摆脱您的myForEach方法,只需执行以下操作:
theList.forEach(Test::displayInt);
关于作为一等公民的职能
总而言之,事实是 Java 8 不会有函数作为一等公民,因为不会将结构函数类型添加到语言中。Java 将简单地提供另一种方法来创建函数式接口的实现 lambda 表达式和方法引用。最终 lambda 表达式和方法引用将绑定到对象引用,因此我们所拥有的只是作为一等公民的对象。重要的是功能在那里,因为我们可以将对象作为参数传递,将它们绑定到变量引用并将它们作为来自其他方法的值返回,然后它们几乎可以用于类似的目的。