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.
Answer from Stuart Marks on Stack OverflowAn 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.
Lambdas though a great feature, will only work with SAM types. That is, interfaces with only a single abstract method. It would fail as soon as your interface contains more than 1 abstract method. That is where anonymous classes will be useful.
So, no we cannot just ignore anonymous classes. And just FYI, your sort() method can be more simplified, by skipping the type declaration for p1 and p2:
Collections.sort(personList, (p1, p2) -> p1.firstName.compareTo(p2.firstName));
You can also use method reference here. Either you add a compareByFirstName() method in Person class, and use:
Collections.sort(personList, Person::compareByFirstName);
or, add a getter for firstName, directly get the Comparator from Comparator.comparing() method:
Collections.sort(personList, Comparator.comparing(Person::getFirstName));
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.
As I found, the iterating over array with Stream is working much slower (74 slides are not consider such the case). I think that it is not the only performance leaks in lambdas (guess, it will be improved in the future). The example below was running with Java 8 without any options:
//Language is an enum
Language[] array = Language.values();
System.err.println(array.length); // 72 items
long t = System.nanoTime();
for (Language l : array) System.out.println(l.getLanguageName());
System.err.println(System.nanoTime()-t); //nano time 1864724
t = System.nanoTime();
Arrays.stream(array).forEach(v -> System.out.println(v.getLanguageName()));
System.err.println(System.nanoTime()-t); //nano time 55812625 (55812625/1864724 = 29.93 times longer)
List<Language> list = Arrays.asList(array);
t = System.nanoTime();
for (Language l : list) System.out.println(l.getLanguageName());
System.err.println(System.nanoTime()-t); //nano time 1435008
t = System.nanoTime();
list.forEach(v -> System.out.println(v.getLanguageName()));
System.err.println(System.nanoTime()-t); //nano time 1619973 (1619973/1435008 = 1.128 times longer)
performance - Big execution time difference between java Lambda vs Anonymous class - Stack Overflow
java - Lambda vs anonymous inner class performance: reducing the load on the ClassLoader? - Stack Overflow
algorithm - Java lambdas 20 times slower than anonymous classes - Stack Overflow
performance - Are there plans to make lambda expressions in Java more performant than anonymous classes? - Stack Overflow
Are lambdas always better than anonymous classes?
Are method references better than lambdas?
Do lambdas support recursion?
Oracle has a presentation covering some of the performance differences. It appears that there are quite a few factors that impact performance of lambdas vs. anonymous classes.
http://www.oracle.com/technetwork/java/jvmls2013kuksen-2014088.pdf
After reading the PDF linked from @Brett Okken I believe the following holds:
- Inner classes have a slightly slower performance on first use, but it seems negliable.
- Lambdas have a slower performance when called often because of the bigger stack they build up when called.
I will stick with the following:
- Use Lambdas for readability when a few milliseconds performance loss is not a problem (GUI stuff, etc.)
- Use inner classes for often called, performance critical functions.
In many scenarios, I think lambda and method-reference is equivalent. But the lambda will wrap the invocation target by the declaring interface type.
For example
public class InvokeTest {
private static void invoke(final Runnable r) {
r.run();
}
private static void target() {
new Exception().printStackTrace();
}
@Test
public void lambda() throws Exception {
invoke(() -> target());
}
@Test
public void methodReference() throws Exception {
invoke(InvokeTest::target);
}
}
You will see the console output the stacktrace.
In lambda(), the method calling target() is lambda$lambda$0(InvokeTest.java:20), which has traceable line info. Obviously, that is the lambda you write, the compiler generates an anonymous method for you. And then, the caller of the of the lambda method is something like InvokeTest$$Lambda$2/1617791695.run(Unknown Source), that is the invokedynamic call in JVM, it means the call is linked to the generated method.
In methodReference(), the method calling target() is directly the InvokeTest$$Lambda$1/758529971.run(Unknown Source), it means the call is directly linked to the InvokeTest::target method.
Conclusion
Above all, compare to method-reference, using lambda expression will only cause one more method call to the generating method from lambda.
It's all about the metafactory
First, most method references do not need desugaring by the lambda metafactory, they are simply used as the reference method. Under the section "Lambda body sugaring" of the Translation of Lambda Expressions ("TLE") article:
All things being equal, private methods are preferable to nonprivate, static methods preferable to instance methods, it is best if lambda bodies are desugared into in the innermost class in which the lambda expression appears, signatures should match the body signature of the lambda, extra arguments should be prepended on the front of the argument list for captured values, and would not desugar method references at all. However, there are exception cases where we may have to deviate from this baseline strategy.
This is further highlighted further down in TLE's "The Lambda Metafactory":
metaFactory(MethodHandles.Lookup caller, // provided by VM String invokedName, // provided by VM MethodType invokedType, // provided by VM MethodHandle descriptor, // lambda descriptor MethodHandle impl) // lambda bodyThe
implargument identifies the lambda method, either a desugared lambda body or the method named in a method reference.
A static (Integer::sum) or unbounded instance method (Integer::intValue) references are the 'simplest' or the most 'convenient', in the sense that they can be optimally handled by a 'fast-path' metafactory variant without the desugaring. This advantage is helpfully pointed out in TLE's "Metafactory variants":
By eliminating arguments where they are not needed, classfiles become smaller. And the fast path option lowers the bar for the VM to intrinsify the lambda conversion operation, enabling it to be treated as a "boxing" operation and faciliating unbox optimizations.
Naturally, an instance-capturing method reference (obj::myMethod) needs to provide the bounded instance as an argument to the method handle for invocation, which may mean the need of desugaring using 'bridge' methods.
Conclusion
I'm not exactly sure what is the lambda 'wrapper' you are hinting at, but even though the ultimate result of using your user-defined lambdas or method references are the same, the way that is reached seems to be quite different, and can be different in the future if that's not the case now. Hence, I suppose it's more likely than not that method references can be handled in a more optimal way by the metafactory.