1.1 为什么要使用lambda 表达式

第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 中使用代码块。

时间: 2024-10-14 22:56:15

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

Lambda表达式实战视频教程

视频教程地址: https://my.oschina.net/u/3217554/blog/1507456 1:Lambda表达式及函数式接口介绍 2:Lambda表达式详解 3:方法的引用(一) 4:方法的引用(二) 5:Stream API(一) 6:Stream API(二) 7:Lambda表达式.方法的引用.Stream API实战

lambda表达式封装对数据库的查询

前言: 1.为什么要封装lambda表达式数据库查询,原因有一下几点: 1.1.在以往的开发中进行数据库表查询时,其实所需要的字段就是其中几个,但是在开发中,开发者往往习惯select * 进行查询,当数据多和用户量多时,查询的效率会降低. 1.2.在写查询where条件的时候,总是用string.format去拼接字符串,开发效率低. 1.3.代码不够优雅,代码中嵌套和多sql语句,如果是表字段发生改变时编译器检查不出来,代码出错的概率大. 1.4.本着 write less  do more

Lambda表达式

import org.junit.Test; import java.util.Comparator; import java.util.function.Consumer; /** * 一.Lambda 表达式基础语法:Java8中引入一个新的操作符"->"该操作符称为箭头操作符或Lambda操作符 * 箭头操作符将Lambda表达式拆分为两部分: * 左侧: Lambda表达式的参数列表 * 右侧: Lambda表达式中所需要执行的功能,即Lambda体 * * 语法格式一:

C#学习日记25---匿名方法 与 Func委托 与 lambda表达式

       在 2.0 之前的 C# 版本中,声明委托的唯一方法是使用命名方法.C# 2.0 引入了匿名方法(委托),而在 C# 3.0 及更高版本中,Lambda 表达式取代了匿名方法,作为编写内联代码的首选方式. 匿名委托(方法): 匿名委托的叫法并不准确,准确的应该叫做匿名方法,(总之两者是一个意思啦).前面  委托类型  中我已经提到过,委托是用于引用与其具有相同标签的方法.换句话说,您可以使用委托对象调用可由委托引用的方法(参数是方法名).而匿名方法则是将代码块作为委托参数(参数是实

java8之lambda表达式(构造器引用)

构造器引用同方法引用类似,不同的是在构造器引用中方法名是new.例如,Button::new表示Button类的构造器引用.对于拥有多个构造器的类,选择使用哪个构造器取决于上下文.假设你有一个字符串列表,并且希望调用Button类的构造器使用列表中的字符串来构造一个按钮列表,可以使用如下表达式: List<String> labels = ....; Stream<Button> stream = labels.stream().map(Button::new); List<

lambda表达式+python内置函数

传统的定义函数方式如下 def f1(): return 123 lambda表达式定义函数 f2 = lambda : 123 python3的内置函数 1.abs 绝对值 i = abs(-11) print (i) 输出结果是11 abs = absolute 2,all 循环参数,如果每个元素都为真,则返回为真 r = all([True, True]) print (r) 在python中 0 () [] ''和 None是False(空值都是假的) r = all(["123&quo

兰姆达表达式Lambda 表达式(C# 编程指南)

转https://msdn.microsoft.com/zh-cn/library/bb397687.aspx Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数.通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地函数.Lambda 表达式对于编写 LINQ 查询表达式特别有用. 若要创建 Lambda 表达式,需要在 Lambda 运算符 => 左侧指定输入参数(如果有),然后在另一侧输入表达式或语句块.例如,lambda 表达式 x => x

JDK8新特性 Lambda表达式

一.接口的默认方法二.Lambda 表达式三.函数式接口四.方法与构造函数引用五.Lambda 作用域六.访问局部变量七.访问对象字段与静态变量八.访问接口的默认方法九.Date API十.Annotation 注解:支持多重注解 一.接口的默认方法 Java8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下: [java] view plain copy public interface Formula { double calcu

lambda表达式和for_each

1 lambda表达式可以允许我传递任意可调用对象,必须要有捕获列表和函数体,标准形式是[捕获列表] (参数列表)->return tpye{函数体} 谓词:一元谓词指的是只能接受一个传入参数,二元谓词指的是接受两个参数. 如果没有写返回类型[](){};这样有两种情况:1.函数体类只能有一个return语句,2.如果有多余两条语句,返回的就是void 有多条语句还想返回其他类型,必须用标准形式eg;[] (int i)->int{if (i>0) return i;else retur

python lambda表达式简单用法

转自:http://www.cnblogs.com/guigujun/p/6134828.html 习条件运算时,对于简单的 if else 语句,可以使用三元运算来表示,即: 1 2 3 4 5 6 7 8 # 普通条件语句 if 1 == 1:     name = 'wupeiqi' else:     name = 'alex'   # 三元运算 name = 'wupeiqi' if 1 == 1 else 'alex' 对于简单的函数,也存在一种简便的表示方式,即:lambda表达式