How do I define a method which takes a lambda as a parameter in Java 8?
Asked Answered
K

16

492

In Java 8, methods can be created as Lambda expressions and can be passed by reference (with a little work under the hood). There are plenty of examples online with lambdas being created and used with methods, but no examples of how to make a method taking a lambda as a parameter. What is the syntax for that?

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

class MyClass{
  //How do I define this method?
  static int method(Lambda l) {
    return l(5, 10);
  }
}
Kenleigh answered 28/11, 2012 at 12:6 Comment(1)
Good question. And you are right: None of the tutorials contain that part.Ajmer
S
324

Lambdas are purely a call-site construct: the recipient of the lambda does not need to know that a Lambda is involved, instead it accepts an Interface with the appropriate method.

In other words, you define or use a functional interface (i.e. an interface with a single method) that accepts and returns exactly what you want.

Since Java 8 there is a set of commonly-used interface types in java.util.function.

For this specific use case there's java.util.function.IntBinaryOperator with a single int applyAsInt(int left, int right) method, so you could write your method like this:

static int method(IntBinaryOperator op){
    return op.applyAsInt(5, 10);
}

But you can just as well define your own interface and use it like this:

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

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

Then call the method with a lambda as parameter:

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

Using your own interface has the advantage that you can have names that more clearly indicate the intent.

Sulfite answered 28/11, 2012 at 12:9 Comment(8)
Will there be built-in interfaces to be used, or must I create an interface for every lambda I want to take?Kenleigh
A good compromise to the reusability vs. descriptive name dilemma would be to extend the built in interface without overriding the method it specifies. That gives you your descriptive name with only a single additional line of code.Sulcate
I don't get it. He can pass lambda for anything and it will work? What happens if he passes (int a, int b, int c) for TwoArgIntOperator. What happens if TwoArgIntOperator has two methods with the same signature. This answer is confusing.Visit
@TomášZato: if you use a lambda with non-matching arguments the compiler will complain. And interfaces with two (non-default) methods will not be usable as lambdas, as only functional interfaces can be used.Sulfite
A basic question: I think I still don't understand the aspect of passing a method as a parameter with the parameters of that method missing. If he is passing TwoArgIntOperator as a parameter and he needs to pass the parameter of that method separately, doesn't it look ugly? Is there a way to pass the complete execution body along with the parameter? Like in your example, a way to avoid hardcoding "5" and "10".Fedak
This example doesn't show a lambda being used... Am I missing something?Abuttal
@CameronHudson: the question is about how to define a method that takes a Lambda. I assumed that those who care about that already know how to use a lambda (it's even shown in the question).Sulfite
@Fedak the idea is that whoever you are passing that method/lambda/function to knows by itself what parameters to use, but doesn't know what function to call. The most known examples would be all the Stream manipulations from java.util.stream.*. If you want to pass method + parameters, you basically have a parameterless function (from the point of view of whoever is calling it), and can use Runnable or Producer<T> (depending on whether the return value is needed) as your functional interface.Dicephalous
D
76

To use Lambda expression you need to either create your own functional interface or use Java functional interface for operation that require two integer and return as value. IntBinaryOperator

Using user defined functional interface

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

    }
}

Using Java functional interface

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

    }
}
Denudation answered 19/3, 2014 at 15:28 Comment(4)
The link to the IntBinaryOperator documentation is dead.Antecedence
this is the best example of lambda's I've found so far, and it was the only one that really had me 'get' it finally.Hiero
Sooooooo...basically a delegate, but we're not supposed to call it that?Resilient
This answer doesn't answer the question, which is "how to make a method taking a lambda as a parameter", not "how to create and use a lambda".Matter
T
49

For functions that do not have more than 2 parameters, you can pass them without defining your own interface. For example,

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

In BiFunction<Integer, String, List<String>>, Integer and String are its parameters, and List<String> is its return type.

For a function with only one parameter, you can use Function<T, R>, where T is its parameter type, and R is its return value type. Refer to this page for all the interfaces that are already made available by Java.

Translatable answered 27/5, 2015 at 3:19 Comment(0)
S
25

To me, the solution that makes the most sense is to define a Callback interface :

interface Callback {
    void call();
}

and then to use it as parameter in the function you want to 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();
}

Just a precision though

A lambda is not a special interface, class or anything else you could declare by yourself. Lambda is just the name given to the () -> {} special syntax, which allows better readability when passing single-method interfaces as parameter. It was designed to replace this :

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

So in the example above, Callback is not a lambda, it's just a regular interface ; lambda is the name of the shortcut syntax you can use to implement it.

Serotine answered 19/11, 2018 at 15:32 Comment(2)
We can also use a Runnable instead of the above interfaceMonoatomic
Thanks, finally the simple answer I was looking for! Was having serious doubts that the only way to do this was using the weird-ass classes in the other answers.Pushup
C
16

There's a public Web-accessible version of the Lambda-enabled Java 8 JavaDocs, linked from http://lambdafaq.org/lambda-resources. (This should obviously be a comment on Joachim Sauer's answer, but I can't get into my SO account with the reputation points I need to add a comment.) The lambdafaq site (I maintain it) answers this and a lot of other Java-lambda questions.

