摘要:由此可以看出,使用可以让你的代码在某些情况下达到何等的简洁。如果没有参数,那么前面的是必须存在的。我们知道中的,而其实就是一个只定义了一个抽象方法的。也就是说,可以访问定义它的那个方法的局部变量。而在里面,还可以访问所谓的局部变量。
上次在盆友圈发了一张照片
上面的两段代码是完全等效的,但是代码行数从11行降低到了一行,更不用说在第一段代码里面,我在run方法的前后以及内部都没有加入任何的空行。由此可以看出,使用lambda可以让你的Java代码在某些情况下达到何等的简洁。
那么问题来了。。。
Java 8 给我们带来了lambda,然而在Oracle的文档中,我没有找到lambda的定义,wikipedia里面也没有找到适合Java中的lambda的定义。写这篇文章的时候,我在这里 看到一篇很好的介绍lambda的文章,它里面给了一个定义,我觉得还挺合适的。
lambda的写法A lambda expression is a block of code with parameters.
首先列举一个完整的lambda expression:
(int a, int b) -> { System.out.println("Performing add operation..."); return a+b; }
一个lambda expression由三部分组成:
参数:(int a, int b)是这个lambda expression的参数部分,包括参数类型和参数名
箭头:->
代码块:就是用"{}"包含着的那两句代码。
上面说的是一个完整的lambda表达式,在很多情况下,很多东西是可以省略的。比如说,当系统可以根据上下文自动推断出参数的类型的时候,参数类型是可以省略的。这样的话就可以写成:
(a, b) -> { System.out.println("Performing add operation..."); return a+b; }
系统怎么自动推断出参数类型的呢?这个在下面我们就可以看到。
再比如,如果只有一个参数,而参数的类型又可以自动判断,那么连()也是可以省略的,那么就写成了:
a -> { System.out.println("Performing add operation..."); return a+a; }
再再比如,如果代码块里面只有一行代码,那么{}也是可以省略的,那么就写成了:
a -> return a+a;
是的,可以写在同一行
a -> return a+a;
让我们更进一步,在这里,return其实也是没必要的。
a -> a+a;
Great, 如果没有参数的话,是不是就可以写成:
-> a+a
呢?
很可惜,答案是否定的。如果没有参数,那么前面的()是必须存在的。也就是说,必须写成:
()-> a+alambda的用法
实际上,如果你直接把上面的代码放到你的编辑器里面,你的IDE是会报错的,因为lambda是不能这样使用的。lambda的使用永远要跟一个叫做Functional Interface的东西绑定在一起。什么叫Functional Interface呢?Functional Interface也是Java8 中引入的概念.是的,是为了lambda。我们知道java中的interface,而Functional Interface其实就是一个只定义了一个抽象方法的interface。比如Runnable 这个interface就只有一个run方法,那么它就是一个Functional Interface。
如果你对“重复”这件事情比较敏感的话,你可能又有疑问了,什么叫只定义了一个抽象方法的interface?interface中的方法不都是抽象的吗?你这个是病句吧,重复了。。。Well,在java8以前是这样的,然而在java8中,Java引进了default method的概念,说白了就是带有具体实现的方法:
public interface DuckInterface { public void wwwalksLikeADuck(); public default void tttalksLikeADuck() { System.out.println("Quack!"); } }
在上面的例子中,tttalksLikeADuck()就是一个default method,注意到这个方法的定义中有一个“default”修饰符。相信很多人会觉得这是个非常有用的feature,我也是这样觉得的。
再说回Functional Interfacel和lambda。刚刚说到,lambda必须和Functional Interface配套使用,那怎么配套使用呢?
以安卓里面的View.OnClickListener为例(它也是个Functional Interface)如果没有lambda,我们经常会这样使用的。
View.OnClickListener onClickListener = new View.OnClickListener() { @Override public void onClick(View view) { handleClick(); } }); findViewById(R.id.someView).setOnClickListener(onClickListener);
或者直接使用匿名内部类:
findViewById(R.id.someView).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { handleClick(); } });
在上面的5行代码中,有用的其实只有handleClick(),而我们却必须用5行代码去处理,这是非常繁琐的。在Java 8以前的世界,这样的代码非常多。有一个专门的名词来称呼这种性质的代码,叫“boilerplate code”,我不知到中文叫什么。。。
现在好了,有了lambda,我们可以这样写:
View.OnClickListener onClickListener = view -> handleClick(); findViewById(R.id.someView).setOnClickListener(onClickListener);
匿名内部类的版本:
findViewById(R.id.someView).setOnClickListener(view -> handleClick());
是不是瞬间觉得简洁优雅了?
从上面的例子可以看到,lambda其实就相当于简化了Functional Interface的实例的创建。当然,从真正意义上来讲,lambda的意义不止这么一点点,只不过从使用的角度来看,你可以这样看待。
这里稍微讨论一下关于lambda的其他一些特性。
在上面的例子中
View.OnClickListener onClickListener = view -> handleClick(); findViewById(R.id.someView).setOnClickListener(onClickListener);
这里,你既可以吧onClickListener看作是OnClickListener的一个instance,也可以把它看做一个代码块,后面的那句findViewById(R.id.someView).setOnClickListener(onClickListener);就相当于是吧这个代码块传给了view.setOnClickListener()这个函数。也就是说,从某种意义上来讲,你可以把lambda看作是可以相互传递的代码块。而传递代码块,是Functional Programming(一下简称FP)非常重要的一个特征,虽然说这两者其实没有什么对等关系。因为FP的本质特征是,运行一段代码并不会改变事物的状态,也就是说,没有side-effect。而lambda里面是可以调用所在的类的成员方法的、也可以访问和修改所在类的成员变量的。
话说回来,关于FP我也不是了解的很多,我本身并没有多少FP的经验,虽然对Ruby有一定了解,但Ruby也只是“可以比较好的进行”FP而已,也不是纯粹的FP语言。纯粹的FP语言是List(包括Scheme,Clojure)、Haskell、ML等等这些。关于FP,Robert Martin(就是《Clean code》和《The Clean Coder》的作者)有一个讲得很好的视频在这里。
刚刚讲到,lambda的代码块可以访问所在类的成员变量和成员方法,那对于局部变量?
我们知道,方法内部定义的匿名类是可以访问所在方法的final局部变量的,作为Functional Interface的简写方式,lambda在这点上面跟匿名类保持了一致。也就是说,lambda可以访问定义它的那个方法的final局部变量。而在Java8里面,lambda还可以访问所谓“Effectively final”的局部变量。所谓“Effectively final”的局部变量,就是说除了在定义的时候给了一个初始值以为,在没有改变过她的值的那些局部变量:
int age = 26; //在这里,age就是Effectively final的局部变量 Runnable r = () -> System.out.println("My age is "+age); new Thread(r).start();在Android开发中的应用
可是!!!Android只支持Java 7啊?怎么办?莫急,要相信网友的力量,已经有人开发了gradle的插件,可以将java 8中的labmda表达式在编译出来的bytecode里面,给它转化成Java 7兼容的代码。猛戳这里,使用方法那个页面都用,在这里就不赘述了。
如果对文章有任何意见或建议,或者是发现文中有任何问题欢迎留言!
作者 小创 更多文章 | Github | 公众号
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/64358.html
摘要:可能是最流行的集合类型。它是一个范性有序的集合。一个无序并不支持重复的集合。接口继承接口,集合中可以存放重复对象。集合类提供了,等高阶函数去处理。我们声明一个集合或者数组,可以转换成相应类型的集合。调用转换为可变集合。 不积跬步无以至千里,不积小流无以成江海 先看看Kotlin中for循环的遍历 fun testList(){ var StringVal = 12_...
摘要:现在爸爸终于让平台支持了,这篇文章中便来和大家聊聊如何在项目中配置使用。要想在项目中使用的新特性,需要将你的升级到及以上版本,并采用新的编译。 转载请注明出处:https://zhuanlan.zhihu.com/p/23279894 前言 在过去的文章中我介绍过Java8的一些新特性,包括: Java8新特性第1章(Lambda表达式) Java8新特性第2章(接口默认方法) J...
阅读 1597·2019-08-29 13:53
阅读 3201·2019-08-29 13:50
阅读 841·2019-08-27 10:51
阅读 552·2019-08-26 18:36
阅读 1743·2019-08-26 11:00
阅读 594·2019-08-26 10:36
阅读 3191·2019-08-23 17:58
阅读 2014·2019-08-23 15:17