Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda expression and equivalent anonymous class

If I have a method that takes a single-method interface as an argument, I can call it like this:

foo(new Bar() {
    @Override
    public String baz(String qux) {
        return modify(qux) + transmogrify(qux);
    }
}

But if I have to call foo millions of times in a tight loop, I might prefer to avoid creating a new instance of the anonymous class every time through the loop:

final Bar bar = new Bar() {
        @Override
        public String baz(String qux) {
            return modify(qux) + transmogrify(qux);
        }
    };

while (...) {
    foo(bar);
}

Now if I replace the anonymous class with a lambda expression:

while (...) {
    foo(qux -> modify(qux) + transmogrify(qux));
}

Is this lambda expression equivalent to the first or second snippet from the above examples of anonymous class?

like image 419
k314159 Avatar asked Sep 29 '20 16:09

k314159


People also ask

Is lambda the same as anonymous function?

In Python, an anonymous function is a function that is defined without a name. While normal functions are defined using the def keyword in Python, anonymous functions are defined using the lambda keyword. Hence, anonymous functions are also called lambda functions.

Does lambda expression eliminates the need of anonymous class?

Lambda expressions are introduced in Java 8. These are used primarily to define inline implementation of a functional interface, i.e., an interface with a single method only. Lambda expression eliminates the need of anonymous class and gives a very simple yet powerful functional programming capability to Java.

Can lambda expressions be used in place of instances of anonymous classes?

By the way, you cannot always use lambda expression in place of Anonymous class, because of its limitation of being SAM type. If you are using an anonymous class to implement an interface with two abstract methods then you cannot replace it with a lambda of Java 8.

Can we use lambda expression for comparable?

The answer to that question is Yes, you can use a lambda expression to implement Comparator and Comparable interface in Java, and not just these two interfaces but to implement any interface, which has only one abstract method because those are known as SAM (Single Abstract Method) Type and lambda expression in Java ...


1 Answers

I think it's more like the second one because there will only be one instance of Bar created by the lambda.

I write a Test class:

public class LambdaTest {
    //create a new runnable for each loop
    void test1(){
        while (true){
            invoke(new Runnable() {
                @Override
                public void run() {
                    System.out.println("---");
                }
            });
        }
    }

    //create only one Runnable
    void test2(){
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                System.out.println("---");
            }
        };
        while (true){
            invoke(runnable);
        }
    }

    //use lambda
    void test3(){
        while (true){
            invoke(()->{
                System.out.println("---");
            });
        }
    }
    private void invoke(Runnable runnable){
    }
}

And here is the bytecode for each method:

test1:
         0: aload_0
         1: new           #2                  // class LambdaTest$1
         4: dup
         5: aload_0
         6: invokespecial #3                  // Method LambdaTest$1."<init>":(LLambdaTest;)V
         9: invokevirtual #4                  // Method invoke:(Ljava/lang/Runnable;)V
        12: goto          0

test2:
         0: new           #5                  // class LambdaTest$2
         3: dup
         4: aload_0
         5: invokespecial #6                  // Method LambdaTest$2."<init>":(LLambdaTest;)V
         8: astore_1
         9: aload_0
        10: aload_1
        11: invokevirtual #4                  // Method invoke:(Ljava/lang/Runnable;)V
        14: goto          9

test3:
         0: aload_0
         1: invokedynamic #7,  0              // InvokeDynamic #0:run:()Ljava/lang/Runnable;
         6: invokevirtual #4                  // Method invoke:(Ljava/lang/Runnable;)V
         9: goto          0

In test1, each loop will crate a new instance of the anonymous class and call init method.
In test2, there will only be one instance of the anonymous class, and has the smallest number of opcode in the loop.
In test3, the only difference between test2 is that there add a invokedynamic before invokevirtual opcode in the loop.

According the this article, invokedynamic will call a bootstrap method to create an instance of the anonymous class for the first time, after that it will use the created instance for the rest of its life.

So my suggestion is: Use lambda when ever you like, don't have to care about the overhead.

like image 154
haoyu wang Avatar answered Sep 20 '22 14:09

haoyu wang