我如何定义一个方法,以一个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);
}
}
339898 次浏览

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

换句话说,您定义或使用一个函数接口(即具有单一方法的接口),该接口接受并返回您想要的内容。

从Java 8开始,在java.util.function中有一组常用的接口类型。

对于这个特定的用例,有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);
}

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

有一个支持lambda的Java 8 JavaDocs的公共web可访问版本,从http://lambdafaq.org/lambda-resources链接。(这显然应该是对Joachim Sauer的回答的评论,但我无法进入我的SO帐户,我需要声望点来添加评论。)lambdafaq站点(由我维护)回答了这个问题和许多其他Java-lambda问题。

注意:这个答案是在Java 8 GA文档变成公开的之前写的。不过,我把λ常见问题解答留在原地,因为对于学习Java 8中引入的特性的人来说,λ常见问题解答可能仍然有用。

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


}
}

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


}
}

对于不超过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已经提供的所有接口,请参考页面

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

如果有功能接口-

interface IMyFunc {
boolean test(int num);
}

还有一个filter方法,它只在int值大于5时才将int值添加到列表中。这里注意,filter方法有函数接口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);
}
}

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

参数→method_body

下面是一种方法,你可以定义一个以函数接口(lambda)为参数的方法。 a.如果你想在函数接口中定义一个方法, 例如,功能界面作为参数/形参被赋给从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)
}
       

}

FInterface fi = (x) ->{返回0;};

funcUsesAnonymousOrLambda (fi);

在上面我们可以看到,lambda表达式是如何被接口替换的。

以上解释了lambda表达式的一个特殊用法,还有更多。 裁判 Java 8 lambda内的lambda不能从外部lambda修改变量 < / p >

这很简单。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");
}
}

就是这样!

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。

对于任何正在谷歌这个的人来说,一个好方法是使用java.util.function.BiConsumer。 例:< / p >
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

对我来说,最有意义的解决方案是定义一个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 a,它只是一个常规接口;lambda是你可以用来实现它的快捷语法的名称。

做以下…

你已经声明了method(lambda l) 你所要做的就是创建一个名为lambda的接口,并声明一个抽象方法

public int add(int a,int b);

方法名称在这里不重要。

所以当你调用MyClass.method( (a,b)->a+b) 这个实现(a,b)->a+b将被注入到你的接口add方法中,所以无论你何时调用l.add,它都会接受这个实现并执行ab的加法,而return l.add(2,3)将返回5。 -基本上这就是lambda的作用..

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

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

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

希望能有所帮助

下面是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);
}
}

如果你同时使用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;
});
        

}