手记

Android lambda 入门教程

用20分钟的时间,再来了解下 Lambda 表达式。为什么要学习 Lambda 表达式呢?毕竟现在的 Android 使用的 JDK 版本官方并不支持 Lambda。这里列出了一些需要理由,来说明为什么要学习 Lambda 表达式。


Lambda 表达式在后续的 Android 版本中必将得到官方支持,一些其他的 Android 开发语言例如 kotlin,未雨绸缪总是好事。

Java8 实现的 Lambda 表达式,有助于我们更好地理解编程中非常重要的几个概念,尤其是 闭包,理解数据和函数的等价性。

使用 Lambda 能够简化我们的代码,是很甜的语法糖,让我们能更好地专注于实现逻辑。

Android N 将官方支持 Lambda!


背景介绍

也许你听过 Execution in the Kingdom of Nouns, 中文翻译也叫 名词王国里的死刑,这是很有意思的一篇文章,找了一个翻译的链接,没有读过的同学可以看看, 名词王国里的死刑(翻译) - Hi!Roy!。在编写 Java 程序的时候,我们会使用类似于 ViewHelper,Compartor 等等这样的名词,几乎所有的类都是名词,Java 世界里面名词是一等公民,而动词是二等公民。但在另一些编程范式里面,名词和动词是具有同等地位的 ,代表就是函数式编程。在这些更纯粹的编程语言中,函数同样也是数据,可以像数据一样被传递,被消费,有兴趣的同学可以看看 高阶函数。引入 Lambda 是Java 对这种情况的小弥补。

闭包是函数式编程中非常重要的概念,个人对闭包这个概念的理解是,能够访问上下文环境,自包含的函数代码块,可以在代码中被传递和试用。Java 的匿名函数一定上可以实现闭包,但有了 Lambda 表达式后可以实现得更加简洁有力。

久而久之,对 Lambda 的呼声越来越高,因此在 Java8 时,官方就推出了 Lambda 表达式。

语法简介

形如 (arguments) -> (body) 的,就是 Lambda 表达式。我们来看看一些简单的例子。

[代码]java代码:

?


(int a, int b) -> {  return a + b; }  () -> System.out.println("Hello World");  (String s) -> { System.out.println(s); }  () -> 42  () -> { return 3.1415 };

Lambda 表达式可以有0个,1个以及多个参数。


参数的类型可以显示声明,也可以通过类型推导(通过上下文环境推导出)得出。


参数用括号包含,多个参数用逗号分隔。


空括号表示无参数。


如果是单个参数,同时类型可推导时,可以是不用括号包含起来。


body 部分,可以有 0 行,或者多行

当 body 部分只有一行,且返回类型匹配时,可以不加大括号。


当 body 部分有多行时,则必须用大括号包起来,也就是代码块。


总结地说,Lambda 表达式在语法上就是匿名函数的一种简写方式。


函数式接口


也许你会好奇,这些语法糖是怎么实现的?就没有一点点要求吗?我们知道 Runnable 是可以用于函数式表达式的,在查看 JDK 文档时,发现了这样的一条注释。


This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.


注释里面提及了 functional interface,Lambda 表达式规定必须是函数式接口。在 java8 中用 @FunctionalInterface 这个注解来表示是函数式接口,这里注意的是,函数式接口必须只能有申明一个抽象方法,如果有大于一个的情况,那么会发生编译错误。


我们以 Runnable 为例子,看看新的 Lambda 表达式怎么用。


[代码]java代码:

?


//Old way:new Thread(new Runnable() {    @Override    public void run() {        System.out.println("Old!");    }}).start();  //New way:new Thread(    () -> System.out.println("New")).start();

空小括号表示没有参数,而代码块只有一块,return 的是 void,所以也可以去掉大括号。

在 java 7 中,已经是函数式接口的有.

  • java.lang.Runnable

  • java.util.concurrent.Callable

  • java.security.PrivilegedAction

  • java.util.Comparator

  • java.io.FileFilter

  • java.beans.PropertyChangeListener

此外 java8 还增加了一个包,用来包含其他常用的函数式接口。

  • Predicate -- a boolean-valued property of an object

  • Consumer -- an action to be performed on an object

  • Function<T,R> – a function transforming a T to a R

  • Supplier -- provide an instance of a T (such as a factory)

  • UnaryOperator -- a function from T to T

  • BinaryOperator -- a function from (T, T) to T

我们来看下面这个例子,Java 会通过编译器,来推导具体是什么类型,即使是泛型的情况。

[代码]java代码:

?

1Callable<string> c = () -> “done”;</string>


词法作用域

Lambda表达式不会从超类中继承任何变量名,也不会引入一个新的作用域。Lambda表达式基于词法作用域,也就是说lambda表达式函数体里面的变量和它外部环境的变量具有相同的语义。例如,我们在 Lambda 外部声明了一个变量,在 Lambda 内部可以直接使用。大家在使用匿名函数的时候,会发现出于线程安全的目的,外部传入的变量必须为 final 的,而 Lambda 并不要求你也同样声明 final,但是在之后不能修改该值。这个概念被称为变量捕获。

在 Lambda 中的this,同样因为词法作用域的问题,指得是创建 Lambda 表达式所有的地方的 this。

Android 开发中该如何使用 Lambda

由于 Android Rom 使用的 Java Class 版本还是 6,7 的版本,在 Android 中使用 Lambda,需要对 Java 8 做一些桥接处理,以作适配的需要。这里可以使用 gradle-retrolambda 这个库,就能很方便地使用 Lambda 了。

下载并安装 Java 8

在 gradle 文件中,加入以下代码。

[代码]xml代码:

?


buildscript {  repositories {     mavenCentral()  }  dependencies {     classpath 'me.tatarka:gradle-retrolambda:3.4.0'  }}// Required because retrolambda is on maven centralrepositories {  mavenCentral()}apply plugin: 'com.android.application' //or apply plugin: 'java'apply plugin: 'me.tatarka.retrolambda'


原文链接:http://www.apkbus.com/blog-705730-62849.html

0人推荐
随时随地看视频
慕课网APP