第1章 lambda 表达式

1.1 为什么要使用lambda 表达式

1.2 lambda 表达式的语法

1.3 函数式接口

1.4 方法引用

1.5 构造器引用

1.6 变量作用域

1.7 默认方法

1.8 接口中的静态方法

练习

Java 作为一门面向对象的编程语言诞生于20 世纪90 年代,在当时,面向对象编程是软件开发的主流模式。在面向对象编程出现之前,也曾诞生过像Lisp 和Scheme 这样的函数式编程语言,但它们只活跃于学术圈中。最近,由于在并发和事件驱动(或者称“互动”)编程中的优势,函数式编程又逐渐变得重要起来。这并不意味着面向对象编程不好,相反,最终的趋势是将面向对象编程和函数式编程结合起来。即使你对并发等功能不感兴趣,函数式编程也会给你带来帮助。例如,如果语言有了非常方便的函数表达式语法,集合API 就会变得异常强大。

Java 8 主要是在原来面向对象的基础上增加了函数式编程的能力。在本章中,你将学习基本的语法。下一章将会向你介绍如何利用这些语法来使用Java 集合类,第3章将介绍如何构建自己的函数式API。

本章的要点包括:

一个lambda 表达式是一个带有参数的代码块。

当你想要代码块在以后某个时间点执行时,可以使用lambda 表达式。

lambda 表达式可以被转换为函数式接口。

lambda 表达式可以在闭包作用域中有效地访问final 变量。

方法和构造器引用可以引用方法或构造器,但无须调用它们。

你现在可以向接口添加默认(default)和静态(static)方法来提供具体的实现。

你必须解决接口中多个默认方法之间的冲突。

1.1 为什么要使用lambda 表达式

“lambda 表达式”是一段可以传递的代码,因此它可以被执行一次或多次。在学习语法(甚至包括一些奇怪的术语)之前,我们先回顾一下之前在Java 中一直使用的相似的代码块。

当我们要在另一个独立线程中执行一些逻辑时,通常会将代码放在一个实现Runnable 接口的类的run 方法中,如下所示:

  1. class Worker implements Runnable {
  2. public void run() {
  3. for (int i = 0; i < 1000; i++)
  4. doWork();
  5. }
  6. ...
  7. }

然后,当我们希望执行这段代码时,会构造一个Worker 类的实例。然后将该实例提交到一个线程池中,或者简单点,直接启动一个新的线程:

  1. Worker w = new Worker();
  2. new Thread(w).start();

这段代码的关键在于,run 方法中包含了你希望在另一个线程中执行的代码。我们考虑一下用一个自定义的比较器来进行排序。如果你希望按照字符串的长度而不是默认的字典顺序来排序,那么你可以将一个Comparator 对象传递给sort 方法:

  1. class LengthComparator implements Comparator<String> {
  2. public int compare(String first, String second) {
  3. return Integer.compare(first.length(), second.length());
  4. }
  5. }
  6. Arrays.sort(strings, new LengthComparator());

sort 方法会一直调用compare 方法,对顺序不对的元素进行重新排序,直到数组完全有序为止。你给sort 方法传递了一段需要比较元素的代码片段,而该代码会被整合到排序逻辑中,而你可能并不关心如何在那里实现。

注意:如果x=y,那么Integer.compare(x,y)会返回0;如果x<y,则它会返回一个负数;而如果x>y,则它会返回一个正数。这个静态方法已经被添加到Java 7中(请参考第9 章)。还要注意,不应该使用x-y 来比较x 和y 的大小,因为对于大的、符号相反的操作数,这种计算有可能会产生溢出。

按钮回调是另外一个会延迟执行的例子。你将回调操作放到一个实现了监听器接口的类的某个方法中,然后构造一个实例,并将实例注册到按钮上。在这种情况下,许多开发人员都会使用“匿名类的匿名实例”的方法:

  1. button.setOnAction(new EventHandler<ActionEvent>() {
  2. public void handle(ActionEvent event) {
  3. System.out.println("Thanks for clicking!");
  4. }
  5. });

这里的关键是代码处于handle 方法中。该代码会在按钮被点击时执行。

注意:由于Java 8 将JavaFX 作为Swing GUI 的下一任继承者,我会在这些示例中使用JavaFX(请参考第4 章来了解更多关于JavaFX 的信息)。当然,细节并不重要,因为不管是Swing、JavaFX 还是Android,你都需要为按钮添加一些代码,以使它们在按钮被点击时可以执行。

在所有三个例子中,你会看到相同的方式。一段代码会被传递给其他调用者——也许是一个线程池、一个排序方法,或者是一个按钮。这段代码会在稍后被调用。

到现在为止,在Java 中向其他代码传递一段代码并不是很容易。你不可能将代码块到处传递。由于Java 是一个面向对象的语言,因此你不得不构建一个属于某个类的对象,由它的某个方法来包含所需的代码。

在其他一些语言中可以直接使用代码块。在很长一段时间里,Java 设计者们都拒绝加入这一特性。毕竟,Java 的一大优势在于它的简单和一致性。如果一个语言包含了所有可以略微简化代码的特性,那么它就会变得不可维护。但是,在其他那些语言中,并不只是产生线程或者注册按钮点击事件的代码变得更简单了,它们大量的API 都是更简单、更一致、更强大的。虽然我们已经通过类、对象的方式在Java 中实现了相似的API和功能,但是这些API 使用起来并不让人感到轻松和愉快。

