Android 中lambda的小使用

前言

Lambda表达式是在JDK 8中开始支持的一种函数式推导语言,能够大量减少匿名内部类那种冗余的代码。

任务

明白怎样简单的使用和看懂lambda。

AS配置使用环境

要想使用lambda最起码需要Studio支持吧,我使用的是**Studio 2.3.3 **,因为在2.1.1之后支持lambda插件,所以我的操作如下:

 android {
      defaultConfig {
          jackOptions {
              // 打开jack编译器
              enabled true
          }
      }

      // 编译支持Java8
      compileOptions {
          sourceCompatibility JavaVersion.VERSION_1_8
          targetCompatibility JavaVersion.VERSION_1_8
      }
  }

最开始没有添加下列代码:

          jackOptions {
              // 打开jack编译器
              enabled true
          }

报错:Error:Jack is required to support java 8 language features. Either enable Jack or remove sourceCompatibility JavaVersion.VERSION_1_8.
当时一脸懵逼的样子;

扩展:
  • 2016 年 3 月 10 日, Google 向外界发布了 Android N 的预览版,并宣布了 Android N 的 Roadmap ,Android N 的最终版源代码将于今年 8 或 9 月份释出到 AOSP 项目。
  • 在众多的 Android N 新特性中,有一项新工具链的出现与 Android 生态圈的所有开发者息息相关,即 Jack & Jill 编译器的引入。在依赖了 Sun/Oracle 的 Java 编译器十年之后,Jack 是 Java Android Compiler Kit 的缩写,它可以将 Java 代码直接编译为 Dalvik 字节码,并负责 Minification, Obfuscation, Repackaging, Multidexing, Incremental compilation。它试图取代 javac/dx/proguard/jarjar/multidex 库等工具。
  • Android 终于有了自己的 Java 编译器。Android7.0(API24)在对JAVA8 语言功能的支持上,需要一个名为 Jack 的新编译。Jack 仅在 Android Studio 2.1 和更高版本上才受支持。因此,如果要使用 Java 8 语言功能,则需使用 Android Studio 2.1 开发应用。
  • 支持 Java 8 语言功能需要一个名为 Jack 的新编译。Jack 仅在 Android Studio 2.1 和更高版本上才受支持。因此,如果要使用 Java 8 语言功能,则需使用 Android Studio 2.1 开发应用,还需使用新的 Jack 工具链。新的 Android 工具链将 Java 源语言编译成 Android 可读取的 Dalvik 可执行文件字节码,且有其自己的 .jack库格式,在一个工具中提供了大多数工具链功能:重新打包、压缩、模糊化以及 Dalvik 可执行文件分包。

以下是构建 Android Dalvik 可执行文件可用的两种工具链的对比:

  • 旧版 javac 工具链:
    javac (.java –> .class) –> dx (.class –> .dex)
  • 新版 Jack 工具链:
    Jack (.java –> .jack –> .dex)

有小伙伴说了:我的不是2.1.1之前的怎么办???不要急,代码如下

  1. 在 Project 的 build.gradle 中添加如下代码
  dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3.2.0'
  }
  1. 在 Module 的 build.gradle 中添加如下代码
 // 应用插件
 apply plugin: 'me.tatarka.retrolambda'
 // 支持Java8
 android {
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_8
         targetCompatibility JavaVersion.VERSION_1_8
     }
 }

配置完,编译一下就大功告成
只可惜没有测试,有心的小伙伴可以测试一下。

使用Lambda

lambda 表达式共有三种形式:函数式接口、方法引用和构造器引用
函数式接口:是指有且只有一个抽象方法的接口,比如各种Listener接口和Runnable接口。lambda表达式就是对这类接口的匿名类进行简化。基本形式如下:
(参数列表...) ->{语句块...}
具体语法:

语法一:()->{}
其中()和{}可以看情况去掉,()只有一个参数可去掉,{}里逻辑只有一行可去掉
详情如下:

  • 无参数时,直接这么写
    // 创建Runnable对象
    Runnable runnable = () -> {

     };
  • 有一个参数,直接参数名 ->{}
  View.OnClickListener listener = view -> {

  };
  • 有多个参数,只需要在()里写上参数名字就可以
View.OnFocusChangeListener listener = (view, b) -> {

  };

