如何在 Java8 中为 void(非 Void)方法指定函数类型? [英] How to specify function types for void (not Void) methods in Java8?

查看:24
本文介绍了如何在 Java8 中为 void(非 Void)方法指定函数类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Java 8,以了解如何作为一等公民发挥作用.我有以下片段:

I'm playing around with Java 8 to find out how functions as first class citizens. I have the following snippet:

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.编译器产生以下错误:

What I'm trying to do is pass method displayInt to method myForEach using a method reference. To compiler produces the following error:

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 不能转换为Void.我不知道如何在 myForEach 的签名中指定函数接口的类型,以便代码编译.我知道我可以简单地将 displayInt 的返回类型更改为 Void,然后返回 null.但是,在某些情况下,可能无法更改我想在其他地方传递的方法.是否有一种简单的方法可以按原样重复使用 displayInt?

The compiler complains that void cannot be converted to Void. I don't know how to specify the type of the function interface in the signature of myForEach such that the code compiles. I know I could simply change the return type of displayInt to Void and then return null. However, there may be situations where it's not possible to alter the method I want to pass somewhere else. Is there an easy way to reuse displayInt as it is?

推荐答案

您正在尝试使用错误的接口类型.Function 类型不适合这种情况是因为它接收一个参数并有一个返回值.相反,您应该使用 Consumer(以前是称为块)

You are trying to use the wrong interface type. The type Function is not appropriate in this case because it receives a parameter and has a return value. Instead you should use Consumer (formerly known as Block)

函数类型声明为

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

但是,Consumer 类型与您要查找的类型兼容:

However, the Consumer type is compatible with that you are looking for:

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

因此,Consumer 与接收 T 且不返回任何内容 (void) 的方法兼容.这就是你想要的.

As such, Consumer is compatible with methods that receive a T and return nothing (void). And this is what you want.

例如,如果我想显示列表中的所有元素,我可以简单地使用 lambda 表达式为其创建一个使用者:

For instance, if I wanted to display all element in a list I could simply create a consumer for that with a lambda expression:

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

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

You can see above that in this case, the lambda expression receives a parameter and has no return value.

现在,如果我想使用方法引用而不是 lambda 表达式来创建这种类型的消费,那么我需要一个接收 String 并返回 void 的方法,对吧?

Now, if I wanted to use a method reference instead of a lambda expression to create a consume of this type, then I need a method that receives a String and returns void, right?.

我可以使用不同类型的方法引用,但在这种情况下,让我们通过使用 System.out 对象中的 println 方法来利用对象方法引用,像这样:

I could use different types of method references, but in this case let's take advantage of an object method reference by using the println method in the System.out object, like this:

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

或者我可以简单地做

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

println 方法是合适的,因为它接收一个值并有一个返回类型 void,就像 Consumer 中的 accept 方法一样.

The println method is appropriate because it receives a value and has a return type void, just like the accept method in Consumer.

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

So, in your code, you need to change your method signature to somewhat like:

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

然后您应该能够使用静态方法引用创建一个使用者,在您的情况下执行以下操作:

And then you should be able to create a consumer, using a static method reference, in your case by doing:

myForEach(theList, Test::displayInt);

最终,您甚至可以完全摆脱您的 myForEach 方法,只需执行以下操作:

Ultimately, you could even get rid of your myForEach method altogether and simply do:

theList.forEach(Test::displayInt);

关于一等公民的职能

总而言之,事实是 Java 8 不会将函数作为一等公民,因为不会将结构函数类型添加到语言中.Java 将简单地提供一种替代方法来从 lambda 表达式和方法引用中创建函数式接口的实现.最终 lambda 表达式和方法引用将绑定到对象引用,因此我们所拥有的只是作为一等公民的对象.重要的是功能在那里,因为我们可以将对象作为参数传递,将它们绑定到变量引用并将它们作为值从其他方法返回,然后它们几乎可以用于类似的目的.

All been said, the truth is that Java 8 will not have functions as first-class citizens since a structural function type will not be added to the language. Java will simply offer an alternative way to create implementations of functional interfaces out of lambda expressions and method references. Ultimately lambda expressions and method references will be bound to object references, therefore all we have is objects as first-class citizens. The important thing is the functionality is there since we can pass objects as parameters, bound them to variable references and return them as values from other methods, then they pretty much serve a similar purpose.

这篇关于如何在 Java8 中为 void(非 Void)方法指定函数类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