NB This answer was written before the Java 8 GA documentation became publicly available. I've left in place, though, because the Lambda FAQ might still be useful to people learning about features introduced in Java 8.

Cochard answered 28/11, 2012 at 12:59 Comment(4)
Thanks for the link and the fact that you maintain that site! I took the liberty to add links to your public JavaDoc to my answer.Sulfite
As a side note: It seems you're building for Lambdas what Angelika Langer has built for Generics. Thanks for that, Java needs such resources!Sulfite
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From ReviewSavannasavannah
@Savannasavannah Yes, agreed. AFAIR I didn't want to add anything to existing answers but only to point out where I had posted a copy of the API documentation, which at that time wasn't otherwise easily accessible.Cochard
B
9

Lambda expression can be passed as a argument.To pass a lambda expression as an argument the type of the parameter (which receives the lambda expression as an argument) must be of functional interface type.

If there is a functional interface -

interface IMyFunc {
   boolean test(int num);
}

And there is a filter method which adds the int in the list only if it is greater than 5. Note here that filter method has funtional interface IMyFunc as one of the parameter. In that case lambda expression can be passed as an argument for the method parameter.

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);
    }
}
Blayne answered 11/8, 2015 at 17:9 Comment(0)
H
7

For anyone who is googling this, a good method would be to use java.util.function.BiConsumer. ex:

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

The outprint would be: 166

Haney answered 19/8, 2018 at 19:7 Comment(2)
Instead of Consumer<Pair<A,B>>, use BiConsumer<A,B> for this case. (docs)Bunsen
Didn't know that existed, I should sift through the function package next time.Haney
P
5

You can use functional interfaces as mentioned above. below are some of the examples

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

Hope it helps

Pelotas answered 22/10, 2019 at 15:54 Comment(0)
K
4

Lambda is not a object but a Functional Interface. One can define as many as Functional Interfaces as they can using the @FuntionalInterface as an annotation

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

The Output will be as follows

Output : 7

The Basic concept of a Lambda Expression is to define your own logic but already defined Arguments. So in the above code the you can change the definition of the do function from addition to any other definition, but your arguments are limited to 2.

Kultur answered 4/6, 2018 at 9:56 Comment(1)
@FuntionalInterface annotation is optional but not mandatory. This can prevent users from adding another abstract method to the interface.Arsyvarsy
S
3

Basically to pass a lamda expression as a parameter, we need a type in which we can hold it. Just as an integer value we hold in primitive int or Integer class. Java doesn't have a separate type for lamda expression instead it uses an interface as the type to hold the argument. But that interface should be a functional interface.

Sholley answered 10/5, 2019 at 7:32 Comment(0)
W
2

Well, that's easy. The purpose of lambda expression is to implement Functional Interface. It is the interface with only one method. Here is awesone article about predefined and legacy functional interfaces.

Anyway, if you want to implement your own functional interface, make it. Just for simple example:

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

So let's make a class, where we will create a method, which accepts the type of MyFunctionalInterface :

public class Main {

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

    public static void main(String[] args) {

    }
}

The last thing you should do is to pass the implementation of the MyFunctionalInterface to the method we've defined:

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

That's it!

Wellworn answered 20/4, 2018 at 5:46 Comment(0)
R
2

Do the following ..

You have declared method(lambda l) All you want to do is create a Interface with the name lambda and declare one abstract method

public int add(int a,int b);  

method name does not matter here..

So when u call MyClass.method( (a,b)->a+b) This implementation (a,b)->a+b will be injected to your interface add method .So whenever you call l.add it is going to take this implementation and perform addition of a and b and return l.add(2,3) will return 5. - Basically this is what lambda does..

Ribald answered 20/4, 2019 at 8:21 Comment(0)
M
1

Here's roughly how C# handles this problem (but expressed as Java code). Something like this could handle almost all your needs:

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);
    }
}
Mozellamozelle answered 27/1, 2020 at 3:24 Comment(1)
A proper programming language :-D :-D I miss C#Chockfull
A
0

If you're using Java along with Kotlin language (As we do in Android Development) you can pass lambda function without defining any additional interface:

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;
    });
        
}
Aerograph answered 17/8, 2021 at 12:8 Comment(0)
F
0
ToDoubleFunction<DataSource> getValueOf(String methodName) {
    return (DataSource ds) -> {
        try {
            Method method = DataSource.class.getMethod(methodName);
            Integer i = (Integer) method.invoke(ds);
            return Double.valueOf(i);
        } catch (Exception throwables) {
            throwables.printStackTrace();
        }
        return 0;
    };
}
Fick answered 10/8, 2023 at 19:2 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Lipocaic
L
-2

There is flexibility in using lambda as parameter. It enables functional programming in java. The basic syntax is

param -> method_body

Following is a way, you can define a method taking functional interface (lambda is used) as parameter. a. if you wish to define a method declared inside a functional interface, say, the functional interface is given as an argument/parameter to a method called from 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) -> { return 0; };

funcUsesAnonymousOrLambda(fi);

Here above it can be seen, how a lambda expression can be replaced with an interface.

Above explains a particular usage of lambda expression, there are more. ref Java 8 lambda within a lambda can't modify variable from outer lambda

Lapidify answered 13/3, 2017 at 23:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.