一、Lambda表达式及函数式接口介绍

1. 描述

Lambda表达式是Java8中最重要的新功能之一。使用Lambda表达式可以替代只有一个抽象函数的接口实现, 告别匿名内部类,代码看起来更简洁易懂。Lambda表达式同时还提升了对集合、框架的跌代、遍历、过滤数据的操作。

2. 特点

函数式编程

参数类型自动推断

代码量少,简洁

3. 如何学习

熟悉泛型

多练, 多用Stream API

4. Lambda表达式使用场景

任何有函数式接口的地方

函数式接口: 只有一个抽象方法的接口, 排除 Object中的方法, default, static修饰的方法.

5. 函数式接口定义

定义只有一个抽象方法的接口

在接口上加注解@FunctionalInterface

示例

@FunctionalInterface
public interface DemoLambda2 {
int delete();
// Object中的方法不包括
public int hashCode();
// default修饰的不包括
default int insert(){
return 1;
}
// static修饰的不包括
static void update() {}
}
6. JDK1.8中定义的Lambda表达式
Supplier: 代表一个输出
@FunctionalInterface
public interface Supplier {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
Consumer: 代表一个输入
@FunctionalInterface
public interface Consumer {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
BiConsumer: 代表2个输入.
@FunctionalInterface
public interface BiConsumer {
/**
* Performs this operation on the given arguments.
*
* @param t the first input argument
* @param u the second input argument
*/
void accept(T t, U u);
}
Function: 代表一个输入, 一个输出(一般输入和输出是不同类型的)
@FunctionalInterface
public interface Function {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
}
UnaryOperator: 代表一个输入, 一个输出(输入和输出是相同类型)
@FunctionalInterface
public interface UnaryOperator extends Function {
}
BiFunction: 代表2个输入, 一个输出.(一般输入输出不同)
@FunctionalInterface
public interface BiFunction {
/**
* Applies this function to the given arguments.
*
* @param t the first function argument
* @param u the second function argument
* @return the function result
*/
R apply(T t, U u);
BinaryOperator: 代表2个输入, 一个输出 (输入和输出是相同类型的)
@FunctionalInterface
public interface BinaryOperator extends BiFunction {
}

二、Lambda表达式详解

1. Lambda表达式

Lambda表达式是对象, 是一个函数式接口的实例.

2. Lambda表达式语法

语法: LambdaParameters -> lambdaBody

例子

Runnable r = () -> Systerm.out.print("例子");

自己理解如下:

函数式接口定义的方法中的参数是LambdaParameters, 加上->, 实现函数式接口的具体内容是lambdaBody.

三、方法的引用(一)

方法的引用: 用来直接访问类或者实例的已经存在的方法或构造方法, 方法引用提供了一种引用而不执行方法的方式, 如果抽象方法的实现恰好可以使用调用另外一个方法来实现, 就有可能使用方法引用.

方法引用分类

类型

语法

对应的lambda表达式

静态方法引用

类名::staticMethod

(args)->类名.staticMethod(args)

实例方法引用

inst::instMethod

(args)->inst.instMethod(args)

对象方法引用

类名::instMethod

(args)->类名.instMethod(args)

构造方法引用

类名::new

(args)->new 类名(args)

静态方法引用

定义: 如果函数式接口的实现恰好是通过调用一个静态方法来实现, 那么就可以使用静态方法使用.

实例方法引用

定义: 如果函数式接口的实现恰好可以通过调用一个实例的实例方法来实现, 那么就可以使用实例方法引用

语法: inst::instMethod

对象方法引用

定义: 函数是接口中的抽象方法的第一个参数类型刚好是实例的类型, 抽象方法剩余的参数恰好可以当做实例方法的参数. 如果函数式接口的实现能由上面说的实例方法调用来实现的话, 那么就可以使用对象方法引用.

抽象方法的参数类型. 而不是抽象接口.例如:

对象方法引用适用于自定义对象.

/**

* 注意不要用函数式接口的泛型参数来对比参数:

* 比如函数式接口: BiFunction

* 要对比它的抽象方法: R apply(T t, U u);

* 第一个参数T, 要是实例的类型DemoLamda5

* 第二个参数U, 要是实例方法getA(String b)的参数b类型一致

* R是出参, 不是抽象方法的入参.

*/
public class DemoLamda5 {
public String getA(String b) {
return b;
}
public void test1() {
BiFunction biFunction = (a, b) -> new DemoLamda5().getA(b);
BiFunction biFunctio2n = DemoLamda5::getA;
}
}
构造方法引用
定义: 如果函数式接口的实现恰好可以通过调用一个类的构造方法来实现, 那么就可以使用构造方法引用.
注意: 构造方法引用适用于无参的构造方法. 有参也可以使用.
public class DemoLambda6 {
public void testConst() {
// 全写
Supplier supplier = () -> {
return new Person();
};
// 构造方法引用写法
Supplier supplier1 = Person::new;
}
}

五、Stream API

英文定义: A sequence of elements supporting sequential and parallel aggregate operations

Stream是一组用来处理数组、集合的API

特性

不是数据结构, 没有内部存储

不支持索引访问

延迟计算

支持并行

很容易生成数组或集合(List, Set)

支持过滤, 查找, 转换, 汇总, 聚合等操作.

Stream运行机制

Stream分为源source, 中间操作, 终止操作。

流的源可以是一个数组、 一个集合、 一个生成器方法、 一个I/O通道等等.

一个流可以有零个或多个中间操作,每一个中间操作都会返回一个新的流,供下一个操作使用,一个流只会有一个终止操作。

Stream只有遇到终止操作,它的源才开始执行遍历操作。

Stream的创建

通过数组

通过集合

通过Stream.generate方法来创建

通过Stream.iterate方法来创建

其他API创建.

Stream常用API

中间操作

过滤 filter

去重 distinct

排队 sorted

截取 limit, skip

转换 map/flatmap

其他 peek

终止操作

循环 foreach

计算 min, max, count, average

匹配 anyMatch, allMatch, noneMatch, findFirst, findAny

汇聚 reduce

收集器 toArray, collect

七、 Lambda表达式、方法的引用、Stream API实战