http://blog.csdn.net/zxhoo/article/details/38349011
Function-Type interface
Understanding the functional Interface (functional interface, FI) is the key to learning Java8 lambda expressions, so put it at the very beginning of the discussion. The definition of fi is very simple: any interface, if it contains only one abstract method, then it is a fi. In order for the compiler to help us ensure that an interface satisfies the requirements of fi (that is, there is only one abstract method), JAVA8 provides @functionalinterface annotations. To give a simple example, the Runnable interface is a fi, and here is its source code:
[Java]View PlainCopy
- @FunctionalInterface
- Public interface Runnable {
- public abstract Void run ();
- }
Lambda syntax sugar
In order to create an instance of fi in a convenient, fast and elegant way, JAVA8 provides a lambda expression, the syntactic sugar. Here I use an example to introduce the lambda syntax. Suppose we want to sort a list<string> by the length of a string, then the anonymous inner class can be implemented before JAVA8:
[Java]View PlainCopy
- list<string> words = arrays.aslist ("Apple", "banana", "pear");
- Words.sort (new comparator<string> () {
- @Override
- public int Compare (string w1, String w2) {
- return Integer.compare (W1.length (), w2.length ());
- }
- });
The anonymous inner class above can be described as ugly, the only line of logic is drowned in the five-piece garbage code. Based on the previous definition (and looking at the Java source code), comparator is a fi, so it can be implemented with lambda expressions:
[Java]View PlainCopy
- Words.sort (String w1, String w2), {
- return Integer.compare (W1.length (), w2.length ());
- });
The code shortened a lot! A closer look will reveal that the lambda expression is much like an anonymous method, except that the argument list inside the parentheses and the code inside the curly braces are separated. The less garbage code is written, the more time we have to write real logic code, right? Yes! The type of argument in parentheses can be omitted:
[Java]View PlainCopy
- Words.sort ((W1, W2), {
- return Integer.compare (W1.length (), w2.length ());
- });
If the code block of a lambda expression is just a return followed by an expression, it can be further simplified:
[Java]View PlainCopy
- Words.sort (
- (W1, W2), Integer.compare (W1.length (), W2.length ())
- );
Note that there is no semicolon after the expression! If there is only one parameter, then the parentheses enclosing the parameter can be omitted:
[Java]View PlainCopy
- Words.foreach (Word, {
- SYSTEM.OUT.PRINTLN (word);
- });
What if an expression does not require arguments? Well, that must also have parentheses, for example:
[Java]View PlainCopy
- Executors.newsinglethreadexecutor (). Execute (
- (), {/* do something. * /}//Runnable
- );
Method reference
Sometimes the code for a lambda expression is just a simple method call, and in this case, the lambda expression can be further simplified as a method References. There are four forms of method references, the first of which refers to static methods , such as:
[Java]View PlainCopy
- list<integer> ints = arrays.aslist (1, 2, 3);
- Ints.sort (Integer::compare);
The second way to refer to an instance of a particular object , such as the previous one that iterates through and prints each word, can be written like this:
[Java]View PlainCopy
- Words.foreach (System.out::p rintln);
The third type of instance method that references a class , for example:
[Java]View PlainCopy
- Words.stream (). Map (Word, word.length ()); //Lambda
- Words.stream (). Map (String::length); //Method reference
The fourth kind of constructor that references a class, for example:
[Java]View PlainCopy
- Lambda
- Words.stream (). Map (Word, {
- return new StringBuilder (word);
- });
- Constructor reference
- Words.stream (). Map (StringBuilder::new);
When to use lambda expressions
Since lambda expressions are so useful, where can they be used? If you really understand what fi is (it's easy), you should be able to answer it right away: any place where you can accept an instance of FI, you can use a lambda expression. For example, although the example given above is passing a lambda expression as a method parameter, you can actually define the variable as well:
[Java]View PlainCopy
- Runnable task = (), {
- //Do something
- };
- Comparator<string> cmp = (S1, s2), {
- return Integer.compare (S1.length (), s2.length ());
- };
Pre-defined functional interfaces
Java8 in addition to Runnable,comparator and other interfaces on the @functionalinterface annotation, but also pre-defined a large number of new fi. These interfaces are in the Java.util.function package, the following is a brief introduction to several of them.
[Java]View PlainCopy
- @FunctionalInterface
- Public interface Predicate<t> {
- Boolean test (T T);
- }
predicate is used to determine whether an object satisfies a certain condition, such as whether the word consists of more than six letters:
[Java]View PlainCopy
- Words.stream ()
- . Filter (Word, word.length () > 6)
- . Count ();
A function that represents an argument that receives a parameter and produces a result:
[Java]View PlainCopy
- @FunctionalInterface
- Public Interface Function<t, r> {
- R apply (t T);
- }
The following example multiplies each integer in the collection by 2:
[Java]View PlainCopy
- Ints.stream (). Map (x-X * 2);
Consumer represents an operation on a single parameter, which is the parameter received by the foreach () method in the preceding example:
[Java]View PlainCopy
- @FunctionalInterface
- Public interface Consumer<t> {
- void Accept (T t);
- }
Enhancements to Legacy APIs
To give full play to the power of lambda, JAVA8 has enhanced many of the old class libraries and equipped them with lambda weapons. For example, the foreach () method used in the previous example is actually added to the Iterable interface. The stream () method, which appears multiple times, is added to the collection interface. Java programmers who have used languages such as Ruby,scala,groovy may have long coveted external iterator patterns that are well implemented in these languages. While Google's guava can compensate for Java's flaws in some way, Java8 's lambda really makes Java a big step towards functional programming.
Default methods for interfaces
The attentive reader may find a problem, adding methods to interfaces such as iterable and collection, would it not break the interface backwards compatibility? Yes, in order to ensure the backward compatibility of the API, JAVA8 has made a large adjustment to the syntax of the interface, adding the default method, which is Methods. The following is the implementation code for the foreach () method:
[Java]View PlainCopy
- Public interface Iterable<t> {
- ...
- default void ForEach (consumer<? Super t> Action) {
- Objects.requirenonnull (action);
- For (T T: this ) {
- Action.accept (t);
- }
- }
- ...
- }
static methods for interfaces
In addition to the abstract method and the default method, the interface can have static methods, starting with Java8. With this syntax, we can define interface-related helper methods (helper Methods) directly in the interface. For example, a function interface defines a factory method indentity ():
[Java]View PlainCopy
- Public Interface Function<t, r> {
- ...
- /**
- * Returns a function that all Returns its input argument.
- *
- * @param <T> The type of the input and output objects to the function
- * @return A function that all returns its input argument
- */
- static <T> function<t, t> identity () {
- return T-t;
- }
- ...
- }
Variable capture
Like inner classes, lambda can also access external (lexical scope) variables, which are basically the same rules. Before Java8, the inner class could only access variables of the final type, Java8 relaxed the limit, as long as the variable was actually immutable (effectively final). In other words, if you add the final keyword compiler to the variable without an error, then when you remove the final keyword, it is effectively final. Look at the following example:
[Java]View PlainCopy
- int a = 100;
- Runnable x = new Runnable () {
- @Override
- public Void Run () {
- System.out.println (a);
- }
- };
Before Java8, a must be final in order to be seen by X. The following example is rewritten with a lambda expression:
[Java]View PlainCopy
- int a = 100;
- Runnable x = (), {
- System.out.println (a);
- };
Conclusion
As you can see, JAVA8 has made great adjustments to the Java language in order to support lambda expressions. But the lambda expression is not just Java syntax sugar, but is implemented by the compiler and the JVM together, which I'll cover in the next article.
"Turn" JAVA8 study notes (1)--from the functional interface