最近的一段时间,争论的问题已经不再是Java 是否要变成一门函数式编程语言,而是如何实现这种改变了。在设计出一个适合Java 的解决办法之前已经进行了多年的实验。在下一节中,你将会看到如何在Java 8 中使用代码块。

1.1 为什么要使用lambda 表达式的更多相关文章

  1. 你知道C#中的Lambda表达式的演化过程吗?

    那得从很久很久以前说起了,记得那个时候... 懵懂的记得从前有个叫委托的东西是那么的高深难懂. 委托的使用 例一: 什么是委托? 个人理解:用来传递方法的类型.(用来传递数字的类型有int.float ...

  2. Linq表达式、Lambda表达式你更喜欢哪个?

    什么是Linq表达式?什么是Lambda表达式? 如图: 由此可见Linq表达式和Lambda表达式并没有什么可比性. 那与Lambda表达式相关的整条语句称作什么呢?在微软并没有给出官方的命名,在& ...

  3. 背后的故事之 - 快乐的Lambda表达式(一)

    快乐的Lambda表达式(二) 自从Lambda随.NET Framework3.5出现在.NET开发者眼前以来,它已经给我们带来了太多的欣喜.它优雅,对开发者更友好,能提高开发效率,天啊!它还有可能 ...

  4. Kotlin的Lambda表达式以及它们怎样简化Android开发(KAD 07)

    作者:Antonio Leiva 时间:Jan 5, 2017 原文链接:https://antonioleiva.com/lambdas-kotlin/ 由于Lambda表达式允许更简单的方式建模式 ...

  5. java8中lambda表达式的应用,以及一些泛型相关

    语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利 顺带用到一些泛型编程,一切都是为了简化代码 场景: 一个数据类,用于记录职工信息 public clas ...

  6. 背后的故事之 - 快乐的Lambda表达式(二)

    快乐的Lambda表达式 上一篇 背后的故事之 - 快乐的Lambda表达式(一)我们由浅入深的分析了一下Lambda表达式.知道了它和委托以及普通方法的区别,并且通过测试对比他们之间的性能,然后我们 ...

  7. CRL快速开发框架系列教程二(基于Lambda表达式查询)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  8. Lambda 表达式递归用法实例

    注意: 使用Lambda表达式会增加额外开销,但却有时候又蛮方便的. Windows下查找子孙窗口实例: HWND FindDescendantWindows(HWND hWndParent, LPC ...

  9. Spark中Lambda表达式的变量作用域

    通常,我们希望能够在lambda表达式的闭合方法或类中访问其他的变量,例如: package java8test; public class T1 { public static void main( ...

  10. 释放Android的函数式能量(I):Kotlin语言的Lambda表达式

    原文标题:Unleash functional power on Android (I): Kotlin lambdas 原文链接:http://antonioleiva.com/operator-o ...

随机推荐

  1. twisted高并发库transport函数处理数据包的些许问题

    还是在学校时间比较多, 能够把时间更多的花在学习上, 尽管工作对人的提升更大, 但是总是没什么时间学习, 而且工作的气氛总是很紧凑, 忙碌, 少了些许激情吧.适应就好了.延续着之前对twisted高并 ...

  2. sso系统使用

    一:什么是sso(single sign on) ? sso(单点登录系统)简单说就是客户端第一次访问应用1的时候,由于没有登录,会被引导到登录页面进行登录,如果登录校验通过,将返回一个认证信息tic ...

  3. 百度编辑器上传视频音频的bug

    前言:UEditor是由百度web前端研发部开发所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点,开源基于MIT协议,允许自由使用和修改代码,百度Ueditor 支持多种后台语言上传 ...

  4. 【精解】EOS标准货币体系与源码实现分析

    EOS智能合约中包含一个exchange合约,它支持用户创建一笔交易,是任何两个基本货币类型之间的交易.这个合约的作用是跨不同币种(都是EOS上的标准货币类型)的,通过各自与EOS主链价值进行锚定,然 ...

  5. svn path already exists的解决办法

    这种问题的一般原因是这个path所指的目录在服务器端是一个空目录,对客户端不可见,客户端如果新建了这个目录,而且向服务器端commit的时候就会报错,服务器端此目录已存在,这个时候就会存在一个问题:就 ...

  6. Angularjs $http服务的两个request安全问题

    今天为了hybrid app和后端restful服务的安全认证问题,又翻了一下$http的文档,$http服务文档页面两个安全问题是json和XSRF,JSON那个比较好理解,就不补充什么了,说说XS ...

  7. 关于django migrations的使用

    django 1.8之后推出的migrations机制使django的数据模式管理更方便容易,现在简单谈谈他的机制和一些问题的解决方法: 1.谈谈机制:migrations机制有两个指令,第一个是ma ...

  8. 在 Ubuntu 系统中部署 Git Server

    http://blog.csdn.NET/poisonchry/article/details/11849781 虽然有很多开源的Git仓库,不过并非所有都尽人意,譬如Github,Gitlab等,不 ...

  9. 一道面试题引发的思考(C#值类型和引用类型)

    某年某月,笔者去面试招行的一个外包项目,辗转来到面试地点以后,面试官给了我一份试卷,试卷只有两道题目,其中一道是这样的: 阅读以下程序 class Program { struct Point { p ...

  10. javaXML文件解析之DOM4J实操

    既然前面说了DOM4J这里好那里好,大家都是在用这个,那咱就不得不写一个了. XML文件: <?xml version="1.0" encoding="UTF-8& ...