如何定义在Java 8中将lambda作为参数的方法?

Mar*_*ius 331 java lambda java-8

在Java 8中,方法可以创建为Lambda表达式,并且可以通过引用传递(通过一些工作).有大量的在线示例,lambdas被创建并与方法一起使用,但没有关于如何使用lambda作为参数的方法的示例.那是什么语法?

MyClass.method((a, b) -> a+b);


class MyClass{
  //How do I define this method?
  static int method(Lambda l){
    return l(5, 10);
  }
}
Run Code Online (Sandbox Code Playgroud)

Joa*_*uer 227

Lambdas纯粹是一个调用站点构造:lambda的接收者不需要知道涉及Lambda,而是接受具有适当方法的接口.

换句话说,您定义或使用功能接口(即具有单个方法的接口)接受并准确返回您想要的内容.

为此,Java 8附带了一组常用的接口类型java.util.function(感谢Maurice Naftalin提供有关JavaDoc的提示).

对于这个特定的用例,java.util.function.IntBinaryOperator只有一个int applyAsInt(int left, int right)方法,所以你可以写method这样的:

static int method(IntBinaryOperator op){
    return op.applyAsInt(5, 10);
}
Run Code Online (Sandbox Code Playgroud)

但你也可以定义自己的界面并像这样使用它:

public interface TwoArgIntOperator {
    public int op(int a, int b);
}

//elsewhere:
static int method(TwoArgIntOperator operator) {
    return operator.op(5, 10);
}
Run Code Online (Sandbox Code Playgroud)

