430

在 Java 8 中,方法可以创建为 Lambda 表达式,并且可以通过引用传递(在后台做一些工作)。网上有很多关于创建 lambda 并将其与方法一起使用的示例,但没有关于如何制作将 lambda 作为参数的方法的示例。它的语法是什么?

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


class MyClass{
  //How do I define this method?
  static int method(Lambda l){
    return l(5, 10);
  }
}
4

16 回答 16

290

Lambda 纯粹是一个调用站点构造: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);
}

但是您也可以定义自己的接口并像这样使用它:

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

//elsewhere:
static int method(TwoArgIntOperator operator) {
    return operator.op(5, 10);
}

然后使用 lambda 作为参数调用该方法:

public static void main(String[] args) {
    TwoArgIntOperator addTwoInts = (a, b) -> a + b;
    int result = method(addTwoInts);
    System.out.println("Result: " + result);
}

使用您自己的界面的好处是您可以使用更清楚地表明意图的名称。

于 2012-11-28T12:09:03.720 回答
72

要使用 Lambda 表达式,您需要创建自己的函数式接口或使用 Java 函数式接口进行需要两个整数并作为值返回的操作。整数二元运算符

使用用户定义的功能接口

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

    }
}

使用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));

    }
}
于 2014-03-19T15:28:46.983 回答
44

对于不超过 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));

其中BiFunction<Integer, String, List<String>>IntegerString是它的参数,并且List<String>是它的返回类型。

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

于 2015-05-27T03:19:32.710 回答
17

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

interface Callback {
    void call();
}

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

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

虽然只是一个精度

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

所以在上面的例子中,Callback不是lambda,它只是一个常规接口;lambda是您可以用来实现它的快捷语法的名称。

于 2018-11-19T15:32:05.417 回答
15

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

注意 这个答案是在 Java 8 GA 文档公开之前编写的。不过,我已经离开了,因为Lambda 常见问题解答可能对学习 Java 8 中引入的功能的人仍然有用。

于 2012-11-28T12:59:24.073 回答
9

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

如果有功能接口——

interface IMyFunc {
   boolean test(int num);
}

并且有一个过滤器方法,它仅在大于 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);
    }
}
于 2015-08-11T17:09:31.110 回答
7

对于任何正在谷歌搜索的人,一个好方法是使用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)));
    }

输出将是:166

于 2018-08-19T19:07:16.347 回答
4

Lambda 不是一个对象,而是一个功能接口。使用@FuntionalInterface 作为注解可以定义尽可能多的功能接口

@FuntionalInterface
public interface SumLambdaExpression {
     public int do(int a, int b);
}

public class MyClass {
     public static void main(String [] args) {
          SumLambdaExpression s = (a,b)->a+b;
          lambdaArgFunction(s);
     }

     public static void lambdaArgFunction(SumLambdaExpression s) {
          System.out.println("Output : "+s.do(2,5));
     }
}

输出如下

Output : 7

Lambda 表达式的基本概念是定义您自己的逻辑但已经定义了参数。因此,在上面的代码中,您可以将 do 函数的定义从添加到任何其他定义,但您的参数限制为 2。

于 2018-06-04T09:56:14.610 回答
4

您可以使用上面提到的功能接口。下面是一些例子

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

希望能帮助到你

于 2019-10-22T15:54:43.740 回答
3

基本上,要将 lamda 表达式作为参数传递,我们需要一个可以保存它的类型。就像我们在原始int或 Integer 类中保存的整数值一样。Java 没有单独的 lamda 表达式类型,而是使用接口作为保存参数的类型。但是那个接口应该是一个功能接口

于 2019-05-10T07:32:25.067 回答
2

嗯,这很容易。lambda 表达式的目的是实现功能接口。它是只有一种方法的接口。这是关于预定义和遗留功能接口的很棒的文章。

无论如何,如果你想实现自己的功能接口,那就去做吧。仅举一个简单的例子:

public interface MyFunctionalInterface {
    String makeIt(String s);
}

所以让我们创建一个类,我们将在其中创建一个方法,该方法接受MyFunctionalInterface的类型:

public class Main {

    static void printIt(String s, MyFunctionalInterface f) {
        System.out.println(f.makeIt(s));
    }

    public static void main(String[] args) {

    }
}

您应该做的最后一件事是将MyFunctionalInterface的实现传递给我们定义的方法:

public class Main {

    static void printIt(String s, MyFunctionalInterface f) {
        System.out.println(f.makeIt(s));
    }

    public static void main(String[] args) {
        printIt("Java", s -> s + " is Awesome");
    }
}

就是这样!

于 2018-04-20T05:46:21.270 回答
0

请执行下列操作 ..

您已经声明method(lambda l) 了您要做的就是创建一个具有名称的接口lambda并声明一个抽象方法

public int add(int a,int b);  

方法名称在这里无关紧要..

