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

查看:144
本文介绍了如何在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);
    }
}

我要做的是传递方法<使用方法引用code> 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?

推荐答案

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

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);
}

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

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

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

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

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?.

我可以使用不同类型的方法引用,但在这种情况下,让我们通过使用 println System.out 对象中的$ c>方法,如下所示:

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天全站免登陆