举例子:上一个简单的代码:

     //定义一个接口
    interface Comparator<T> {
        int compare(T var1, T var2);
    }
    
    //老的实现方法
    Comparator comparator = new Comparator<String>() {
        @Override
        public int compare(String var1, String var2) {
            return 0;
        }
    };
    
    //lambda优化一下
    Comparator<String> comparator1 = (String s1, String s2) -> {
        return 0;
    };
    
    //lambda最后的优化,当编译器可以推导出具体的参数类型时
    Comparator<String> comparator2 = (s1, s2) -> {
        return 0;
    };
  • 当语句块内的处理逻辑只有一句表达式时,其两侧的花括号也可省略,特别注意这句处理逻辑表达式后面也不带分号。
button.setOnClickListener(view1 -> activity.finish());

同时,当只有一句去除花括号的表达式且接口方法需要返回值时,这个表达式不用(也不能)在表达式前加 return ,就可以当作返回语句。下面用 Java 的 Function 接口作为示例,这是一个用于转换类型的接口,在这里我们自己造一个使用:

    interface Function<T, R> {
        R applay(T t);
    }
    //原来的写法
    Function<Integer, String> function = new Function<Integer, String>() {
        @Override
        public String applay(Integer integer) {
            return String.valueOf(integer);
        }
    };
    //lambda的写法
    Function<Integer, String> function1 = integer -> String.valueOf(integer);

方法引用:就是当逻辑实现只有一句且调用了已存在的方法进行处理( this 和 super 的方法也可包括在内)时,对函数式接口形式的 lambda 表达式进行进一步的简化。传入引用方法的参数就是原接口方法的参数。
接下来总结一下方法引用形式的三种格式:

  • object :: instanceMethod

直接调用任意对象的实例方法,如 obj::equals 代表调用 obj 的 equals 方法与接口方法参数比较是否相等,效果等同 obj.equals(t);。

当前类的方法可用this::method进行调用,父类方法同理。

  • ClassName :: staticMethod

直接调用某类的静态方法,并将接口方法参数传入,如上述 TextUtils::isEmpty,效果等同 TextUtils.isEmpty(s);
例子如下:

  Predicate<String> predicate = new Predicate<String>() {
        @Override
        public boolean test(String s) {
            // 下面的代码和TextUtils.isEmpty(s)等价。
            return s == null || s.length() == 0;
        }
    };
    //进一步用lambda简化得到
    Predicate<String> predicate1 = s -> TextUtils.isEmpty(s);
    //但是还是可以继续简化的,我的天啊!!!
    Predicate<String> predicate2 = String::isEmpty;
  • ClassName :: instanceMethod

较为特殊,将接口方法参数列表的第一个参数作为方法调用者,其余参数作为方法参数。由于此类接口较少,故选择 Java 提供的 BiFunction 接口作为示例,该接口方法接收一个 T1 类对象和一个 T2 类对象,通过处理后返回 R 类对象:

    interface BitFunction<T1, T2, R> {
        R applay(T1 t1, T2 t2);
    }
    BitFunction<String, String, Boolean> bitFunction = new BitFunction<String, String, Boolean>() {
        @Override
        public Boolean applay(String s, String s2) {
            return s.endsWith(s2);
        }
    };
    //使用lambda得到下面的结果
    BitFunction<String, String, Boolean> bitFunction1 = String::endsWith;
    //ClassName 为接口方法的第一个参数的类名,同时利用接口方法的第一个参数作为方法调用者,其余参数作为方法参数,实现s1.endsWith(s2);
    //补充一个例子,
    BitFunction<List<String>,List<String>,Boolean> bitFunction3=List ::contains;

构造器引用
Lambda 表达式的第三种形式,其实和方法引用十分相似,只不过方法名替换为 new 。其格式为 ClassName :: new。这时编译器会通过上下文判断传入的参数的类型、顺序、数量等,来调用适合的构造器,返回对象。

使用技巧

Android Studio 会在可以转化为 lambda 表达式的代码上进行如图的灰色标识,这时将光标移至灰色区域,按下 Alt + Enter ,选择第一项(方法引用和构造器引用在第二项),IDE 就会自动进行转换。还有就是在代码进行编译的时候比如你要新建一个对象的时候也可以按下 Alt + Enter,就会得到你想要的结果。如下图所示:

img.png

特别注意

this 关键字
在匿名内部类中,this 关键字指向的是匿名类本身的对象,而在 lambda 中,this 指向的是 lambda 表达式的外部类。

方法数量差异
当前 Android Studio 对 Java 8 新特性编译时采用脱糖(desugar)处理,lambda 表达式经过编译器编译后,每一个 lambda 表达式都会增加 1~2 个方法数。而 Android 应用的方法数不能超过 65536 个。虽然一般应用较难触发,但仍需注意。

我会不定时的对文章进行补充的哦!!!加油吧骚年。。。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容