Search

Java 8 Lambda expression vs Method reference. How different are they?

Before I begin to talk about what we I am going to share here, I want to give a heads up to my plans about the blog here.

I want to write a small blog every few days or so,I will be writing something about what I learned during those times.

This is a step to try and make it a habit.

I want to check how consistent I can be in writing a blog about something which hopefully I have learned in that period. If that period was so boring or too hectic that I didn't learn anything new/interesting, I plan to write something that I might not have written about but I have learnt about it sometime in the past. Hopefully this will reach a few people and inspire some of you to start writing too...

Enough of the boring stuff, lets get into it. If you are new to Java and the method reference and lambda stuff, I suggest you start with Maurice Naftalin's blog


If you think Lambda expression is just calling one more method compared to Method reference, think again. :) May be the below piece of code will help you understand that there is something more to it than just another method call

I came across the following piece of code shared by Mr.Joshua Bloch, the author of Effective Java, which is one of the best books on Java. you should get it if you haven't already. The explanation I have mentioned here is based on one of the replies to his question which I felt best represented the answer. I too was not so convinced but after digging through the bits in that explanation I feel like I have got to the bottom of it. So lets get to it,



class MethodReference {
    static AtomicLong incremental = new AtomicLong();

    static {
        Thread t = new Thread(incremental::getAndIncrement);
        t.start();
        try {
            t.join();
        } catch (Exception e) {
        }
    }

    public static void main(String[] a) {
        System.out.print(incremental.get());
    }
}

Can you identify what happens when you run this code? If yes very good else lets see what happens, but before that lets see another piece of code given below, If you can't spot the difference, A small change has been made in the creation of the Thread object t, that is,


 Thread t = new Thread(incremental::getAndIncrement);

has been changed to


 Thread t = new Thread(() -> i.getAndIncrement());

As you can see below,

class LambdaExpression {
    static AtomicLong incremental = new AtomicLong();

    static {
        Thread t = new Thread(() -> incremental.getAndIncrement());
        t.start();
        try {
            t.join();
        } catch (Exception e) {
        }
    }

    public static void main(String[] a) {
        System.out.print(incremental.get());
    }
}

When we run the two classes, one of them prints 1 and the other one actually goes into a deadlock.

So which one does what? and why? these are the questions we will try to answer.


The class MethodReference.java will run successfully and print 1. and the class LambdaExpression.java will enter a deadlock. Where do you think this deadlock will happen? How or why does it happen? To know that lets take a look how differently are they interpreted by the JVM while running the application.


Before reading below to understand why they behave differently, They both have something in common and that is how and when is a class marked as initialised by the JVM, in our specific case we have a static block and a static variable.

So lets take a look at JLS(Java language Specification) to understand this behaviour.


In the JLS12.4.2 it says on point 9 that,


Next execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.


And on point 10 it says that ,


If the execution of the initializers completes normally, then acquire LC, label the Class object for C as fully initialized, notify all waiting threads, release LC, and complete this procedure normally.


From the above two statements from JLS it is clear that the initialization is not complete until the whole static block is initialized. and any value that is being initialised in step 9 will be released by the initialising thread only when the static variable and the static blocks have been initialised.

That was about class loading which is same for both Method references and lambda expressions. Now let see how different are they when the class is initialized.


In case of lambda expression, lets see how it is,


This is similar to a class instance creation expression as given in JLS. So, since that expression needs the variable LambdaExpression.incremental to instantiate the lambda body, it will have to wait till it gets the lock for that object.

As we saw a bit earlier about the time when the lock LC on class is released, it happens only when all initializations are completed and its only after that the lambda thread will get the lock on the object and is this going to happen?

The answer is NO, simply because its a classic deadlock situation when one thread waits for the other. The main thread initializing the static block is waiting for the other thread to join on the main thread which is never going to happen.


So now that is clear, lets take a look at why the method reference class does not have a deadlock.


In case of MethodReference lets see how is the runtime execution done,

Lets start by taking a look at how method references are evaluated at runtime. The statement given in JLS is,

The target reference is the value of ExpressionName or Primary, as determined when the method reference expression was evaluated.

what this means is, say in our example above, incremental::getAndIncrement is our lambda, and when the new Thread is created with the Runnable, it will have a reference to the incremental variable declared, this happens when the method reference lambda is created and the method reference expression evaluation will use this object reference when evaluating the method reference.


I did learn a lot of things when I went through this. I hope I was able to share something worth knowing with you too.



Nithin

10 views0 comments

Recent Posts

See All

Who am I and What this site is all about??

As you probably know by know, if you have read the name of the author, my name is Nithin, I am a software engineer working in Kerala, Southern part of India, I currently have more than 6 and a half ye

 

©2020 by AllInTech