转载请标明出处:一片枫叶的专栏

新的Java8 API中提供了不少新的特性,其中就有Lambda表达式。而本文我们将主要介绍一下在Android开发过程中如何使用Lambda表达式,这里主要是为我们后续介绍RxAndroid、RxJava相关知识做铺垫的。

  • Lambda表达式的概念

Lambda表达式是Java8中提供的一种新的特性,它支持Java也能进行简单的“函数式编程”,即Lambda允许你通过表达式来代替功能接口。其实Lambda表达式的本质只是一个”语法糖”,由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能。

Lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)

咋样很厉害吧?下面我们将慢慢看一下Lambda表达式的相关知识。

  • 标准的Lambda表达式写法

那么Lambda表达式具体如何编写呢?下面我们可以看一个具体的Lambda表达式实例。

(int x, int y) -> {    Log.i("TAG", "x:" + x + "  y:" + y);    return x + y;}

这是一个标准的Lambda表达式的写法,一个Lambda表达式通常有三部分组成:

  • 参数:(int a, int b)是这个lambda expression的参数部分,包括参数类型和参数名

  • 箭头:->

  • 代码块:就是用”{}”包含着的那两句代码。

其中由于参数的类型是可以通过系统上下文推断出来的,所以在很多情况下,参数的类型是可以省略的,可以省略的写成:

(x, y) -> {    Log.i("TAG", "x:" + x + "  y:" + y);    return x + y;}

其实不光参数类型是可以省略的,代码块也是可以省略的,比如如果我们的代码块中只有一句代码,我们可以写成:

(x, y) ->     return x + y;

也可以写成:

(x, y) -> return x + y

而这个时候其实return关键字也是可以省略的,这时候我们就可以这样写:

(x, y) -> x + y

好精简有木有…

  • Lambda表达式的几个特性

(1)类型推导
编译器负责推导Lambda表达式的类型。它利用Lambda表达式所在上下文所期待的类型进行推导, 这个被期待的类型被称为目标类型。就是说我们传入的参数可以无需写类型了!

(2)变量捕获
对于lambda表达式和内部类, 我们允许在其中捕获那些符合有效只读(Effectively final)的局部变量。简单的说,如果一个局部变量在初始化后从未被修改过,那么它就符合有效只读的要求, 换句话说,加上final后也不会导致编译错误的局部变量就是有效只读变量

(3)方法引用
如果我们想要调用的方法拥有一个名字,我们就可以通过它的名字直接调用它:

Comparator byName = Comparator.comparing(Person::getName); 

此处无需再传入参数,Lambda会自动装配成Person类型进来然后执行getName()方法,而后返回getName()的String

方法引用有很多种,它们的语法如下:

静态方法引用:ClassName::methodName
实例上的实例方法引用:instanceReference::methodName
超类上的实例方法引用:super::methodName
类型上的实例方法引用:ClassName::methodName
构造方法引用:Class::new
数组构造方法引用:TypeName[]::new

  • 学习使用Lambda表达式
/** * 定义线程测试例子 */public static void m1() {        new Thread(new Runnable() {            @Override            public void run() {                Log.i("TAG", "定义一个简单测试例子...");            }        }).start();    }

以上是我们使用的普通的Java代码实现的一个简单的线程例子,那么如果使用Lambda表达式是什么形式的呢?

/** * 使用Lambda表达式实现 */public static void m2() {        new Thread(                () -> {                    Log.i("TAG", "使用Lambda表达式的例子...");                }        ).start();    }

可以看到通过Lambda表达式代码还是相当简洁的

(1)我们直接在编辑器里面写Lambda表达式是会报错的,因为Lambda不可以这样使用。在关于Lambda的使用其实需要跟一个叫做函数接口(Functional Interface)的东西绑定在一起。什么是函数接口呢?函数接口是在Java8 中引入的概念,其就是为了Lambda表达式而引入的。我们知道Java中的接口的概念,而函数接口其实就是:

