第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. HDFS的java api操作

    hdfs在生产应用中主要是针对客户端的开发,从hdfs提供的api中构造一个HDFS的访问客户端对象,然后通过该客户端对象操作(增删改查)HDFS上的文件. 搭建开发环境 方式一(windows环境下 ...

  2. Configure the MySQL account associate to the domain user via MySQL Windows Authentication Plugin

    在此记录如何将之前一次做第三发软件在配置的过程. 将AD user通过代理映射到mysql 用户. 在Mysql官网有这样一段话: The server-side Windows authentica ...

  3. CSS3实现多样的边框效果

    半透明边框 实现效果: 实现代码: <div> 你能看到半透明的边框吗? </div> div { /* 关键代码 */ border: 10px solid rgba(255 ...

  4. 学习一下DOM中的cloneNode()与cloneNode(true)的基础知识

    带你去熟悉HTML dom中当然cloneNode()与cloneNode(true)之间区别 code <!DOCTYPE html> <html> <head> ...

  5. Hibernate中配置文件的学习

    首先我们看一下hibernate的主配置文件 <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Conf ...

  6. Opencv3.1+python2.7的CentOS7安装

    http://blog.csdn.NET/daunxx/article/details/50506625 转载注释:有些包名和系统包名并不匹配,yum install 找不到的时候,可以yum sea ...

  7. zinnia项目功能分析

    Zinnia是基于Django开发的一个开源博客系统,近期为了写一个类博客系统特对它做功能分析,+号的多少表明这个功能对于博客的重要性: ++评论:Comments 站点图:Sitemaps ]压缩视 ...

  8. Jenkins实现Android自动化打包

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/77102359 本文出自[赵彦军的博客] 1.Tomcat 进入 https://t ...

  9. 设计一个卖不同种类车的4s店

    # 定义奔驰车类 class BenchiCar(object): # 定义车的方法 def move(self): print('---奔驰车在移动---') def stop(self): pri ...

  10. Python进阶开发之元类编程

    系列文章 √第一章 元类编程,已完成 ; 本文目录 类是如何产生的如何使用type创建类理解什么是元类使用元类的意义元类实战:ORM . 类是如何产生的 类是如何产生?这个问题肯定很傻.实则不然,很多 ...