Lambda表达式告别@override

引言

 什么是Lambda呢?你肯定想到了数学符号中的那个“入”形状的符号吧?它可不是数学界的专利,在java中也有哦,本文针对Android开发中的Lambda表达式,详细介绍并且教你如何使用,简化你的代码,让你的代码看起来清新脱俗~


介绍

  Lambda 是匿名函数的别名。简单来说,就是对匿名内部类的进一步简化。使用 Lambda 表达式的前提是编译器可以准确的判断出你需要哪一个匿名内部类的哪一个方法。


用法

第一步:添加Lambda表达式(Module下build.gradle)

因为java1.8环境下支持lambda表达式的使用,故

compileOptions {
        targetCompatibility 1.8
        sourceCompatibility 1.8
}

第二步:布局文件

简单添加一个按钮,并为其设置id值

    <Button
        android:id="@+id/btn_LambdaShow"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="千夜零一"
        android:textSize="20sp" />

第三步:点击事件处理

我们最经常接触使用匿名内部类的行为是为 view 设置 OnClickListener ,这时你的代码是这样的:

//一般写法
public class Case20 extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_case20);

        Button btnShow = findViewById(R.id.btn_LambdaShow);
        btnShow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(getBaseContext(),"hello,千夜零一!",Toast.LENGTH_SHORT).show();
            }
        });
    }
}

使用匿名内部类,实现了对象名的隐匿;而匿名函数,则是对方法名的隐匿。所以当使用 lambda 表达式实现上述代码时,是这样的:

//lambda表达式
public class Case20 extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_case20);
        btnShow.setOnClickListener((View)->{
             Toast.makeText(getBaseContext(),"hello,Lambda!",Toast.LENGTH_SHORT).show();
        });
    }
}

你只要理解,lambda表达式不仅对对象名进行隐匿,更完成了方法名的隐匿,展示了一个接口抽象方法最有价值的两点:参数列表和具体实现。


【 干货】:lambda表达式的三种形式

在 Java 中,lambda表达式共有三种形式:==函数式接口==、==方法引用==和==构造器引用==。其中,函数式接口形式是最基本的 lambda 形式,其余两种形式都是基于此形式进行拓展。

函数式接口(形式一)

函数式接口是指有且只有一个抽象方法的接口,比如各种 Listener 接口和 Runnable 接口。lambda 表达式就是对这类接口的匿名内部类进行简化。基本形式如下:

( 参数列表... ) -> { 语句块... }

排序比较函数例子:两个参数

interface Comparator<T> {int compare(T var1, T var2);}
Comparator<String> comparator = new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        doSomeWork();
        return result;
    }
};

此时使用lambda进行简化,就变成了这样

Comparator<String> comparator = (s1, s2) -> {
    doSomeWork();
    return result;
};

常用点击事件函数例子:一个参数

当参数只有一个时,参数列表两侧的圆括号也可省略,比如 OnClickListener 接口可写成

interface OnClickListener {
    void onClick(View v);
}

OnClickLisenter listener = v -> {语句块...};

然而,当方法没有传入参数的时候,则记得提供一对空括号假装自己是参数列表(雾),比如 Runnable 接口:

interface Runnable {
    void void run();
}

Runnable runnable = () -> {语句块...};

当语句块内的处理逻辑只有一句表达式时,其两侧的花括号也可省略,特别注意这句处理逻辑表达式后面也不带分号。比如这个关闭 activity 的点击方法:

button.setOnClickListener( v -> activity.finish() );

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

interface Function<T, R> { R apply(T t); }
Function<User, String> function = new Function<User, String>() {
    @Override
    public String apply(User user) {
        return user.getName();
    }
};
Function<User, String> function = user -> user.getName();

方法引用(形式二)

当我们使用第一种 lambda 表达式的时候,进行逻辑实现的时候我们既可以自己实现一系列处理,也可以直接调用已经存在的方法,下面以 Java 的 Predicate 接口作为示例,此接口用来实现判断功能,我们来对字符串进行全面的判空操作:

interface Predicate<T> { boolean test(T t); }
Predicate<String> predicate = 
    s -> {
        // 用基本代码组合进行判断
        return s== null || s.length() == 0;
    };

我们知道,TextUtils的isEmpty()方法实现了上述功能,所以我们可以写作:

Predicate<String> predicate = s -> TextUtils.isEmpty(s);

这时我们调用了已存在的方法来进行逻辑判断,我们就可以使用方法引用的形式继续简化这一段 lambda 表达式:

Predicate<String> predicate = TextUtils::isEmpty(s);

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


方法引用形式的三种格式:

第一种:

object :: instanceMethod

直接调用任意对象的实例方法,如 obj::equals 代表调用 obj 的 equals 方法与接口方法参数比较是否相等,效果等同 obj.equals(t);当前类的方法可用this::method进行调用,父类方法同理。

第二种:

ClassName :: staticMethod

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

第三种:

ClassName :: instanceMethod

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

interface BiFunction<T1, T2, R> {
      R apply(T1 t1, T2 t2);
  }
  BiFunction<String, String, Boolean> biFunction =new BiFunction<String, String, Boolean>() {
      @Override
      public Boolean apply(String s1, String s2) {
          return s1.equals(s2);
      }
  };
  // ClassName 为接口方法的第一个参数的类名,同时利用接口方法的第一个参数作为方法调用者,
  // 其余参数作为方法参数,实现 s1.equals(s2);
  BiFunction<String, String, Boolean> biFunction = String::equals;

运行效果

Lambda.gif

构造器引用

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


解析

this 关键字

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

方法数量差异

  当前 Android Studio 对 Java 8 新特性编译时采用脱糖(desugar)处理,lambda 表达式经过编译器编译后,每一个 lambda 表达式都会增加 1~2 个方法数。而 Android 应用的方法数不能超过 65536 个(之后我会就这个bug报错的解决方法也分享出来)虽然一般应用较难触发,但仍需注意。


千夜零一:“之前总是看各种博客学习东西,现在我想用博客记录下我的学习脚步,好东西也需要分享,索取和给予是相互的。以后会尽量日更的!目标完成1001篇博客哈哈。”
  如果觉得对你有所帮助,请不要吝啬你的点赞,有问题也可以在下方评论区留言哦,关注我一起学习吧~

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