概要:
- 函数式编程特性
- lambda表达式语法及应用场景
- Java 8自带函数式接口详解
一、函数式编程特性
1. lambda表达式简介
lambda表达式,也可称为闭包,它是推动Java 8发布的最重要新特性。
lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用lambda表达式可以使代码变得更加简洁紧凑。
如下示例中起到的作用是功能类似的:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello World");
}
}).start();
new Thread(() -> System.out.println("Hello World")).start();
java 8加入lambda之后,就可以像javascript之类的函数式语言一样,将函数逻辑作为参数或属性进行传递。
// 将函数执行逻辑以参数的形式传递给方法
sayHello(str -> Integer.parse(str) + 1);
private void sayHello(Function<String, Integer> convert) {
System.out.println("Hello World");
System.out.println(convert.apply("29"));
}
2. 为什么要使用lambda表达式?
一些会随着业务场景而变化的逻辑则以参数的形式传递到方法中,采用行为参数化可以让程序更加的通用,以应对频繁变更的需求。
这里以java 8 in action中的例子进行说明,考虑一个业务场景,假设我们需要通过程序对苹果按照一定的条件进行筛选,我们先定义一个苹果类:
// 获取 red 红颜色的苹果
public List<Apple> getRedApple() {
List result = new ArrayList();
for (Apple apple : appleStore) {
if (apple.getColor().equals("red")) {
result.add(apple);
}
}
return result;
}
// 基于颜色获取苹果
public List<Apple> getAppleByColor(String color) {
List result = new ArrayList();
for (Apple apple : appleStore) {
if (apple.getColor().equals(color)) {
result.add(apple);
}
}
return result;
}
// 基于表达式获取苹果
public List<Apple> getAppleBy(Predicate<Apple> predicate) {
List result = new ArrayList();
for (Apple apple : appleStore) {
if (predicate.test(apple)) {
result.add(apple);
}
}
return result;
}
二、lambda表达式语法及应用场景
1. 函数式接口
lambda前置条件:必须是函数式接口才可以使用lambda表达式
函数式接口特征:
- 接口中标注了@FunctionInterface注解
- 接口中只有一个抽象方法,则该接口会被编译器自动识别成函数式接口
- 接口中有一个抽象方法,同时包含了Object类的其他抽象方法,则该接口也会被识别成函数式接口
2. lambda表达式三种编写方式
expression:单条语句表达式
statement:语句块
reference:方法引用
expression单条语句表达式
只能是一个完整的语句。
expression表达式中不需要写return关键字,解释器会自动将表达式的计算结果进行返回。
示例演示:
(参数) -> 表达式
statement语句块
statement语句块通过大括号{}包裹多条语句,如果是需要返回结果的接口,必须显式的加上return指明返回的变量
示例演示:
(参数) -> {}
reference方法引用
如果某个方法在结构上与lambda表达式中对应方法是匹配的,那么就可以直接引用给lambda表达式。其总共包含4种引用类型,语法格式见表格:
类型 | 语法 |
---|---|
基于实例方法引用 | object::methodName |
构造方法引用 | className::new |
基于参数实例方法引用 | className::methodName |
静态方法引用 | className::staticMethodName |
示例演示
构造方法引用演示
public interface MyLoves {
List<String> getAllLove();
}
@Test
public void test2() {
// 构造方法引用
MyLoves loves = ArrayList::new;
loves.getAllLove();
}
基于参数实例方法引用
public interface MyLoves {
void compare(String wife, String mom);
}
@Test
public void test() {
MyLoves love = String::compareTo;
}
3. lambda表达式主要特征总结
- 可选类型声明: 不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号: 一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号: 如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字: 如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指明表达式返回了一个数值。
4. lambda表达式常见应用场景
对象排序
动态代理
事件监听
条件过滤
启动线程
三、Java 8自带函数式接口详解
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer | T | void | 对T类型参数操作,无返回结果,包含方法void accept(T t) |
Supplier | 无 | T | 返回T类型参数,方法是T get() |
Function | T | R | 对T类型参数操作,返回R类型参数,包含方法R apply(T t) |
BiFunction | 与Function类似,不同在于接收两个参数 | ||
BinaryOperator | 类似于BiFunction,不同在于所有参数和返回结果必须是一样的 | ||
Predicate | T | boolean | T 断言型接口,对类型T进行条件筛选操作 |
BiPredicate | T 断言型接口,接收两个参数进行断言 |
网友评论