可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Since Java8 has been recently released and its brand new lambda expressions looks to be really cool, I was wondering if this means the demise of the Anonymous classes that we were so used to.
I've been researching a bit about this and found some cool examples about how Lambda expressions will systematically replace those classes, such the Collection's sort method, which used to get an Anonymous instance of Comparator to perform the sort:
Collections.sort(personList, new Comparator<Person>(){ public int compare(Person p1, Person p2){ return p1.firstName.compareTo(p2.firstName); } });
Now can be done using Lambdas:
Collections.sort(personList, (Person p1, Person p2) -> p1.firstName.compareTo(p2.firstName));
And looks surprisingly concise. So my question is, is there any reason to keep using those classes in Java8 instead of Lambdas?
EDIT
Same question but in the opposite direction, what are the benefits of using Lambdas instead of Anonymous classes, since Lambdas can only be used with single method interfaces, is this new feature only a shortcut only used in few cases or is it really useful?
回答1:
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 lexcially enclosing environment. For lambdas, all names are resolved lexically.
回答2:
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));
回答3:
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)
回答4:
Lambda's in java 8 was introduced for functional programming. Where you can avoid boilerplate code. I came across this interesting article on lambda's.
http://radar.oreilly.com/2014/04/whats-new-in-java-8-lambdas.html
It's advisable to use lambda functions for simple logics. If implementing complex logic using lambdas will be a overhead in debugging the code in case of issue.
回答5:
There are following differences:
1) Syntax
Lambda expressions looks neat as compared to Anonymous Inner Class (AIC)
public static void main(String[] args) { Runnable r = new Runnable() { @Override public void run() { System.out.println("in run"); } }; Thread t = new Thread(r); t.start(); } //syntax of lambda expression public static void main(String[] args) { Runnable r = ()->{System.out.println("in run");}; Thread t = new Thread(r); t.start(); }
2)Scope
An anonymous inner class is a class, which means that it has scope for variable defined inside the inner class.
Whereas,lambda expression is not a scope of its own, but is part of the enclosing scope.
Similar rule applies for super and this keyword when using inside anonymous inner class and lambda expression. In case of anonymous inner class this keyword refers to local scope and super keyword refers to the anonymous class’s super class. While in case of lambda expression this keyword refers to the object of the enclosing type and super will refer to the enclosing class’s super class.
//AIC public static void main(String[] args) { final int cnt = 0; Runnable r = new Runnable() { @Override public void run() { int cnt = 5; System.out.println("in run" + cnt); } };