Java8 Lambdas VS Anonymous Classes

Java8 Lambdas vs Anonymous classes

An anonymous inner class (AIC) can be used to create a subclass of an abstract class or a concrete class. An AIC can also provide a concrete implementation of an interface, including the addition of state (fields). An instance of an AIC can be referred to using this in its method bodies, so further methods can be called on it, its state can be mutated over time, etc. None of these apply to lambdas.

I'd guess that the majority of uses of AICs were to provide stateless implementations of single functions and so can be replaced with lambda expressions, but there are other uses of AICs for which lambdas cannot be used. AICs are here to stay.

UPDATE

Another difference between AICs and lambda expressions is that AICs introduce a new scope. That is, names are resolved from the AIC's superclasses and interfaces and can shadow names that occur in the lexically enclosing environment. For lambdas, all names are resolved lexically.

Local variables in Lambdas vs Anonymous inner classes

Those are not equivalent. The first function modifies a variable outside of it's scope, whereas in the second example each time you're invoking h.sing();, the body of that function is being invoked. That means, a variable is instantiated with value 2 every time.

From Anonymous class to lambda expression

Actually lambda expressions aren't "just an abbreviation to implement anonymous classes". The benefit of using lambda expression is that it has direct access to instance of this class (the class from which it was called), while anonymous class don't (it has its own this instance).

In other words, anonymous classes introduce a new scope. so that names
are resolved from their superclasses and interfaces and can shadow
names that occur in the lexically enclosing environment. For lambdas,
all names are resolved lexically.

https://stackoverflow.com/a/22640484
And also

Lambda performance with Anonymous classes

When application is launched each class file must be loaded and
verified.

Anonymous classes are processed by compiler as a new subtype for the
given class or interface, so there will be generated a new class file
for each.

Lambdas are different at bytecode generation, they are more efficient,
used invokedynamic instruction that comes with JDK7.

For Lambdas this instruction is used to delay translate lambda
expression in bytecode untill runtime. (instruction will be invoked
for the first time only)

As result Lambda expression will becomes a static method(created at
runtime). (There is a small difference with stateles and statefull
cases, they are resolved via generated method arguments)

https://stackoverflow.com/a/33874965

For instance:

interface Supplier {
void foo();
}

class A {

private String name;

public void doSome() {
baz(() -> System.out.println(this.name));
}

private void baz(Supplier sup){
sup.foo();
}
}

or

class A {

private String name;

public void doSome() {
baz(new Supplier() {
void foo() {
System.out.println(A.this.name);
}
});
}

private void baz(Supplier sup){
sup.foo();
}
}

I recommend to read this: Java8 Lambdas vs Anonymous classes.

Is lambda in fact an anonymous class?

No, lambdas != anonymous inner classes

Lambdas in Java replace many of the common uses of anonymous inner classes. The result is much more compact, readable, and obvious code.

No, the implementation of lambdas is not based on anonymous inner classes.

For more discussion, see this Question on a sibling site of Stack Overflow.

lambda vs anonymous class

There is nothing wrong with your method references, but the IllegalArgumentException hasn’t been thrown by that subsystem either.

It seems the problem is connected to what eventBus.subscribe does internally. Due to type erasure, there is only one subscribe(EventBusListener) method, not knowing whether you passed in an EventBusListener<NavigationEvent> or EventBusListener<NotificationEvent>.

As the message “Could not resolve payload type” indicates, it tries to find out the actual payload type anyway, which implies using Reflection. This only works for reifiable, i.e. non-generic, types. Your anonymous inner classes are reifiable types, not being generic themselves but having a generic super class/interface which can be inspected via getGenericSuperclass() resp. getGenericInterfaces().

The problem with using method references or lambda expressions in that context, is, that if the interface is generic, the generated runtime class will not be reifiable, i.e. you can’t find out the actual type parameter via Reflection. It’s like if you hay written

eventBus.subscribe(Event::getPayload);

Unless there is an overloaded method allowing you to specify the payload type explicitly, this will not work with lambda expressions or method references.

Depending, how the framework does resolving the type internally, using a reifiable interface might work, e.g.

interface NavigationEventListener extends EventBusListener<NavigationEvent> {}


eventBus.subscribe((NavigationEventListener)Event::getPayload);

of course, this would only pay off if you are going to instantiate more than one listener of such a type, otherwise, you could stay with the anonymous inner class (unless their capturing of the this instance is your issue).

Performance difference between Java 8 lambdas and anonymous inner classes

Oracle has posted a study comparing performance between Lambdas and anonymous classes

See JDK 8: Lambda Performance Study by Sergey Kuksenko, which is 74 slides long.

Summary: slow to warm up but when JIT inlines it worst case just as fast as anonymous class but can be faster.

Lambda expression and equivalent anonymous class

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.



Related Topics



Leave a reply



Submit