Reprint please indicate the source:
http://blog.csdn.net/xmxkf/article/details/51532028
This article is from: "Openxu's Blog"
Directory:
- Why use a lambda expression
- Let Android Stutio support Lambda
- Function-type interface functional interfaces
- The target type of the lambda expression and the matching
- Lambda expression syntax
- 1 basic syntax and syntax simplification
- 2 lexical scope of a lambda expression
- 3 variable Capture
?? One of the big highlights of Java 8 is the introduction Lambda
of expressions, which are more concise, a functional derivation language that can greatly reduce the redundancy of anonymous internal classes of code. In Android development, we often use a large number of listening settings and asynchronous callbacks and other scenarios. Like what:
textView.setOnClickListener(new View.OnClickListener(){ @Override publicvoidonClick(View v) { "hello Lambda", Toast.LENGTH_LONG).show(); }});
?? This writing is the most common before, a simple listening event, it takes so many lines of code to get it done, and {nested {, looks very bloated. The biggest problem with anonymous types is its redundant syntax, which is called "Height problem" by anonymous types: for example, in the previous Onclicklistener example, only one line in the five lines is actually working. A lambda expression is an anonymous method that provides a lightweight syntax that resolves the "height problem" of anonymous inner classes. Using lambda syntax instead of anonymous internal classes, the code is not only concise, but also highly readable:
textView.setOnClickListener( v -> Toast.makeText"Lambda", Toast.LENGTH_LONG).show());
1. Why use lambda expressions
With the increasing popularity of callback patterns and functional programming styles, we need to provide in Java a way to encapsulate the code as data (Model code as) as lightweight as possible. Anonymous internal classes are not a good choice because:
- Syntax too redundant
- This and variable names in anonymous classes are easy to misunderstand
- Type loading and instance creation semantics are not flexible
- Unable to capture non-final local variables
- Unable to abstract control flow
Most of the above issues are resolved in Java SE 8:
- By providing more concise syntax and local scope rules, Java SE 8 completely solves issue 1 and issue 2
- By providing more flexible and easy-to-optimize expression semantics, Java SE 8 bypassed the issue 3
- By allowing the compiler to infer the "constant" (finality) of a variable, the Java SE 8 mitigates the problem of 4
2. Let Android Stutio support Lambda
?? Currently Android development tools have migrated from Eclipse's ADT to Android studio, but Android studio does not currently support lambda directly, requires plug-in support, and, of course, JDK version must use JDK 8 or above. Follow the steps below to configure Gradle:
(1). Introducing the Retrolambda plugin:
?? Add in Build.gradle of Module:app
‘com.android.application‘‘me.tatarka.retrolambda‘ //添加此句
(2). Set the Java version
?? Add the following code to the Module:app build.gradle android node
android { 21 "21.1.2" ... //设置java版本 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 }}
(3). Introducing the classpath of the RETROLAMBDA
?? Add the following code to the Buildscript->dependencies node in Project Build.gradle
buildscript { repositories { jcenter() //添加 } dependencies { ‘com.android.tools.build:gradle:2.1.0‘ ‘me.tatarka:gradle-retrolambda:3.2.5‘ //添加 }}//添加// Required because retrolambda is on maven centralrepositories { mavenCentral()}
(4). Build the Build.gradle
(5). Copy the following code to the activity to run
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView = (TextView)findViewById(R.id.textview); textView.setOnClickListener(v -> Toast.makeText"Lambda", Toast.LENGTH_LONG).show());}
With the configuration above, the Android Stutio will be able to use lambda syntax, and we'll learn more about lambda in the following context.
3. Function-type interface (functional interfaces)
?? The next step is to take a look at the lambda expression, but before we speak the lambda syntax, we need to know what the Lambda looks like: (parameter list), {function Body};
?? At the beginning of the article, we used the Onclicklistener listener interface to experience lambda expressions, and some of the students might be thinking, if you have a lambda expression, is not all the interface can be used in such a concise way? such as the following:
EditText EditText = (EditText) Findviewbyid (R.id.edittext); Edittext.addtextchangedlistener (NewTextwatcher () {@Override Public void beforetextchanged(Charsequence S,intStartintCountintAfter) {}@Override Public void ontextchanged(Charsequence S,intStartintBefore,intCount) {}@Override Public void aftertextchanged(Editable s) { }});
?? Textwatcher can this interface use lambda syntax? The answer is no, not all interfaces can use lambda syntax, and if you want to use lambda syntax, this interface must conform to the specification and it must be a "functional interface." What is a functional interface?
?? A functional interface is a type that can be used as a parameter by a class function, and a lambda expression supports providing such an argument. A very abstruse look, for a popular chestnut, we set the click to listen is to execute a piece of code after the button is clicked, according to the common People's thought, the code should write (pseudo code):
button.set点击监听({点击后需要执行的代码});
We should pass {The code that needs to execute after click} directly as a parameter, of course, in order to embody the encapsulation characteristics, we need to encapsulate this block of code into a method:
button.set点击监听(onClick()); onClick(){ 点击后需要执行的代码; }
?? We know that Java is an object-oriented programming language that does not support methods being passed in as parameters, so it must be encapsulated with an interface, which is Onclicklistener, our traditional anonymous class approach. The lambda expression, on the surface, is like passing a piece of code directly as a method parameter (essentially an anonymous method), more like a function-oriented programming language, and in order to be able to use such concise programming, it must be defined as a rule, which is why the "functional interface" appears, it is the rule , the interface must follow this rule in order to use lambda expressions.
What kind of conditions does the functional interface need to meet?
?? An interface, if there is only one explicitly declared abstract method (which can have other non-abstract methods), then it is a function interface (formerly known as the Sam type, which is the single abstract method type). Functional interfaces are generally labeled with @functionalinterface (or not).
?? How can a non-abstract method be allowed for a horizontal slot? Isn't that an abstract class? But interfaces in Jdk8 can have non-abstract methods, which are modified by default, Jdk8 adds a number of functional interfaces to the Java.util.function package, all of which have only one abstract method, but there are several implementations of the default adornments, which have a @functionalinterface annotation on them. Indicates that this is a functional interface, with this annotation, the compiler verifies that the interface meets the requirements of the functional interface. If an interface with @functionalinterface annotations defines two abstract methods that report syntax errors, this is also a way to detect a functional interface. For example, the new functional interface in the function pack below:
/** * Functional interface * @since 1.8 */@FunctionalInterfacePublic interface Function<t, r> {/** * Abstract method * /R apply (t T);default<V> Function<v, r> compose (function<?SuperV?extendsT> before) {objects.requirenonnull (before);return(v V), apply (Before.apply (v)); }default<V> function<t, v> andthen (function<?SuperR?extendsV> after) {objects.requirenonnull (after);return(T T)-after.apply (apply (t)); } static <T> Function<t, t> identity () {returnT-t; }}
Default methods and Static interface methods:
?? The Java SE 7 era is very difficult to add functionality to an existing class library. Specifically, the interface has been trained after it has been published, unless we can update all implementations of the interface at once, otherwise adding a method to the interface will break the existing interface implementation. The goal of the default method (formerly known as the virtual extension method or daemon) is to solve this problem, so that the interface can evolve gradually after it is published.
?? The default method uses an object-oriented approach to add new behavior to the interface. It is a new method: The interface method can be either abstract or default. The default method has its default implementation, and the type that implements the interface is inherited by the default implementation (if the type does not override the default implementation). In addition, the default method is not an abstract method, so we can safely add the default method to the functional interface without worrying about the single abstract method limitation of the functional interface.
?? In addition to the default method, Java SE 8 also allows the definition of static methods in the interface. This allows us to call directly from the interface and its associated helper methods (helper method), rather than from other classes (previously such classes tend to be named after the complex number of the corresponding interface, such as collections). For example, we typically need to use a static helper method to generate a comparator that implements comparator, and in Java SE 8 we can define the static method directly in the comparator interface:
publicstaticsuper U>> comparing(Function<T, U> keyExtractor) { return (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));}
?? About the functional interface, interested students can get to know the Java.util.function the interface in this package; I won't say much. The key thing to remember is that lambda expressions only apply to "functional interfaces" with only one abstract method. This is why Textwatcher cannot use lambda expressions (there are 3 abstract methods).
4. The target type of the lambda expression and the matching
?? We can think of a lambda expression as an object, but it has its own type name called "Target Type". The target type of the lambda expression is the function interface (functional interface), and we cannot assign the lambda expression directly to object, and a lambda expression can be used as object only after it has been transformed into a function interface. Like what:
//A lambda expression can be used to assign a value to a function interface runnable R1 = () {System.out.println ("Hello lambda!");};//Then assign a value to a objectobject obj1 = r1;//You can't do this, error!. Object is notA functional interface! Object Obj2 = () {System.out.println ("Hello lambda!");};//Must be explicitly transformed into a function interface in order to be an object obj3 = (Runnable) () {System.out.println ("Hello lambda!"); };//A lambda expression can be used as an object only after it has been transformed into a function interface, so the following sentence cannot be compiled System.out.println ((), {});//Error! The target type is ambiguous, theprintln method can accept any type of argument, and () {} can match many function interfaces//Must first transform System.out.println( (Runnable) (), {});//Correct
?? A lambda expression can have more than one target type (functional interface), and as long as the function matches successfully, the Java compiler automatically infers the corresponding function interface according to the context. However, a lambda expression must have at least one target type, or it is a syntax error. Chestnuts:
If there is another function interface in the SDK that is the same as Onclicklistener, but the interface name is different:
publicinterface MyOnClickListener { void onClick(View v);}
The following code is also correct, when compiling the Setonclicklistener method is found to accept the Onclicklistener type, and v -> Log.v(TAG, "Lambda”)
exactly the onClick(View v)
method, So the Java compiler will automatically match it to the Onclicklistener function interface, not myonclicklistener.
findViewById(R.id.textView).setOnClickListener( v -> Log.v"Lambda"));
5. Lambda expression Syntax (1). Basic syntax and syntax simplification
?? The syntax of a lambda expression consists of a parameter list, an arrow symbol, and a function body. A function body can be either an expression or a block of statements:
- Expression: The expression is executed and then returned to the execution result.
- Statement BLOCK: Statements in a statement block are executed sequentially, just like the statements in a method
Take a look at the following example:
the function interface used in the/*** example: */Private interface Interface1{ BooleanHasperson (String name,intAge, String addr);}Private interface Interface2{ BooleanHasperson (String name);}Private interface Interface3{ BooleanEat ();}Private interface Interface4{ voidEat ();}
The following is the complete form:
privatevoid lambda3(){ = (StringString-> { Log.v(TAG"有这个人吗?"); Log.v(TAG"没有啊"); returnfalse; };}
The parameter types in the argument list are generally omitted, and the translator can infer the parameter types of the lambda expression from the context. So the lambda expression becomes:
=-> { Log.v(TAG"有这个人吗?"); Log.v(TAG"没有啊"); returnfalse;};
When a lambda expression has only one parameter number, you can omit the parentheses. The lambda expression is abbreviated as:
=-> { Log.v(TAG"有这个人吗?"); Log.v(TAG"没有啊"); returnfalse;};
When the argument is empty, you cannot omit ()
in31 = () -> { "吃饭了吗"); returntrue;};
When a lambda expression contains only one statement:
//当lambda表达式只包含一条语句时,可以省略大括号、returnin4 = ()->"吃饭了吗");//只有一returnin32 = ()-> {returnfalse;};//可以省略returnin33 = () ->false;
(2). The lexical scope of a lambda expression
?? Using variable names (and this) in an inner class is very error-prone. An inherited member from an inner class (including a method from object) may mask the members of the outer class, and the unqualified this reference points to the inner class itself rather than to the outer class.
?? The semantics of lambda expressions are simple relative to inner classes. It does not inherit any variable names from the parent class (supertype), nor does it introduce a new scope. A lambda expression is based on a lexical scope, meaning that a variable inside a lambda expression function body has the same semantics as a variable in its external environment (also including the formal parameters of a lambda expression). In addition, the ' this ' keyword and its references also have the same semantics inside and outside the lambda expression. Example:
/** * Lambda表达式中的词法作用域 */privatevoidlambdaThis(){ //this代表的是外部的Activity对象 this+"");//[email protected] r1.run(); //toString()是外部类Activity的toString,而不是Runnable的 Runnable r2 = () -> Log.e(TAG, toString());//[email protected] r2.run();}
(3). Variable capture
?? In Java 7, the compiler has strict requirements for external variables (that is, captured variables) that are referenced in internal classes: If the captured variable is not declared final, a compilation error is generated. This restriction is relaxed in Java 8, where we allow the capture of local variables that conform to valid read-only, for lambda expressions and inner classes. Simply put, if a local variable has never been modified after initialization, then it conforms to a valid read-only requirement, in other words the local variable that does not cause a compilation error after the external variable is added to the final is a valid read-only variable. Although we have relaxed the syntax restrictions on the capture variable, the behavior of trying to modify the capture variable is still forbidden. Example:
/** * Lambda表达式中的变量捕获 * lambda表达式对值封闭,对变量开放 */privatevoidlambdaFinal() { "abcdefg"; new Runnable() { @Override publicvoidrun() { Log.v(TAG, str); //只是打印str,并不作修改,允许 // str = "abc"; //编译错误,str不能修改 } }; Runnable r2 = () -> Log.e(TAG, str);//只是打印str,并不作修改,允许 //Runnable r3 = () -> {str = ""};//编译错误,str不能修改}
Special Note:
?? A reference to this and a call to an unqualified field through this and an unqualified method are all essentially using the final local variable. A lambda expression that contains such a reference is equivalent to capturing the this instance. In other cases, the Lambda object does not retain any references to this. This feature is a good thing for memory management: An internal class instance retains a strong reference to its external class instance, whereas a lambda expression that does not capture an external class member does not preserve a reference to an instance of the external class. It is often known that this feature of internal classes can cause memory leaks.
Lambda expressions using Java8 in Android stutio