所以当你调用MyClass.method( (a,b)->a+b) 这个实现时,这个实现 (a,b)->a+b将被注入到你的接口添加方法中。所以每当你调用l.add它时,它都会采用这个实现并执行 加法a和返回。- 基本上这就是 lambda 所做的..breturn l.add(2,3)5

于 2019-04-20T08:21:45.110 回答
0

以下是 C# 处理此问题的大致方式(但表示为 Java 代码)。像这样的东西几乎可以满足您的所有需求:

import static org.util.function.Functions.*;

public class Test {

    public static void main(String[] args)
    {
        Test.invoke((a, b) -> a + b);       
    }

    public static void invoke(Func2<Integer, Integer, Integer> func)
    {
        System.out.println(func.apply(5, 6));
    }
}

package org.util.function;

public interface Functions {

    //Actions:
    public interface Action {
        public void apply();
    }

    public interface Action1<T1> {
        public void apply(T1 arg1);
    }

    public interface Action2<T1, T2> {
        public void apply(T1 arg1, T2 arg2);
    }

    public interface Action3<T1, T2, T3> {
        public void apply(T1 arg1, T2 arg2, T3 arg3);
    }

    public interface Action4<T1, T2, T3, T4> {
        public void apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
    }

    public interface Action5<T1, T2, T3, T4, T5> {
        public void apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
    }

    public interface Action6<T1, T2, T3, T4, T5, T6> {
        public void apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
    }

    public interface Action7<T1, T2, T3, T4, T5, T6, T7> {
        public void apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
    }

    public interface Action8<T1, T2, T3, T4, T5, T6, T7, T8> {
        public void apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
    }

    //Functions:
    public interface Func<TResult> {
        public TResult apply();
    }

    public interface Func1<T1, TResult> {
        public TResult apply(T1 arg1);
    }

    public interface Func2<T1, T2, TResult> {
        public TResult apply(T1 arg1, T2 arg2);
    }

    public interface Func3<T1, T2, T3, TResult> {
        public TResult apply(T1 arg1, T2 arg2, T3 arg3);
    }

    public interface Func4<T1, T2, T3, T4, TResult> {
        public TResult apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
    }

    public interface Func5<T1, T2, T3, T4, T5, TResult> {
        public TResult apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
    }

    public interface Func6<T1, T2, T3, T4, T5, T6, TResult> {
        public TResult apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
    }

    public interface Func7<T1, T2, T3, T4, T5, T6, T7, TResult> {
        public TResult apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
    }

    public interface Func8<T1, T2, T3, T4, T5, T6, T7, T8, TResult> {
        public TResult apply(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
    }
}
于 2020-01-27T03:24:41.817 回答
0

如果您使用 Java 和 Kotlin 语言(就像我们在 Android 开发中所做的那样),您可以传递 lambda 函数而无需定义任何额外的接口:

import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
import kotlin.jvm.functions.Function2;

void foo(Function0<Boolean> param1) //for zero param
{
    param1.invoke();
}

void foo1(Function1<Integer, Boolean> param1) //for one param
{
    param1.invoke(1);
}

void foo2(Function2<Integer, Boolean, Boolean> param1) //for two param
{
    param1.invoke(1, true);
}

//how to call
void main() 
{
    foo(() -> {
        return true;
    });

    foo1((var1) -> {
        return true;
    });

    foo2((var1, var2) -> {
        return true;
    });
        
}
于 2021-08-17T12:08:00.503 回答
-1

一旦方法由接口实现,您可以将方法设置为参数。

于 2021-10-14T15:54:14.680 回答
-2

使用 lambda 作为参数具有灵活性。它支持java中的函数式编程。基本语法是

参数-> method_body

以下是一种方法,您可以定义一个以功能接口(使用 lambda)作为参数的方法。一种。如果您希望定义在功能接口内声明的方法,例如,功能接口作为参数/参数提供给从调用的方法main()

@FunctionalInterface
interface FInterface{
    int callMeLambda(String temp);
}


class ConcreteClass{
        
    void funcUsesAnonymousOrLambda(FInterface fi){
        System.out.println("===Executing method arg instantiated with Lambda==="));
    }
        
    public static void main(){
        // calls a method having FInterface as an argument.
        funcUsesAnonymousOrLambda(new FInterface() {
        
            int callMeLambda(String temp){ //define callMeLambda(){} here..
                return 0;
            }
        }
    }
        
/***********Can be replaced by Lambda below*********/
        funcUsesAnonymousOrLambda( (x) -> {
            return 0; //(1)
        }
       
    }

F接口 fi = (x) -> { return 0; };

funcUsesAnonymousOrLambda(fi);

从上面可以看出,如何用接口替换 lambda 表达式。

上面解释了 lambda 表达式的一个特定用法,还有更多。参考 lambda 中的 Java 8 lambda 不能从外部 lambda 修改变量

于 2017-03-13T23:35:15.403 回答