Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using method reference instead of multi argument lambda

Tags:

I'm confused about concept behind "Reference to an Instance Method of an Arbitrary Object of a Particular Type". Oracle documentation has an example about this:

String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);

Most of the examples I have seen for this kind of method reference is like this: If lambda is like: x -> x.func() then you can write it like ClassOfX::func. The example in documentation says:

The equivalent lambda expression for the method reference String::compareToIgnoreCase would have the formal parameter list (String a, String b), where a and b are arbitrary names used to better describe this example. The method reference would invoke the method a.compareToIgnoreCase(b).

The question is: for any two argument lambda like (a, b) -> a.func(b) the func method must be instance method of first argument and second argument of lambda will be passed as an argument to that method? If we have multiple argument lambda then func method must be instance method of first argument of lambda and other arguments of lambda will be passed to func in the order the appear in lambda? I mean instead of (a, b, c) -> a.func(b, c) we can write ClassOfA::func

I'm sorry for my English. I hope I made the problem clear.

like image 255
Majid Azimi Avatar asked Apr 17 '14 17:04

Majid Azimi


People also ask

Can we replace lambda expression with method reference?

If you are using a lambda expression as an anonymous function but not doing anything with the argument passed, you can replace lambda expression with method reference. In the first two cases, the method reference is equivalent to lambda expression that supplies the parameters of the method e.g. System.

Can we pass arguments in method reference?

Notice that between a static method and a static method reference, instead of the . operator, we use the :: operator, and that we don't pass arguments to the method reference. In general, we don't have to pass arguments to method references. However, arguments are treated depending on the type of method reference.

What is difference between lambda expression and method reference in Java?

Lambda expression is an anonymous method (method without a name) that has used to provide the inline implementation of a method defined by the functional interface while a method reference is similar to a lambda expression that refers a method without executing it.

What are we using lambdas and method reference for?

You use lambda expressions to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method. In those cases, it's often clearer to refer to the existing method by name.


2 Answers

SomeClass::func can mean two things, depending on whether func is a static method or an instance method.

(1) If func is a static method, then SomeClass::func is a lambda that just passes all the arguments to the method:

(a, b, c) -> SomeClass.func(a, b, c);

(2) If func is an instance method, then SomeClass::func is a lambda that uses the first argument as the instance, as you thought:

(a, b, c) -> a.func(b, c);

where a has type SomeClass.

EDIT: Sotirios' answer demonstrates yet a different type of method reference: example::method where example is a reference variable (instead of a class name). This means the same as

(a, b) -> example.method(a, b);

or perhaps more accurately

(a, b) -> __someFinalTemporary.method(a, b);

where __someFinalTemporary is assigned to example at the point where the method reference is evaluated, so that if example changes later, the method is still called using the earlier value of example.

[The fourth kind is SomeClass::new which passes the arguments to a constructor. I think that's all of them.]

like image 64
ajb Avatar answered Oct 01 '22 11:10

ajb


Here's a small example demonstrating the behavior of an instance method reference.

public class Example {  
    public static void main(String[] args) throws Exception {
        List<String> strings = new ArrayList<String>();
        Example example = new Example();
        Functional methodRef = example::method;
        methodRef.funct("a string", strings);
        System.out.println("List now contains: " + strings);

        Functional lambda = (String s, List<String> l) -> {
            example.method(s, l);
        };
        lambda.funct("another string", strings);
        System.out.println("List now contains: " + strings);
    }

    interface Functional {
        void funct(String value, List<String> list);
    }

    void method(String value, List<String> toAddTo) {
        System.out.println("adding");
        toAddTo.add(value);
    }
}

It prints

adding
List now contains: [a string]
adding
List now contains: [a string, another string]

The two are more or less equivalent. In the lambda's case, the variable the method is invoked on needs to be effectively final.

like image 30
Sotirios Delimanolis Avatar answered Oct 01 '22 11:10

Sotirios Delimanolis