(摘自https://www.oracle.com/technetwork/articles/java/architect-lambdas-part1-2080972.html)
1.Type inference.
One of the features that some other languages have been touting is the idea of type inference: that the compiler should be smart enough to figure out what the type parameters should be, rather than forcing the developer to retype the parameters.
If the target type is a Comparator, the objects passed in to the lambda must be strings (or some subtype); otherwise, the code wouldn’t compile in the first place. (This isn’t new, by the way—this is “Inheritance 101.”)
In this case, then, the String declarations in front of the lhs and rhs parameters are entirely redundant and, thanks to Java 8’s enhanced type inference features, they are entirely optional
Example:
public static void main(String... args) {
Comparator<String> c =
(lhs, rhs) ->
{
System.out.println("I am comparing" +
lhs + " to " + rhs);
return lhs.compareTo(rhs);
};
int result = c.compare("Hello", "World");
}
The language specification will have precise rules as to when explicit lambda formal type declarations are needed, but for the most part, it’s proving to be the default, rather than the exception, that the parameter type declarations for a lambda expression can be left out completely.
One interesting side effect of Java’s lambda syntax is that for the first time in Java’s history, we find something that cannot be assigned to a reference of type Object—at least not without some help.
public static void main4(String... args) {
Object o = () -> System.out.println("Howdy, world!");
// will not compile
}
The compiler will complain that Object is not a functional interface, though the real problem is that the compiler can’t quite figure out which functional interface this lambda should implement: Runnable or something else? We can help the compiler with, as always, a cast.
public static void main4(String... args) {
Object o = (Runnable) () -> System.out.println("Howdy, world!");
// now we're all good
}
Recall from earlier that lambda syntax works with any interface, so a lambda that is inferred to a custom interface will also be inferred just as easily, as shown in Listing 9. Primitive types are equally as viable as their wrapper types in a lambda type signature, by the way
2.Lexical scoping
Lambdas, however, are lexically scoped, meaning that a lambda recognizes the immediate environment around its definition as the next outermost scope. So the lambda example in Listing 12 produces the same results as the second Hello nested class example in Listing 11 , but with a much more intuitive syntax
listing 10
class Hello {
public Runnable r = new Runnable() {
public void run() {
System.out.println(this);
System.out.println(toString());
}
};
public String toString() {
return "Hello's custom toString()";
}
}
public class InnerClassExamples {
public static void main(String... args) {
Hello h = new Hello();
h.r.run();
}
}
匿名内部类写法(listing 11):
class Hello {
public Runnable r = new Runnable() {
public void run() {
System.out.println(Hello.this);
System.out.println(Hello.this.toString());
}
};
public String toString() {
return "Hello's custom toString()";
}
}
lambdas写法(listing 12):
class Hello {
public Runnable r = () -> {
System.out.println(this);
System.out.println(toString());
};
public String toString() {
return "Hello's custom toString()";
}
}