Android tips(十三)-->Android开发过程中使用Lambda表达式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_23547831/article/details/52723158

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

新的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

这里写图片描述

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

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

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

具体如:

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

总结:

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

猜你喜欢

转载自blog.csdn.net/qq_23547831/article/details/52723158