使用您自己的界面的优势在于您可以使用更清楚地表明意图的名称.

  • @TomášZato:如果你使用带有不匹配参数的lambda,编译器会抱怨.并且具有两个(非默认)方法的接口将不能用作lambdas,因为只能使用[功能接口](http://www.lambdafaq.org/what-is-a-functional-interface/). (6认同)
  • 是否有内置接口可供使用,还是我必须为每个我想要的lambda创建一个接口? (4认同)
  • 我不明白。他可以将 lambda 传递给任何东西并且它会起作用吗?如果他为 `TwoArgIntOperator` 传递 `(int a, int b, int c)` 会发生什么。如果 `TwoArgIntOperator` 有**两个**具有相同签名的方法,会发生什么。这个答案令人困惑。 (2认同)

par*_*085 59

要使用Lambda表达式,您需要创建自己的功能接口或使用Java功能接口进行需要两个整数并返回值的操作.IntBinaryOperator

使用用户定义的功能界面

interface TwoArgInterface {

    public int operation(int a, int b);
}

public class MyClass {

    public static void main(String javalatte[]) {
        // this is lambda expression
        TwoArgInterface plusOperation = (a, b) -> a + b;
        System.out.println("Sum of 10,34 : " + plusOperation.operation(10, 34));

    }
}
Run Code Online (Sandbox Code Playgroud)

使用Java功能接口

import java.util.function.IntBinaryOperator;

public class MyClass1 {

    static void main(String javalatte[]) {
        // this is lambda expression
        IntBinaryOperator plusOperation = (a, b) -> a + b;
        System.out.println("Sum of 10,34 : " + plusOperation.applyAsInt(10, 34));

    }
}
Run Code Online (Sandbox Code Playgroud)

我创建的其他示例就在这里


小智 35

对于参数不超过2的函数,可以在不定义自己的接口的情况下传递它们.例如,

class Klass {
  static List<String> foo(Integer a, String b) { ... }
}

class MyClass{

  static List<String> method(BiFunction<Integer, String, List<String>> fn){
    return fn.apply(5, "FooBar");
  }
}

List<String> lStr = MyClass.method((a, b) -> Klass.foo((Integer) a, (String) b));
Run Code Online (Sandbox Code Playgroud)

BiFunction<Integer, String, List<String>>,Integer而且String是它的参数,List<String>是它的返回类型.

对于只有一个参数的函数,您可以使用Function<T, R>,T其参数类型在哪里,并且R是其返回值类型.有关Java已提供的所有接口,请参阅此页面.


Mau*_*lin 15

有一个支持Lambda的Java 8 JavaDocs的公共Web可访问版本,链接自http://lambdafaq.org/lambda-resources.(这显然应该是对Joachim Sauer的答案的评论,但我无法通过我需要添加评论的声誉点进入我的SO帐户.)lambdafaq网站(我维护它)回答了这个以及很多其他Java -lambda问题.

注意:这个答案是在Java 8 GA文档公开之前编写的.不过,我已经离开了,因为对于了解Java 8中引入的功能的人来说,Lambda FAQ可能仍然有用.

  • 感谢您的链接以及您维护该网站的事实!我冒昧地向你的公共JavaDoc添加链接到我的答案. (2认同)

Big*_*d_E 6

对于使用谷歌搜索的任何人,最好使用java.util.function.BiConsumer。例如:

Import java.util.function.Consumer
public Class Main {
    public static void runLambda(BiConsumer<Integer, Integer> lambda) {
        lambda.accept(102, 54)
    }

    public static void main(String[] args) {
        runLambda((int1, int2) -> System.out.println(int1 + " + " + int2 + " = " + (int1 + int2)));
    }
Run Code Online (Sandbox Code Playgroud)

输出是:166


小智 5

Lambda表达式可以作为参数传递。要将Lambda表达式作为参数传递,参数的类型(将lambda表达式作为参数接收)必须具有功能接口类型。

如果有功能界面-

interface IMyFunc {
   boolean test(int num);
}
Run Code Online (Sandbox Code Playgroud)

并且有一个过滤器方法仅在列表中大于5的情况下才将int添加到列表中。请注意,此处的过滤器方法将函数接口IMyFunc作为参数之一。在这种情况下,可以将lambda表达式作为方法参数的参数传递。

public class LambdaDemo {
    public static List<Integer> filter(IMyFunc testNum, List<Integer> listItems) {
        List<Integer> result = new ArrayList<Integer>();
        for(Integer item: listItems) {
            if(testNum.test(item)) {
                result.add(item);
            }
        }
        return result;
    }
    public static void main(String[] args) {
        List<Integer> myList = new ArrayList<Integer>();
        myList.add(1);
        myList.add(4);
        myList.add(6);
        myList.add(7);
        // calling filter method with a lambda expression
        // as one of the param
        Collection<Integer> values = filter(n -> n > 5, myList);

        System.out.println("Filtered values " + values);
    }
}
Run Code Online (Sandbox Code Playgroud)


fla*_*yte 5

对我来说,最有意义的解决方案是定义一个Callback接口:

interface Callback {
    void call();
}
Run Code Online (Sandbox Code Playgroud)

然后将其用作您要调用的函数中的参数:

void somewhereInYourCode() {
    method(() -> {
        // You've passed a lambda!
        // method() is done, do whatever you want here.
    });
}

void method(Callback callback) {
    // Do what you have to do
    // ...

    // Don't forget to notify the caller once you're done
    callback.call();
}
Run Code Online (Sandbox Code Playgroud)

虽然只是一个精度

Lambda不是特殊的接口,类或您可以自己声明的其他任何东西。Lambda只是() -> {}特殊语法的名称,当将单方法接口作为参数传递时,可以提高可读性。它旨在替代此:

method(new Callback() {
    @Override
    public void call() {
        // Classic interface implementation, lot of useless boilerplate code.
        // method() is done, do whatever you want here.
    }
});
Run Code Online (Sandbox Code Playgroud)

所以在上面的例子中,Callback不是一个lambda,这只是一个普通的接口; lambda是可用于实现它的快捷方式语法的名称。

  • 我们还可以使用Runnable来代替上面的接口 (4认同)

小智 5

您可以使用上面提到的函数式接口。以下是一些示例

Function<Integer, Integer> f1 = num->(num*2+1);
System.out.println(f1.apply(10));

Predicate<Integer> f2= num->(num > 10);
System.out.println(f2.test(10));
System.out.println(f2.test(11));

Supplier<Integer> f3= ()-> 100;
System.out.println(f3.get());
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你