Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Functional interface initialize different when use lambda in factory-method and method reference (singleton / prototype)?

I have two factory-methods which produce "consumers" use different approaches 👉🏻 lambda and method references:

@SuppressWarnings("Convert2MethodRef")
public Consumer<String> lambdaPrintStringConsumer(){
    return x -> System.out.println(x);
}

public Consumer<String> methodRefPrintStringConsumer(){
    return System.out::println;
}

I found that in first case (lambdaPrintStringConsumer()), method return reference to the same object

@Test
public void shouldSameFromFactoryMethod_lambda() {
    Consumer<String> consumerA = lambdaPrintStringConsumer();
    Consumer<String> consumerB = lambdaPrintStringConsumer();
    
    Assert.assertSame(consumerA, consumerB);//consumerA == consumerB --> true
}

but in the second (methodRefPrintStringConsumer()), objects is different

@Test
public void shouldNotSameFromFactoryMethod_methodRef() {
    Consumer<String> consumerA = methodRefPrintStringConsumer();
    Consumer<String> consumerB = methodRefPrintStringConsumer();

    Assert.assertNotSame(consumerA, consumerB);//consumerA == consumerB --> false
}

direct approach return the same result as shouldNotSameFromFactoryMethod_methodRef():

@SuppressWarnings("Convert2MethodRef")
@Test
public void shouldNotSameFromLambda() {
    Consumer<String> consumerA = s -> System.out.println(s);
    Consumer<String> consumerB = s -> System.out.println(s);

    Assert.assertNotSame(consumerA, consumerB);//consumerA == consumerB --> false
}

, next I tested factory-method with method reference to other static method

public class FunctionalInterfaceTest {

    public static Consumer<String> methodRefFromStaticMethodStringConsumer() {
        return FunctionalInterfaceTest::print;
    }

    public static void print(String string) {
        System.out.println(string);
    }

    ...

}

and get the same result as in the first test (lambdaPrintStringConsumer):

@Test
public void shouldSameFromFactoryMethod_methodRef() {
    Consumer<String> consumerA = methodRefFromStaticMethodStringConsumer();
    Consumer<String> consumerB = methodRefFromStaticMethodStringConsumer();

    Assert.assertSame(consumerA, consumerB );//consumerA == consumerB --> true
}

What is the trick

In Tests 👉🏻 jdk-11.0.1 and jdk-13.0.1.

like image 971
kozmo Avatar asked Nov 18 '19 17:11

kozmo


People also ask

What is difference between functional interface and lambda expression?

A lambda expression (lambda) is a short-form replacement for an anonymous class. Lambdas simplify the use of interfaces that declare single abstract methods. Such interfaces are known as functional interfaces. A functional interface can define as many default and static methods as it requires.

Why are lambda expressions used for only functional interfaces?

Because the lambda expression provides a body to only a single abstract method.

Can lambda expressions be used to implement interfaces having default and static methods?

You can define a lambda expression that would represent an A instance regardless of the context you are in. It can be a static interface method, it could be a default interface method.


1 Answers

Are the following expressions equivalent?

x -> System.out.println(x)

System.out::println

No. If you call System.setOut, the former will pick up the new PrintStream; the latter will not.

So, in this case, the lambda method does not require access to variables from the enclosing lexical scope, whereas this method reference expression does. This allow the former to be shared but the latter cannot.

The exact details may or may not be specified - I can't be bothered to look.

like image 129
Tom Hawtin - tackline Avatar answered Oct 11 '22 14:10

Tom Hawtin - tackline