一个只定义了一个抽象方法的接口

比如ClickListener这个接口就只有一个onClick方法,那么它就是一个函数接口。在Android开发过程中我们经常会这样使用OnClickListener:

/** * 定义OnClickListener,处理按钮点击事件 */View.OnClickListener onClickListener = newView.OnClickListener() {        @Override    public void onClick(View view) {        // 处理按钮点击事件        doSomeThing();    }});findViewById(R.id.titleView).setOnClickListener(onClickListener);

其实我们除了上面定义的OnClickListener我们也可以直接使用匿名内部类:

/** * 定义匿名内部类处理组件的点击事件 */findViewById(R.id.titleView).setOnClickListener(new View.OnClickListener() {        @Override    public void onClick(View view) {        // 处理组件的点击事件        doSomeThing();    }});

在上面的代码中,我们可以发现其实我们主要是调用其他的doSomeThing()方法,该方法中实现了我们的按钮点击事件,并且这里我们通过一系列的缩进,括号来实现了这个调用操作,有木有觉得很繁琐?在Java 8出现之前,在代码中经常有这样的实现。现在好了,有了Lambda达表示,我们可以这样写了:

/** * 自定义OnClickListener按钮点击事件 */View.OnClickListener onClickListener = view -> doSomeThing();findViewById(R.id.titleView).setOnClickListener(onClickListener);

至于匿名内部类我们也可以这样写:

findViewById(R.id.titleView).setOnClickListener(view -> doSomeThing());

通过使用Lambda表达式之后代码就变得相当简洁了。从上面的例子可以看到,Lambda表达式简化了函数接口的实例的创建,可以在代码层次简化函数接口,内部匿名类的写法等。

  • Lambda表达式的优缺点

上面我们简单的介绍了Lambda表达式的概念,写法与特性等,那么它具体有什么优缺点呢?

优点:

  • 使用Lambda表达式可以极大的简化代码。去除了很多无用的Java代码,使得代码更为简洁明了;

缺点:

  • 可读性差。在代码简洁的情况下,另一方面又让大多程序员很难读懂。因为很少程序员接触使用它。

  • 如何在Android Studio中使用Lambda表达式

Android Studio默认使用Lambda表达式是会报错的,即使你使用的是Java 8,升级Android Studio的Language level为1.8

Android开发过程中使用Lambda表达式_第1张图片" title="" width="650" height="335" style="border:1px solid black;">

如果是非Java8,那么我们如何使用Lambda表达式呢?

幸好有Lambda的gradle插件gradle-retrolambda,通过这个插件我们可以在Android Studio中使用Lambda表达式了,其可以兼容到Java5。

至于具体的使用方式我们可以参考其Github地址:gradle-retrolambda

具体如:

/** * 自定义组件点击事件 */imageView.setOnClickListener { view ->            Log.i("TAG", "按钮点击事件...")        }

总结:

相对来说使用Lambda表达式还是能够优化一些代码的,但是相应的代码的可能性会有相应的下降,在实际的开发过程中可根据具体的情况作出相应的选择。

更多相关文章

  1. Android启动流程---App层
  2. 详解Serializable
  3. Android闪屏效果实现方法
  4. Android虚拟导航栏遮挡底部的输入框的解决方法
  5. 修改编译android文件系统编译链版本
  6. 用Kotlin实现Android点击事件的方法
  7. Android(安卓)7.0增加jack跟jill编译器(转)
  8. 动态壁纸开发指南(一)概述介绍
  9. Android(安卓)SDK Samples,学习Android的好方法

随机推荐

  1. Android获取字体高度和设置行高
  2. android binder机制之——(创建binder服务
  3. android 5.0后矢量图形
  4. android中sqlite的使用
  5. android 检查网络状态
  6. 【Android 基础】Animation 动画介绍和实
  7. Android Paint之 setXfermode PorterDuff
  8. Android_Google android SDK源码(1)
  9. Android(安卓)源码下编译APK
  10. drawable animation 循环播放