就从Java8开始吧(一)lambda表达式详解

一直想写一套技术的文章,苦于不知从何落笔。今天得空从忙碌的敲代码中抽身出来,就从Java8开始说起吧。

在我看来,Java至今有两个翻天覆地的版本,一个是5,另一个就是8。Java8发布于2014年,至今已经四年多了,伴随着9和10的发布,8也不能算是多新的版本了。那么Java8的十大“新”特性如今也应该是各个程序员基本技能的一部分了。时至今日,很多软件也纷纷把jdk的最低要求设置到了8,程序员们也没有任何理由使用低于jdk8的java进行开发了。

那么,Java8提供了哪些特性,可以称得上“翻天覆地”呢?让我们一起来看一下吧。

首先,最最主要的,就是从语言层面引入了函数式编程的思想。很多脚本语言对函数式编程有着很好的支持,比如javascript和python,函数(Java中叫方法,以下可以将函数和方法作为同义词)可以像其他类型的数据一样作为函数的参数或者返回值,这样我们可以轻松地实现策略模式。比如在自定义排序函数中,我们可以将排序的策略作为一个参数传递给负责排序的函数。在Java8之前,Java对函数式编程的支持就显得十分笨重了。由于Java的方法都依赖于类,因此想要将方法作为参数或者返回值,必须用类将方法进行包装(wrap),然后将类的对象作为参数或者返回值进行传递。这样的实现无论从语法书写上,还是从阅读上,都显得不那么优雅。因此,Java的语言设计师们决定引入对函数式编程更优雅的支持。那么,过程中,设计师们做了很多考量,比如像其他语言一样,引入函数这样的数据类型。但是,受到兼容历史版本等限制的影响,最终设计师们采用了一种比较折衷的方法,这就是我们所说的lambda表达式。

下面隆重有请我们今天的主角——lambda表达式登场。lambda表达式是Java8引入的一项新语法,用->符号实现对函数式编程的支持。第一眼看到lambda表达式时,我觉得Java不那么像Java了,但是经过一段时间的使用体会,我感受到了这一项新语法引入的强大之处,也逐渐接受了Java大军中的这样一个新伙伴。为什么叫lambda表达式呢?lambda是希腊字母λ的英文拼写,在各个语言中,均有代表匿名函数之意。Java中也沿用了这一定义方式,将新的语法称为lambda表达式。lambda表达式的书写很简单,如:

x, y -> x + y
() -> doSomeThing()
(int x, String s) -> x < s.length()

上述表达式表达的含义可就没那么简单了。它其实是一种语法糖,代表一个被接口包装的方法。如上面的第一行代码,表达的是一个二元求和的方法。它大致相当于:

interface Calc {
    int sum(int x, int y)
}
class CalcImpl implements Calc{
    int sum(int x, int y){
        return x + y;
    }
}

但是在lambda表达式中,x和y的类型是根据实际情况进行推断的。当然也可以显式的指定x和y的类型。
看到这里各位可能有点蒙。没关系,上面只是为了让大家看到lambda表达式语法上的简洁性。下面我们具体来说一说lambda表达式是怎么一回事。我们还是从上面排序的例子说起。比如现在有一个字符串数组:

{"abc", "abcde", "abbb", ....}

我们要对数组进行自定义排序,比如按照字符串长度进行排序。我们知道Java提供了Arrays.sort方法进行数组排序,重载方法中有一个方法传递了一个Comparator接口的对象用于实现自定义排序,在Java8以前,我们会这么写:

String[] array = {"abc", "abcde", "abbb", "bbccd"};
Arrays.sort(array, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return o1.length() - o2.length();
    }
});

即使用一个匿名内部类来实现Comparator接口。(不熟悉这一段代码的童鞋可以回去翻一翻Java基础哦)。引入lambda表达式以后,我们可以这么写:

String[] array = {"abc", "abcde", "abbb", "bbccd"};
Arrays.sort(array, (o1, o2) -> o1.length() - o2.length());

可以看到,lambda表达式用一行代码代替了上面六行代码。lambda表达式由参数列表,箭头符号(->)和方法体三部分组成。参数列表与接口的compare方法参数列表相同,类型可以自动推断,方法体代表对这个方法的实现。方法体使用{}包围,如果只有一行代码,{}可以省略。
为了进一步理解lambda表达式的原理,这里要先引用函数式接口的概念。我们上面提到了,Java的方法依赖于类,这一点即使在Java8中也没有改变。因此想要传递一个方法作为参数或者返回值,我们还是要传递一个类(或者接口)的对象。函数式接口就是这样的接口,它的内部只有一个未实现的抽象方法,也就是说我们使用这个接口其实就是为了使用这个未实现的方法,然后对它进行实现。例如:

@FunctionalInterface
interface Wrapper{
    void method(int param);
}

Wrapper接口的唯一作用就是包装method方法,将其作为使用方法的参数或者返回值进行传递。上面的@FunctionalInterface注解是可选的,它可以在编译阶段检查接口是否符合函数式接口的要求,如果不符合,则会编译失败。
现在我们可以清晰地看到,从本质上讲,lambda表达式就是函数式接口的匿名实现类。凡是参数中传递函数式接口对象的地方,我们都可以使用lambda表达式进行替换。例如线程的创建:

// 使用匿名内部类创建线程
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        doSomeThing();
    }
};
new Thread(runnable).start();

// 使用lambda表达式创建线程
Runnable runnable = () -> doSomeThing();
new Thread(runnable).start();

再如,集合的遍历:

/*
 * Collection forEach循环
 */
List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 8, 7, 6, 5);
// fori循环
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

// foreach循环
for (int ele : list) {
    System.out.println(ele);
}

// lambda表达式
list.forEach(ele -> System.out.println(ele));

好了,先到这里吧。下一篇我们将分析lambda表达式的更多使用场景,以及如何使用方法引用进一步简化lambda表达式。

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

推荐阅读更多精彩内容