为了账号安全,请及时绑定邮箱和手机立即绑定

Android lambda 入门教程

标签:
Android

用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 对这种情况的小弥补。

funny

闭包是函数式编程中非常重要的概念,个人对闭包这个概念的理解是,能够访问上下文环境,自包含的函数代码块,可以在代码中被传递和试用。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

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消