Java深入解析篇四之函数式编程(Functional Programming)详解
目录
- 函数式编程概念与Java实现
- Lambda表达式语法与原理
- 函数式接口体系
- 方法引用
- [Stream API完整操作](#Stream API完整操作)
- Stream内部原理
- Collector自定义
- 并行流原理与ForkJoinPool
- Optional正确使用
- 函数组合
- 函数式异常处理
- 函数式编程在Spring/框架中的应用
- Stream性能分析与最佳实践
- [JDK 9-21函数式改进](#JDK 9-21函数式改进)
1. 函数式编程概念与Java实现
1.1 函数式编程核心思想
函数式编程(FP)是一种以函数为核心构建程序的范式,强调:
- 纯函数(Pure Function):相同输入永远产生相同输出,无副作用
- 不可变性(Immutability):数据一旦创建不可修改
- 高阶函数(Higher-Order Function):函数可作为参数传递、作为返回值
- 声明式(Declarative):描述"做什么"而非"怎么做"
- 函数是一等公民:可赋值给变量、存入集合、作为参数
java
// 命令式:描述"怎么做"
List<String> result = new ArrayList<>();
for (String s : names) {
if (s.length() > 3) {
result.add(s.toUpperCase());
}
}
// 声明式(函数式):描述"做什么"
List<String> result = names.stream()
.filter(s -> s.length() > 3)
.map(String::toUpperCase)
.collect(Collectors.toList());
1.2 Java的函数式支持
Java 8 并非纯函数式语言,而是在面向对象基础上引入函数式特性:
| 特性 | Java实现方式 |
|---|---|
| Lambda | (x) -> x * 2 匿名函数语法 |
| 高阶函数 | 方法参数/返回值为函数式接口 |
| 不可变 | final、Stream不修改源、List.of() |
| 惰性求值 | Stream中间操作延迟执行 |
| 模式匹配 | JDK 21 Pattern Matching for switch |
java
// Java中的高阶函数:接受函数、返回函数
public class HigherOrderDemo {
// 接受函数作为参数
public static <T, R> List<R> transform(List<T> list, Function<T, R> mapper) {
List<R> result = new ArrayList<>();
for (T item : list) {
result.add(mapper.apply(item));
}
return result;
}
// 返回函数作为结果
public static Function<Integer, Integer> multiplier(int factor) {
return x -> x * factor; // 闭包捕获factor
}
public static void main(String[] args) {
List<String> names = List.of("Alice", "Bob", "Charlie");
List<Integer> lengths = transform(names, String::length);
System.out.println(lengths); // [5, 3, 7]
Function<Integer, Integer> triple = multiplier(3);
System.out.println(triple.apply(10)); // 30
}
}
1.3 纯函数与副作用
java
// 非纯函数:依赖外部状态,有副作用
class Counter {
private int count = 0;
public int increment() { return ++count; } // 修改了状态
}
// 纯函数:相同输入 → 相同输出,无副作用
public static int add(int a, int b) {
return a + b; // 不依赖外部状态,不修改任何数据
}
// Stream操作鼓励纯函数风格
List<Integer> doubled = List.of(1, 2, 3).stream()
.map(x -> x * 2) // 纯函数:不修改x
.collect(Collectors.toList()); // 产生新集合,不修改源
2. Lambda表达式语法与原理
2.1 基本语法
java
// 完整形式
(参数类型 参数名, ...) -> { 方法体; return 返回值; }
// 简化规则:
// 1. 参数类型可省略(编译器推断)
// 2. 单参数可省略括号
// 3. 单表达式可省略大括号和return
// 示例对比
Comparator<String> c1 = (String a, String b) -> { return a.length() - b.length(); };
Comparator<String> c2 = (a, b) -> a.length() - b.length(); // 最简形式
Runnable r1 = () -> { System.out.println("hello"); };
Runnable r2 = () -> System.out.println("hello"); // 单语句简化
Function<Integer, Integer> f1 = (x) -> { return x * x; };
Function<Integer, Integer> f2 = x -> x * x; // 单参数+单表达式
2.2 变量捕获与闭包
java
public class ClosureDemo {
public static void main(String[] args) {
int factor = 10; // effectively final(未重新赋值)
// Lambda捕获外部变量(闭包)
Function<Integer, Integer> multiply = x -> x * factor;
System.out.println(multiply.apply(5)); // 50
// factor = 20; // 编译错误!捕获的变量必须effectively final
// 捕获对象引用(引用不变,对象可变)
List<String> list = new ArrayList<>();
Consumer<String> adder = s -> list.add(s); // OK:list引用未变
adder.accept("hello");
// list = new ArrayList<>(); // 编译错误!引用被重新赋值
}
}
2.3 编译原理:invokedynamic
Lambda 不是编译为匿名内部类,而是通过 invokedynamic 指令 + LambdaMetafactory 在运行时生成:
java
// 源码
Function<String, Integer> f = s -> s.length();
// javap -c 反编译结果(简化):
// invokedynamic #2, 0 // InvokeDynamic #0:apply:()Ljava/util/function/Function;
// 调用 LambdaMetafactory.metafactory() 动态生成实现类
// 优势:
// 1. 不生成额外.class文件(匿名内部类会生成 Outer$1.class)
// 2. JVM可缓存Lambda实例(无捕获变量时单例复用)
// 3. 未来可优化为内联(性能更好)
java
// 验证:无捕获Lambda的实例复用
Function<Integer, Integer> f1 = x -> x + 1;
Function<Integer, Integer> f2 = x -> x + 1;
System.out.println(f1 == f2); // true(JVM缓存了同一实例)
// 有捕获变量则每次创建新实例
int offset = 10;
Function<Integer, Integer> f3 = x -> x + offset;
Function<Integer, Integer> f4 = x -> x + offset;
System.out.println(f3 == f4); // false(捕获了不同上下文)
2.4 this指向
java
public class ThisDemo {
private String name = "outer";
public void test() {
// 匿名内部类:this指向匿名类自身
Runnable anonymous = new Runnable() {
@Override
public void run() {
// this.name → 匿名类的name(无此字段则编译错误)
}
};
// Lambda:this指向外围类实例
Runnable lambda = () -> {
System.out.println(this.name); // "outer" --- 指向ThisDemo实例
};
lambda.run();
}
}
3. 函数式接口体系
3.1 @FunctionalInterface 注解
java
@FunctionalInterface // 编译期检查:必须有且仅有一个抽象方法
public interface Function<T, R> {
R apply(T t); // 唯一的抽象方法
// 以下不影响函数式接口判定:
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { ... }
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { ... }
static <T> Function<T, T> identity() { return t -> t; }
}
// 自定义函数式接口
@FunctionalInterface
interface TriFunction<A, B, C, R> {
R apply(A a, B b, C c);
}
// 使用
TriFunction<Integer, Integer, Integer, Integer> sum3 = (a, b, c) -> a + b + c;
System.out.println(sum3.apply(1, 2, 3)); // 6
3.2 核心四接口详解
java
import java.util.function.*;
public class CoreInterfacesDemo {
public static void main(String[] args) {
// Function<T, R>:T → R 转换
Function<String, Integer> strLen = s -> s.length();
Function<Integer, String> intToStr = i -> "num:" + i;
System.out.println(strLen.apply("hello")); // 5
// Predicate<T>:T → boolean 判断
Predicate<String> notEmpty = s -> !s.isEmpty();
Predicate<String> longStr = s -> s.length() > 5;
System.out.println(notEmpty.and(longStr).test("hello world")); // true
// Supplier<T>:() → T 供给
Supplier<Double> random = Math::random;
Supplier<List<String>> listFactory = ArrayList::new;
System.out.println(random.get()); // 0.xxx
// Consumer<T>:T → void 消费
Consumer<String> print = System.out::println;
Consumer<String> log = s -> System.err.println("[LOG] " + s);
print.andThen(log).accept("hello"); // 先print后log
}
}
3.3 Operator系列
java
// UnaryOperator<T>:T → T(Function<T,T>的特化)
UnaryOperator<String> upper = String::toUpperCase;
System.out.println(upper.apply("hello")); // "HELLO"
// BinaryOperator<T>:(T, T) → T(BiFunction<T,T,T>的特化)
BinaryOperator<Integer> sum = Integer::sum;
System.out.println(sum.apply(3, 7)); // 10
// 静态工厂:按比较器取最大/最小
BinaryOperator<String> longest = BinaryOperator.maxBy(Comparator.comparingInt(String::length));
System.out.println(longest.apply("hi", "hello")); // "hello"
// reduce中的典型使用
int total = Stream.of(1, 2, 3, 4, 5)
.reduce(0, Integer::sum); // BinaryOperator作为累加器
System.out.println(total); // 15
3.4 原始类型特化接口
java
// 避免自动装箱的性能开销
// 错误示范:Function<Integer, Integer> 每次调用都装箱/拆箱
Function<Integer, Integer> boxed = x -> x * 2;
// 正确示范:使用原始类型特化
IntUnaryOperator unboxed = x -> x * 2; // 无装箱
IntPredicate isPositive = x -> x > 0;
IntSupplier dice = () -> (int)(Math.random() * 6) + 1;
ToIntFunction<String> length = String::length;
IntBinaryOperator max = Integer::max;
// Stream中也应使用原始类型流
int sum = IntStream.rangeClosed(1, 100)
.filter(x -> x % 2 == 0)
.sum(); // 无装箱,性能更好
// 对比:Stream<Integer>.mapToInt().sum() 有装箱开销
3.5 java.util.function 完整接口清单
| 接口 | 抽象方法 | 语义 |
|---|---|---|
Function<T,R> |
R apply(T) |
转换 |
BiFunction<T,U,R> |
R apply(T,U) |
双参转换 |
Predicate<T> |
boolean test(T) |
判断 |
BiPredicate<T,U> |
boolean test(T,U) |
双参判断 |
Supplier<T> |
T get() |
供给 |
Consumer<T> |
void accept(T) |
消费 |
BiConsumer<T,U> |
void accept(T,U) |
双参消费 |
UnaryOperator<T> |
T apply(T) |
一元运算 |
BinaryOperator<T> |
T apply(T,T) |
二元运算 |
ToIntFunction<T> |
int applyAsInt(T) |
转int |
ToLongFunction<T> |
long applyAsLong(T) |
转long |
ToDoubleFunction<T> |
double applyAsDouble(T) |
转double |
IntFunction<R> |
R apply(int) |
int转R |
LongFunction<R> |
R apply(long) |
long转R |
DoubleFunction<R> |
R apply(double) |
double转R |
IntPredicate |
boolean test(int) |
int判断 |
LongPredicate |
boolean test(long) |
long判断 |
DoublePredicate |
boolean test(double) |
double判断 |
IntSupplier |
int getAsInt() |
供给int |
LongSupplier |
long getAsLong() |
供给long |
DoubleSupplier |
double getAsDouble() |
供给double |
IntConsumer |
void accept(int) |
消费int |
LongConsumer |
void accept(long) |
消费long |
DoubleConsumer |
void accept(double) |
消费double |
IntUnaryOperator |
int applyAsInt(int) |
int一元 |
LongUnaryOperator |
long applyAsLong(long) |
long一元 |
DoubleUnaryOperator |
double applyAsDouble(double) |
double一元 |
IntBinaryOperator |
int applyAsInt(int,int) |
int二元 |
LongBinaryOperator |
long applyAsLong(long,long) |
long二元 |
DoubleBinaryOperator |
double applyAsDouble(double,double) |
double二元 |
ToIntBiFunction<T,U> |
int applyAsInt(T,U) |
双参转int |
ToLongBiFunction<T,U> |
long applyAsLong(T,U) |
双参转long |
ToDoubleBiFunction<T,U> |
double applyAsDouble(T,U) |
双参转double |
IntToLongFunction |
long applyAsLong(int) |
int转long |
IntToDoubleFunction |
double applyAsDouble(int) |
int转double |
LongToIntFunction |
int applyAsInt(long) |
long转int |
LongToDoubleFunction |
double applyAsDouble(long) |
long转double |
DoubleToIntFunction |
int applyAsInt(double) |
double转int |
DoubleToLongFunction |
long applyAsLong(double) |
double转long |
ObjIntConsumer<T> |
void accept(T,int) |
对象+int消费 |
ObjLongConsumer<T> |
void accept(T,long) |
对象+long消费 |
ObjDoubleConsumer<T> |
void accept(T,double) |
对象+double消费 |
BooleanSupplier |
boolean getAsBoolean() |
供给boolean |
4. 方法引用
4.1 四种方法引用
java
import java.util.*;
import java.util.function.*;
public class MethodReferenceDemo {
public static void main(String[] args) {
// 1. 静态方法引用:ClassName::staticMethod
Function<String, Integer> parseInt = Integer::parseInt;
// 等价于: s -> Integer.parseInt(s)
System.out.println(parseInt.apply("42")); // 42
BiFunction<Integer, Integer, Integer> maxFn = Math::max;
// 等价于: (a, b) -> Math.max(a, b)
// 2. 实例方法引用(任意对象):ClassName::instanceMethod
// 第一个参数作为方法调用者
Function<String, String> upper = String::toUpperCase;
// 等价于: s -> s.toUpperCase()
Comparator<String> cmp = String::compareToIgnoreCase;
// 等价于: (s1, s2) -> s1.compareToIgnoreCase(s2)
// 3. 特定对象的方法引用:instance::method
List<String> list = new ArrayList<>();
Consumer<String> add = list::add;
// 等价于: s -> list.add(s)
add.accept("hello");
System.out.println(list); // [hello]
String prefix = ">>";
Function<String, String> concat = prefix::concat;
// 等价于: s -> prefix.concat(s)
// 4. 构造器引用:ClassName::new
Supplier<ArrayList<String>> factory = ArrayList::new;
// 等价于: () -> new ArrayList<>()
Function<Integer, int[]> arrayFactory = int[]::new;
// 等价于: n -> new int[n]
int[] arr = arrayFactory.apply(5);
System.out.println(arr.length); // 5
}
}
4.2 构造器引用进阶
java
// 多参数构造器引用
class Person {
String name;
int age;
Person(String name, int age) { this.name = name; this.age = age; }
Person(String name) { this(name, 0); }
}
// 根据函数式接口的方法签名自动匹配构造器
Supplier<Person> s1 = Person::new; // () -> new Person() --- 无此构造器会报错
Function<String, Person> s2 = Person::new; // name -> new Person(name)
BiFunction<String, Integer, Person> s3 = Person::new; // (name, age) -> new Person(name, age)
// 集合创建中的典型应用
List<Person> people = Stream.of("Alice", "Bob", "Charlie")
.map(Person::new) // 调用 Person(String) 构造器
.collect(Collectors.toList());
// toArray中的构造器引用
Person[] arr = people.stream().toArray(Person[]::new);
4.3 方法引用与Lambda的选择
java
// 优先使用方法引用(更简洁)
list.forEach(System.out::println); // 优于: x -> System.out.println(x)
list.sort(Comparator.naturalOrder()); // 优于: (a, b) -> a.compareTo(b)
stream.map(String::toUpperCase); // 优于: s -> s.toUpperCase()
// 必须用Lambda的场景
stream.map(s -> s.substring(1, 3)); // 方法引用无法表达部分参数绑定
stream.filter(s -> s.length() > 3 && s.startsWith("A")); // 复合逻辑
stream.reduce(0, (a, b) -> a + b * b); // 自定义计算逻辑
5. Stream API完整操作
5.1 Stream创建
java
import java.util.stream.*;
import java.util.*;
import java.nio.file.*;
public class StreamCreation {
public static void main(String[] args) throws Exception {
// 1. 集合创建
List<String> list = List.of("a", "b", "c");
Stream<String> s1 = list.stream();
Stream<String> s2 = list.parallelStream();
// 2. 数组创建
String[] arr = {"x", "y", "z"};
Stream<String> s3 = Arrays.stream(arr);
Stream<String> s4 = Stream.of("a", "b", "c");
// 3. 无限流
Stream<Double> randoms = Stream.generate(Math::random);
Stream<Integer> naturals = Stream.iterate(1, n -> n + 1);
// JDK9: 带终止条件的iterate
Stream<Integer> evens = Stream.iterate(0, n -> n < 100, n -> n + 2);
// 4. 范围流(原始类型)
IntStream range = IntStream.range(1, 10); // [1, 10)
IntStream rangeClosed = IntStream.rangeClosed(1, 10); // [1, 10]
// 5. 合并流
Stream<String> combined = Stream.concat(list.stream(), Stream.of("d", "e"));
// 6. 空流 / 单元素流
Stream<String> empty = Stream.empty();
Stream<String> single = Stream.of("only");
Stream<String> nullable = Stream.ofNullable(getMaybeNull()); // JDK9
// 7. 其他来源
// BufferedReader.lines()
// Pattern.splitAsStream("a,b,c")
// Files.walk(Paths.get("."))
// "hello".chars() → IntStream
}
static String getMaybeNull() { return Math.random() > 0.5 ? "value" : null; }
}
5.2 中间操作
java
public class IntermediateOps {
public static void main(String[] args) {
List<String> words = List.of("hello", "world", "hi", "java", "stream", "hello");
// filter:过滤
words.stream().filter(s -> s.length() > 4).forEach(System.out::println);
// map:一对一转换
words.stream().map(String::length).forEach(System.out::println);
// flatMap:一对多转换(展平)
List<List<Integer>> nested = List.of(List.of(1, 2), List.of(3, 4), List.of(5));
List<Integer> flat = nested.stream()
.flatMap(Collection::stream) // List<List<T>> → Stream<T>
.collect(Collectors.toList()); // [1, 2, 3, 4, 5]
// distinct:去重(基于equals)
words.stream().distinct().forEach(System.out::println);
// sorted:排序
words.stream().sorted(Comparator.comparingInt(String::length)).forEach(System.out::println);
// peek:调试(不改变流)
words.stream()
.peek(s -> System.out.println("before: " + s))
.map(String::toUpperCase)
.peek(s -> System.out.println("after: " + s))
.collect(Collectors.toList());
// limit / skip:截取
Stream.iterate(1, i -> i + 1).limit(10).forEach(System.out::println); // 1-10
words.stream().skip(2).forEach(System.out::println); // 跳过前2个
// mapToInt / mapToLong / mapToDouble:转原始类型流
int totalLen = words.stream().mapToInt(String::length).sum();
}
}
5.3 终端操作
java
public class TerminalOps {
public static void main(String[] args) {
List<Integer> nums = List.of(3, 1, 4, 1, 5, 9, 2, 6);
// forEach / forEachOrdered
nums.stream().forEach(System.out::println); // 并行时无序
nums.stream().forEachOrdered(System.out::println); // 保证顺序
// collect:收集为集合
List<Integer> evens = nums.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());
Set<Integer> unique = nums.stream().collect(Collectors.toSet());
Map<Integer, String> map = nums.stream()
.distinct()
.collect(Collectors.toMap(n -> n, n -> "val" + n));
// reduce:归约
int sum = nums.stream().reduce(0, Integer::sum);
Optional<Integer> max = nums.stream().reduce(Integer::max);
String joined = nums.stream().map(String::valueOf).reduce("", (a, b) -> a + "," + b);
// count / min / max
long count = nums.stream().filter(n -> n > 3).count();
Optional<Integer> min = nums.stream().min(Comparator.naturalOrder());
Optional<Integer> maxVal = nums.stream().max(Comparator.naturalOrder());
// 匹配操作
boolean any = nums.stream().anyMatch(n -> n > 8); // true
boolean all = nums.stream().allMatch(n -> n > 0); // true
boolean none = nums.stream().noneMatch(n -> n > 10); // true
// 查找操作
Optional<Integer> first = nums.stream().findFirst(); // Optional[3]
Optional<Integer> anyOne = nums.parallelStream().findAny(); // 并行时不确定
// toArray
Integer[] arr = nums.stream().toArray(Integer[]::new);
int[] primitive = nums.stream().mapToInt(Integer::intValue).toArray();
}
}
5.4 flatMap 深入
java
// flatMap:将每个元素映射为一个流,然后展平合并
// 典型场景:
// 1. 字符串拆分为字符流
List<String> chars = Stream.of("hello", "world")
.flatMap(s -> s.chars().mapToObj(c -> String.valueOf((char) c)))
.distinct()
.collect(Collectors.toList());
// 2. 多条件查询结果合并
List<Order> allOrders = customers.stream()
.flatMap(customer -> customer.getOrders().stream())
.filter(order -> order.getAmount() > 100)
.collect(Collectors.toList());
// 3. 笛卡尔积
List<int[]> cartesian = IntStream.rangeClosed(1, 6).boxed()
.flatMap(a -> IntStream.rangeClosed(1, 6)
.mapToObj(b -> new int[]{a, b}))
.collect(Collectors.toList());
// 4. Optional展平(避免嵌套)
Stream<Optional<String>> optStream = Stream.of(
Optional.of("a"), Optional.empty(), Optional.of("b"));
List<String> values = optStream
.flatMap(Optional::stream) // JDK9: Optional.stream()
.collect(Collectors.toList()); // [a, b]
6. Stream内部原理
6.1 Pipeline架构
Stream 采用管道(Pipeline) 模式,由多个阶段(Stage)组成:
数据源 → [Stage1: filter] → [Stage2: map] → [Stage3: sorted] → 终端操作
Head 中间操作节点 中间操作节点 中间操作节点 触发执行
java
// 源码结构(简化)
// AbstractPipeline 是所有Stage的基类
class ReferencePipeline<T> extends AbstractPipeline<T, Stream<T>> {
// Head节点:持有数据源Spliterator
// 后续节点:通过sourceStage和previousStage链接
// 中间操作:创建新Stage并链接
public final Stream<T> filter(Predicate<? super T> predicate) {
return new StatelessOp<>(this, ...) {
@Override
Sink<T> opWrapSink(int flags, Sink<T> downstream) {
return new Sink.ChainedReference<>(downstream) {
@Override
public void accept(T t) {
if (predicate.test(t)) {
downstream.accept(t); // 满足条件才传递
}
}
};
}
};
}
// 终端操作:包装Sink链 + 驱动Spliterator
public final void forEach(Consumer<? super T> action) {
evaluate(ForEachOps.makeSink(action));
}
}
6.2 Sink链与执行流程
java
// 执行时的调用链(以 filter + map + forEach 为例):
// 1. 终端操作触发 → 从最后一个Stage向前包装Sink链
// 2. Sink链:forEach.sink ← map.sink ← filter.sink
// 3. Spliterator.forEachRemaining 驱动数据流过Sink链
// 伪代码:
Spliterator<T> spliterator = source.spliterator();
Sink<T> chain = terminalSink; // forEach的Sink
chain = mapOp.wrapSink(chain); // 包装map
chain = filterOp.wrapSink(chain); // 包装filter
// 每个元素的处理:
// spliterator.tryAdvance(element -> {
// filterSink.accept(element); → 判断 → mapSink.accept → forEachSink.accept
// });
6.3 Spliterator(可拆分迭代器)
java
// Spliterator是并行流的基础
public interface Spliterator<T> {
boolean tryAdvance(Consumer<? super T> action); // 消费一个元素
Spliterator<T> trySplit(); // 拆分为两半(返回前半,保留后半)
long estimateSize(); // 估算剩余元素数
int characteristics(); // 特征标志
}
// 特征常量:
// ORDERED --- 有序(List)
// SORTED --- 已排序
// SIZED --- 已知确切大小(ArrayList)
// SUBSIZED --- 子拆分也已知大小
// DISTINCT --- 无重复
// NONNULL --- 无null
// IMMUTABLE --- 不可变
// 手动使用Spliterator
List<String> data = List.of("a", "b", "c", "d", "e");
Spliterator<String> sp = data.spliterator();
Spliterator<String> half = sp.trySplit(); // 拆分
half.forEachRemaining(s -> System.out.print(s + " ")); // a b
System.out.println();
sp.forEachRemaining(s -> System.out.print(s + " ")); // c d e
6.4 惰性求值验证
java
// 中间操作是惰性的:不调用终端操作则不执行
List<String> result = Stream.of("one", "two", "three")
.filter(s -> {
System.out.println("filter: " + s); // 不会打印!
return s.length() > 3;
})
.map(s -> {
System.out.println("map: " + s); // 不会打印!
return s.toUpperCase();
})
.collect(Collectors.toList());
// 只有collect触发时才打印
// 短路操作优化:findFirst只处理到第一个满足条件的元素
Optional<String> first = Stream.of("a", "bb", "ccc", "dddd")
.filter(s -> {
System.out.println("checking: " + s);
return s.length() > 2;
})
.findFirst();
// 输出: checking: a → checking: bb → checking: ccc(找到即停止)
7. Collector自定义
7.1 Collector接口五要素
java
public interface Collector<T, A, R> {
Supplier<A> supplier(); // 创建累加容器
BiConsumer<A, T> accumulator(); // 将元素加入容器
BinaryOperator<A> combiner(); // 合并两个容器(并行流)
Function<A, R> finisher(); // 最终转换
Set<Characteristics> characteristics(); // 特征
}
// Characteristics:
// CONCURRENT --- 容器线程安全,可多线程累加
// UNORDERED --- 结果不受元素顺序影响
// IDENTITY_FINISH --- finisher是恒等函数(A即R,可跳过finisher)
7.2 Collector.of 自定义
java
import java.util.stream.Collector;
import java.util.*;
public class CustomCollectorDemo {
// 示例1:收集为不可变List
public static <T> Collector<T, ?, List<T>> toImmutableList() {
return Collector.of(
ArrayList::new, // supplier
List::add, // accumulator
(left, right) -> { // combiner
left.addAll(right);
return left;
},
Collections::unmodifiableList, // finisher
Collector.Characteristics.UNORDERED
);
}
// 示例2:字符串统计收集器
record StringStats(int count, int totalLength, String longest) {}
public static Collector<String, ?, StringStats> toStringStats() {
// 使用可变累加器
class Acc {
int count = 0;
int totalLength = 0;
String longest = "";
}
return Collector.of(
Acc::new,
(acc, s) -> {
acc.count++;
acc.totalLength += s.length();
if (s.length() > acc.longest.length()) acc.longest = s;
},
(a1, a2) -> {
a1.count += a2.count;
a1.totalLength += a2.totalLength;
if (a2.longest.length() > a1.longest.length()) a1.longest = a2.longest;
return a1;
},
acc -> new StringStats(acc.count, acc.totalLength, acc.longest)
);
}
// 示例3:分组+自定义下游
public static void main(String[] args) {
List<String> words = List.of("hi", "hello", "hey", "world", "java", "joy");
// 使用自定义收集器
StringStats stats = words.stream().collect(toStringStats());
System.out.println(stats); // StringStats[count=6, totalLength=24, longest=hello]
// 按首字母分组,值为不可变List
Map<Character, List<String>> grouped = words.stream()
.collect(Collectors.groupingBy(
s -> s.charAt(0),
toImmutableList()
));
System.out.println(grouped);
}
}
7.3 Collectors工具类常用方法
java
List<Employee> employees = getEmployees();
// 归约
List<String> names = employees.stream()
.map(Employee::getName)
.collect(Collectors.toList());
// JDK10+: 不可变集合
List<String> immutable = employees.stream()
.map(Employee::getName)
.collect(Collectors.toUnmodifiableList());
// toMap(注意key重复会抛异常)
Map<Long, Employee> byId = employees.stream()
.collect(Collectors.toMap(Employee::getId, Function.identity()));
// key重复处理
Map<String, List<Employee>> byDept = employees.stream()
.collect(Collectors.toMap(
Employee::getDept,
e -> List.of(e),
(list1, list2) -> { // merge function
List<Employee> merged = new ArrayList<>(list1);
merged.addAll(list2);
return merged;
}
));
// 分组
Map<String, List<Employee>> grouped = employees.stream()
.collect(Collectors.groupingBy(Employee::getDept));
// 多级分组
Map<String, Map<Integer, List<Employee>>> multi = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDept,
Collectors.groupingBy(Employee::getLevel)
));
// 分区(boolean分组)
Map<Boolean, List<Employee>> partition = employees.stream()
.collect(Collectors.partitioningBy(e -> e.getSalary() > 10000));
// 字符串拼接
String joined = employees.stream()
.map(Employee::getName)
.collect(Collectors.joining(", ", "[", "]")); // [Alice, Bob, Charlie]
// 统计
IntSummaryStatistics summary = employees.stream()
.collect(Collectors.summarizingInt(Employee::getAge));
// summary.getAverage(), getMax(), getMin(), getSum(), getCount()
// teeing(JDK12):双路收集
record AvgAndMax(double avg, int max) {}
AvgAndMax result = employees.stream()
.collect(Collectors.teeing(
Collectors.averagingInt(Employee::getSalary), // 第一路
Collectors.maxBy(Comparator.comparingInt(Employee::getSalary)), // 第二路
(avg, maxOpt) -> new AvgAndMax(avg, maxOpt.map(Employee::getSalary).orElse(0))
));
8. 并行流原理与ForkJoinPool
8.1 并行流基础
java
// 创建并行流
List<Integer> data = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 方式1:parallelStream()
long sum1 = data.parallelStream().mapToLong(Integer::longValue).sum();
// 方式2:parallel()切换
long sum2 = data.stream().parallel().mapToLong(Integer::longValue).sum();
// parallel/sequential可切换(最后一次调用生效)
long sum3 = data.stream()
.parallel() // 并行
.filter(n -> n > 3)
.sequential() // 切回串行
.mapToLong(Integer::longValue)
.sum();
8.2 ForkJoinPool与Work-Stealing
java
// 并行流默认使用 ForkJoinPool.commonPool()
// 线程数 = Runtime.getRuntime().availableProcessors() - 1
// 查看公共池信息
ForkJoinPool pool = ForkJoinPool.commonPool();
System.out.println("并行度: " + pool.getParallelism());
System.out.println("活跃线程: " + pool.getActiveThreadCount());
// 自定义ForkJoinPool(隔离IO密集型任务)
ForkJoinPool customPool = new ForkJoinPool(16);
try {
long result = customPool.submit(() ->
data.parallelStream()
.mapToLong(this::expensiveComputation)
.sum()
).get();
} finally {
customPool.shutdown();
}
// Work-Stealing算法:
// 每个线程有自己的双端队列(deque)
// 线程从自己队列头部取任务(LIFO)
// 空闲线程从其他线程队列尾部偷任务(FIFO)
// 减少竞争,提高CPU利用率
8.3 并行流适用性分析
java
// 适合并行流的场景
// 1. 数据量大 + CPU密集计算
long result = LongStream.rangeClosed(1, 10_000_000)
.parallel()
.filter(this::isPrime)
.count();
// 2. 数据源易拆分(ArrayList、数组、IntStream.range)
// SIZED + SUBSIZED 特征 → 精确二分
// 不适合并行流的场景
// 1. 数据量小(线程调度开销 > 计算收益)
List.of(1, 2, 3).parallelStream().map(x -> x * 2); // 无意义
// 2. 数据源难拆分(LinkedList、IO流)
// LinkedList的Spliterator无法高效二分
// 3. 有共享可变状态
List<Integer> unsafe = new ArrayList<>(); // 非线程安全!
data.parallelStream().forEach(unsafe::add); // 可能丢失数据!
// 正确做法:collect
List<Integer> safe = data.parallelStream().collect(Collectors.toList());
// 4. 有状态中间操作(sorted、distinct需要屏障)
// sorted在并行时需要等所有元素到达才能排序
// 5. IO操作(会阻塞公共池线程)
data.parallelStream().forEach(this::httpCall); // 会阻塞其他并行流!
8.4 并行流注意事项
java
// 1. 顺序保证
List<Integer> ordered = data.parallelStream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList()); // collect保证遇到顺序
data.parallelStream().forEach(System.out::println); // 无序
data.parallelStream().forEachOrdered(System.out::println); // 有序(牺牲并行性)
// 2. findFirst vs findAny
Optional<Integer> first = data.parallelStream().findFirst(); // 保证第一个(代价高)
Optional<Integer> any = data.parallelStream().findAny(); // 任意一个(更高效)
// 3. 避免公共池污染
// 所有parallelStream共享commonPool
// 如果一个流执行阻塞IO,会影响所有其他并行流
// 解决:使用自定义ForkJoinPool或CompletableFuture
// 4. 性能基准
// 数据量 < 10,000:串行通常更快
// 数据量 > 100,000 + CPU密集:并行有明显收益
// 使用JMH进行基准测试,不要凭直觉
9. Optional正确使用
9.1 创建与基本操作
java
// 创建
Optional<String> opt1 = Optional.of("hello"); // 非null
Optional<String> opt2 = Optional.ofNullable(null); // 允许null → empty
Optional<String> opt3 = Optional.empty(); // 空
// 判断
opt1.isPresent(); // true(JDK8风格,不推荐)
opt1.isEmpty(); // false(JDK11+)
// 取值
String v1 = opt1.get(); // 有值返回值,无值抛NoSuchElementException
String v2 = opt2.orElse("default"); // 无值返回默认值(立即求值)
String v3 = opt2.orElseGet(() -> compute()); // 无值时惰性计算(推荐)
String v4 = opt2.orElseThrow(); // 无值抛NoSuchElementException(JDK10+)
String v5 = opt2.orElseThrow(() -> new CustomException("not found"));
9.2 链式转换
java
// map:转换值(自动包装为Optional)
Optional<Integer> length = Optional.of("hello")
.map(String::length); // Optional[5]
// flatMap:避免嵌套Optional
Optional<String> city = getUser(id) // Optional<User>
.flatMap(User::getAddress) // Optional<Address>(getAddress返回Optional)
.flatMap(Address::getCity); // Optional<String>
// filter:条件过滤
Optional<String> result = Optional.of("hello")
.filter(s -> s.length() > 3) // 满足 → 保留
.filter(s -> s.startsWith("h")) // 满足 → 保留
.map(String::toUpperCase); // Optional[HELLO]
// JDK9: or --- 链式备选
Optional<String> value = findInCache(key)
.or(() -> findInDatabase(key)) // 缓存没有则查数据库
.or(() -> findInRemote(key)); // 数据库没有则查远程
// JDK9: stream --- 转为Stream
List<String> values = optionals.stream()
.flatMap(Optional::stream) // Optional<T> → Stream<T>(0或1个元素)
.collect(Collectors.toList());
9.3 最佳实践
java
// 正确:作为方法返回值
public Optional<User> findById(Long id) {
User user = userRepository.find(id);
return Optional.ofNullable(user);
}
// 正确:链式处理
String cityName = findById(userId)
.flatMap(User::getAddress)
.map(Address::getCity)
.orElse("Unknown");
// 正确:ifPresent消费
findById(userId).ifPresent(user -> sendWelcomeEmail(user));
// JDK9: ifPresentOrElse
findById(userId).ifPresentOrElse(
user -> log.info("Found: {}", user),
() -> log.warn("User not found: {}", userId)
);
// 错误示范:
// 1. 不要用作字段(不可序列化)
class Bad { private Optional<String> name; } // 错误!
// 2. 不要用作方法参数(增加调用者负担)
void bad(Optional<String> name) { } // 错误!用重载代替
// 3. 不要 optional.get() 不判断
String val = opt.get(); // 危险!
// 4. 不要用于集合
Optional<List<String>> bad; // 错误!用空List代替
List<String> good = Collections.emptyList(); // 正确
// 5. 不要嵌套
Optional<Optional<String>> nested; // 错误!用flatMap
10. 函数组合
10.1 andThen与compose
java
Function<Integer, Integer> add1 = x -> x + 1;
Function<Integer, Integer> mul2 = x -> x * 2;
Function<Integer, String> toStr = x -> "result:" + x;
// andThen:先执行this,再执行参数 → g(f(x))
Function<Integer, String> pipeline = add1.andThen(mul2).andThen(toStr);
System.out.println(pipeline.apply(5)); // "result:12" → (5+1)*2=12
// compose:先执行参数,再执行this → f(g(x))
Function<Integer, Integer> composed = add1.compose(mul2); // add1(mul2(x))
System.out.println(composed.apply(5)); // 11 → (5*2)+1=11
// Predicate组合
Predicate<String> notEmpty = s -> !s.isEmpty();
Predicate<String> notTooLong = s -> s.length() < 100;
Predicate<String> valid = notEmpty.and(notTooLong).negate(); // 非(非空且不太长)
// Consumer组合
Consumer<String> log = s -> System.out.println("[LOG] " + s);
Consumer<String> save = s -> System.out.println("[SAVE] " + s);
Consumer<String> process = log.andThen(save); // 先日志后保存
process.accept("data");
10.2 柯里化(Currying)
java
// 柯里化:将多参数函数转换为一系列单参数函数
// f(x, y) → f(x)(y)
// 未柯里化
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
System.out.println(add.apply(3, 5)); // 8
// 柯里化
Function<Integer, Function<Integer, Integer>> curriedAdd =
a -> b -> a + b;
System.out.println(curriedAdd.apply(3).apply(5)); // 8
// 偏函数应用(Partial Application)
Function<Integer, Integer> add10 = curriedAdd.apply(10);
System.out.println(add10.apply(5)); // 15
System.out.println(add10.apply(20)); // 30
// 实用示例:配置生成器
Function<String, Function<String, Function<Integer, String>>> formatter =
prefix -> suffix -> width ->
prefix + " " + "x".repeat(width) + " " + suffix;
Function<String, Function<Integer, String>> bracket = formatter.apply("[");
Function<Integer, String> bracketDash = bracket.apply("]");
System.out.println(bracketDash.apply(5)); // "[ xxxxx ]"
// 通用柯里化工具
public static <A, B, C> Function<A, Function<B, C>> curry(BiFunction<A, B, C> f) {
return a -> b -> f.apply(a, b);
}
// 使用
Function<String, Function<String, String>> curriedConcat = curry((a, b) -> a + b);
10.3 函数式管道(Pipeline)
java
// 构建可组合的处理管道
public class PipelineDemo {
// 字符串处理管道
public static void main(String[] args) {
Function<String, String> trim = String::trim;
Function<String, String> toLower = String::toLowerCase;
Function<String, String> removeSpaces = s -> s.replaceAll("\\s+", "");
Function<String, String> addHash = s -> "#" + s;
// 组合管道
Function<String, String> process = trim
.andThen(toLower)
.andThen(removeSpaces)
.andThen(addHash);
System.out.println(process.apply(" Hello World ")); // "#helloworld"
// 动态构建管道
List<Function<String, String>> steps = List.of(trim, toLower, removeSpaces);
Function<String, String> dynamic = steps.stream()
.reduce(Function.identity(), Function::andThen);
System.out.println(dynamic.apply(" Java FP ")); // "javafp"
}
}
11. 函数式异常处理
11.1 问题:函数式接口不支持受检异常
java
// 编译错误:Function.apply()没有throws声明
// Function<String, Class<?>> f = s -> Class.forName(s); // 编译失败!
// 笨办法:每个Lambda中try-catch
Function<String, Class<?>> ugly = s -> {
try {
return Class.forName(s);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
};
11.2 方案一:包装函数
java
@FunctionalInterface
interface CheckedFunction<T, R> {
R apply(T t) throws Exception;
}
// 包装方法:将受检异常转为运行时异常
public static <T, R> Function<T, R> unchecked(CheckedFunction<T, R> f) {
return t -> {
try {
return f.apply(t);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
// 使用
List<Class<?>> classes = Stream.of("java.lang.String", "java.lang.Integer")
.map(unchecked(Class::forName))
.collect(Collectors.toList());
// 带异常处理的包装
public static <T, R> Function<T, R> handling(
CheckedFunction<T, R> f,
Function<Exception, R> handler) {
return t -> {
try {
return f.apply(t);
} catch (Exception e) {
return handler.apply(e);
}
};
}
// 使用:异常时返回null
Stream.of("java.lang.String", "invalid.Class")
.map(handling(Class::forName, e -> null))
.filter(Objects::nonNull)
.forEach(System.out::println);
11.3 方案二:Try模式
java
// 简化版Try(类似Vavr)
public sealed interface Try<T> permits Success, Failure {
static <T> Try<T> of(CheckedSupplier<T> supplier) {
try {
return new Success<>(supplier.get());
} catch (Exception e) {
return new Failure<>(e);
}
}
<U> Try<U> map(Function<T, U> f);
<U> Try<U> flatMap(Function<T, Try<U>> f);
T getOrElse(T defaultValue);
Try<T> recover(Function<Exception, T> handler);
boolean isSuccess();
}
record Success<T>(T value) implements Try<T> {
@Override
public <U> Try<U> map(Function<T, U> f) {
return Try.of(() -> f.apply(value));
}
@Override
public <U> Try<U> flatMap(Function<T, Try<U>> f) {
try { return f.apply(value); }
catch (Exception e) { return new Failure<>(e); }
}
@Override
public T getOrElse(T defaultValue) { return value; }
@Override
public Try<T> recover(Function<Exception, T> handler) { return this; }
@Override
public boolean isSuccess() { return true; }
}
record Failure<T>(Exception exception) implements Try<T> {
@Override
public <U> Try<U> map(Function<T, U> f) { return new Failure<>(exception); }
@Override
public <U> Try<U> flatMap(Function<T, Try<U>> f) { return new Failure<>(exception); }
@Override
public T getOrElse(T defaultValue) { return defaultValue; }
@Override
public Try<T> recover(Function<Exception, T> handler) {
return Try.of(() -> handler.apply(exception));
}
@Override
public boolean isSuccess() { return false; }
}
@FunctionalInterface
interface CheckedSupplier<T> { T get() throws Exception; }
// 使用
Try<Integer> result = Try.of(() -> Integer.parseInt("abc"))
.map(n -> n * 2)
.recover(e -> -1);
System.out.println(result.getOrElse(0)); // -1
11.4 方案三:Stream中安全处理
java
// 将异常元素转为Optional/Stream,用flatMap过滤
public static <T, R> Function<T, Stream<R>> safeMap(CheckedFunction<T, R> f) {
return t -> {
try {
return Stream.of(f.apply(t));
} catch (Exception e) {
return Stream.empty(); // 异常元素被跳过
}
};
}
// 使用:安全解析数字
List<Integer> numbers = Stream.of("1", "abc", "3", "def", "5")
.flatMap(safeMap(Integer::parseInt))
.collect(Collectors.toList()); // [1, 3, 5]
// 带日志的版本
public static <T, R> Function<T, Stream<R>> safeMapWithLog(
CheckedFunction<T, R> f, String operation) {
return t -> {
try {
return Stream.of(f.apply(t));
} catch (Exception e) {
System.err.printf("[%s] Failed for input '%s': %s%n", operation, t, e.getMessage());
return Stream.empty();
}
};
}
12. 函数式编程在Spring/框架中的应用
12.1 Spring Framework
java
// 1. JdbcTemplate --- Function作为RowMapper
List<User> users = jdbcTemplate.query(
"SELECT * FROM users WHERE age > ?",
(rs, rowNum) -> new User( // RowMapper是函数式接口
rs.getLong("id"),
rs.getString("name"),
rs.getInt("age")
),
18
);
// 2. RestTemplate --- 函数式回调
String result = restTemplate.execute(url, HttpMethod.GET,
request -> request.getHeaders().set("X-Token", token), // RequestCallback
response -> new String(response.getBody().readAllBytes()) // ResponseExtractor
);
// 3. WebClient(WebFlux)--- 完全函数式链
Mono<User> user = webClient.get()
.uri("/users/{id}", id)
.retrieve()
.bodyToMono(User.class)
.flatMap(u -> enrichUser(u)) // 函数组合
.onErrorReturn(User.DEFAULT); // 函数式异常处理
// 4. Spring Cloud Stream --- Function Bean
@Bean
public Function<String, String> uppercase() {
return value -> value.toUpperCase();
}
@Bean
public Consumer<OrderEvent> orderProcessor() {
return event -> processOrder(event);
}
@Bean
public Supplier<List<Product>> productSource() {
return () -> productRepository.findAll();
}
// 5. 事件驱动
@Component
public class EventHandlers {
@EventListener
public void onUserCreated(UserCreatedEvent event) {
sendWelcomeEmail(event.getUser());
}
}
// 6. Spring WebFlux 函数式路由(RouterFunction)
@Bean
public RouterFunction<ServerResponse> routes(UserHandler handler) {
return RouterFunctions.route()
.GET("/users", handler::listUsers)
.GET("/users/{id}", handler::getUser)
.POST("/users", handler::createUser)
.filter((request, next) -> { // 函数式过滤器
log.info("Request: {}", request.path());
return next.handle(request);
})
.build();
}
12.2 MyBatis-Plus Lambda查询
java
// LambdaQueryWrapper:类型安全的函数式查询
List<User> users = userMapper.selectList(
new LambdaQueryWrapper<User>()
.eq(User::getStatus, 1) // 方法引用代替字符串列名
.ge(User::getAge, 18)
.like(User::getName, "张")
.orderByDesc(User::getCreateTime)
);
// 对比传统方式(字符串列名,重构不安全)
// wrapper.eq("status", 1).ge("age", 18)
// 函数式更新
userMapper.update(null,
new LambdaUpdateWrapper<User>()
.set(User::getStatus, 0)
.eq(User::getId, userId)
);
12.3 设计模式函数式化
java
// 策略模式 → Map<String, Function>
public class PriceCalculator {
private final Map<String, Function<Double, Double>> strategies = Map.of(
"VIP", price -> price * 0.8,
"NORMAL", price -> price * 0.95,
"NEW_USER", price -> price > 100 ? price - 20 : price
);
public double calculate(String type, double price) {
return strategies.getOrDefault(type, Function.identity()).apply(price);
}
}
// 模板方法 → 高阶函数
public class DataExporter {
// 传统:抽象类 + 子类重写
// 函数式:将变化部分作为参数传入
public <T> void export(List<T> data,
Function<T, String> formatter,
Consumer<String> writer) {
String header = buildHeader();
writer.accept(header);
data.stream()
.map(formatter)
.forEach(writer);
}
}
// 使用
exporter.export(users,
u -> String.format("%s,%d", u.getName(), u.getAge()), // 格式化策略
System.out::println // 输出策略
);
// 观察者模式 → Consumer列表
public class EventBus {
private final Map<Class<?>, List<Consumer<Object>>> listeners = new ConcurrentHashMap<>();
public <T> void subscribe(Class<T> eventType, Consumer<T> listener) {
listeners.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>())
.add((Consumer<Object>) listener);
}
public <T> void publish(T event) {
listeners.getOrDefault(event.getClass(), List.of())
.forEach(listener -> listener.accept(event));
}
}
13. Stream性能分析与最佳实践
13.1 性能对比
java
// 基准测试(概念性,实际应使用JMH)
List<Integer> data = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) data.add(i);
// 1. for循环
long sum = 0;
for (int i : data) { sum += i; }
// 2. Stream
long sum2 = data.stream().mapToLong(Integer::longValue).sum();
// 3. 并行Stream
long sum3 = data.parallelStream().mapToLong(Integer::longValue).sum();
// 结论(典型结果):
// 小数据(<1000):for > Stream > ParallelStream
// 大数据简单操作:for ≈ Stream,ParallelStream最快
// 大数据复杂操作:Stream ≈ for(JIT优化后)
// 链式操作越长,Stream优势越明显(代码可读性)
13.2 常见性能陷阱
java
// 1. 装箱开销
// 差:Stream<Integer> 每次操作都装箱
int sum = Stream.of(1, 2, 3, 4, 5)
.map(x -> x * 2) // Integer → Integer(装箱)
.reduce(0, Integer::sum);
// 好:使用IntStream
int sum = IntStream.of(1, 2, 3, 4, 5)
.map(x -> x * 2) // int → int(无装箱)
.sum();
// 2. flatMap产生中间集合
// 差:每个元素创建一个临时Stream
List<String> result = largeList.stream()
.flatMap(s -> Arrays.stream(s.split(","))) // 每次split创建数组
.collect(Collectors.toList());
// 3. sorted的代价(有状态操作,需缓存所有元素)
// 如果只需要前N个,考虑先filter再sorted再limit
List<String> top5 = data.stream()
.filter(this::isRelevant) // 先过滤减少数据量
.sorted(comparator) // 再排序
.limit(5) // 最后取前5
.collect(Collectors.toList());
// 4. Collectors.toMap key重复
// 会抛 IllegalStateException!
Map<String, User> map = users.stream()
.collect(Collectors.toMap(User::getName, Function.identity(),
(existing, replacement) -> existing)); // 必须提供merge函数
// 5. Stream只能消费一次
Stream<String> stream = list.stream().filter(s -> s.length() > 3);
stream.forEach(System.out::println);
// stream.forEach(System.out::println); // IllegalStateException!
13.3 最佳实践总结
java
// 1. 优先可读性
// 好:清晰的命名 + 方法引用
List<String> activeUserNames = users.stream()
.filter(User::isActive)
.map(User::getName)
.sorted()
.collect(Collectors.toList());
// 差:过长的Lambda
List<String> x = users.stream()
.filter(u -> u.getStatus() == 1 && u.getLastLogin() != null
&& u.getLastLogin().isAfter(Instant.now().minus(30, ChronoUnit.DAYS)))
.map(u -> u.getFirstName() + " " + u.getLastName())
.collect(Collectors.toList());
// 应拆分为命名方法:.filter(this::isRecentlyActive)
// 2. 避免副作用
// 差:
List<String> result = new ArrayList<>();
stream.forEach(s -> result.add(s.toUpperCase())); // 外部可变状态!
// 好:
List<String> result = stream.map(String::toUpperCase).collect(Collectors.toList());
// 3. 合理使用原始类型流
long total = orders.stream()
.mapToLong(Order::getAmount) // 转为LongStream
.sum();
// 4. 避免不必要的Stream
// 差:
Stream.of(singleValue).map(...).collect(...);
// 好:直接操作
String result = transform(singleValue);
// 5. 调试:使用peek
List<String> debug = data.stream()
.peek(s -> log.debug("input: {}", s))
.map(this::transform)
.peek(s -> log.debug("output: {}", s))
.filter(this::isValid)
.collect(Collectors.toList());
14. JDK 9-21函数式改进
14.1 JDK 9 改进
java
// 1. Stream.takeWhile / dropWhile
List<Integer> taken = Stream.of(1, 2, 3, 4, 5, 1, 2)
.takeWhile(n -> n < 4) // 取前面满足条件的(遇到不满足即停止)
.collect(Collectors.toList()); // [1, 2, 3]
List<Integer> dropped = Stream.of(1, 2, 3, 4, 5, 1, 2)
.dropWhile(n -> n < 4) // 丢弃前面满足条件的(从第一个不满足开始保留)
.collect(Collectors.toList()); // [4, 5, 1, 2]
// 2. Stream.iterate 带终止条件(三参数)
Stream<Integer> finite = Stream.iterate(1, n -> n < 100, n -> n * 2);
// [1, 2, 4, 8, 16, 32, 64] --- 类似for循环的终止条件
// 3. Stream.ofNullable
Stream<String> stream = Stream.ofNullable(getMaybeNull());
// null → 空Stream,非null → 单元素Stream
// 4. Optional增强
Optional<String> opt = Optional.of("hello");
opt.ifPresentOrElse(
v -> System.out.println("Found: " + v),
() -> System.out.println("Not found")
);
Optional<String> chained = opt.or(() -> Optional.of("fallback"));
Stream<String> asStream = opt.stream(); // 0或1个元素的Stream
// 5. Collectors.flatMapping(配合groupingBy)
Map<String, List<String>> tags = articles.stream()
.collect(Collectors.groupingBy(
Article::getCategory,
Collectors.flatMapping(
article -> article.getTags().stream(),
Collectors.toList()
)
));
// 6. Collectors.filtering
Map<String, List<Article>> filtered = articles.stream()
.collect(Collectors.groupingBy(
Article::getCategory,
Collectors.filtering(
a -> a.getViews() > 1000,
Collectors.toList()
)
));
// 7. 不可变集合工厂
List<String> immutable = List.of("a", "b", "c");
Set<String> set = Set.of("x", "y", "z");
Map<String, Integer> map = Map.of("key1", 1, "key2", 2);
14.2 JDK 10-12 改进
java
// JDK 10: Collectors.toUnmodifiableList/Set/Map
List<String> unmodifiable = stream.collect(Collectors.toUnmodifiableList());
// JDK 10: var 简化(非函数式专属,但简化Lambda相关代码)
var predicate = new Predicate<String>() {
@Override
public boolean test(String s) { return s.length() > 3; }
};
// JDK 11: String方法(配合Stream)
"hello\nworld\njava".lines() // Stream<String>
.map(String::strip)
.filter(s -> !s.isBlank())
.forEach(System.out::println);
"abc".repeat(3); // "abcabcabc"
" hello ".strip(); // "hello"(支持Unicode空白)
// JDK 12: Collectors.teeing --- 双路收集
record Stats(long count, double average) {}
Stats stats = Stream.of(1, 2, 3, 4, 5)
.collect(Collectors.teeing(
Collectors.counting(),
Collectors.averagingInt(Integer::intValue),
Stats::new
));
System.out.println(stats); // Stats[count=5, average=3.0]
// JDK 12: String.transform --- 函数式转换
String result = "hello".transform(s -> s.toUpperCase() + "!");
// "HELLO!"
14.3 JDK 14-16 改进
java
// JDK 16: Stream.toList() --- 直接收集为不可变List
List<String> list = Stream.of("a", "b", "c")
.filter(s -> s.length() > 0)
.toList(); // 返回不可变List(无需Collectors.toList())
// 注意:返回的是unmodifiable List,不能add/remove
// JDK 16: Record --- 不可变数据载体(配合函数式)
record Point(int x, int y) {}
record Line(Point start, Point end) {
double length() {
return Math.sqrt(Math.pow(end.x() - start.x(), 2)
+ Math.pow(end.y() - start.y(), 2));
}
}
List<Point> points = List.of(new Point(0, 0), new Point(3, 4), new Point(1, 1));
double maxLen = points.stream()
.map(p -> new Line(new Point(0, 0), p))
.mapToDouble(Line::length)
.max()
.orElse(0);
// JDK 16: Pattern Matching for instanceof
Object obj = getSomething();
if (obj instanceof String s) {
System.out.println(s.length()); // 直接使用s,无需强转
}
// 配合Optional
Optional<Object> opt = Optional.of("hello");
opt.ifPresent(o -> {
if (o instanceof String s) {
System.out.println(s.toUpperCase());
}
});
14.4 JDK 17-21 改进
java
// JDK 17: Sealed Classes --- 限定继承(配合模式匹配)
sealed interface Shape permits Circle, Rectangle, Triangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double w, double h) implements Shape {}
record Triangle(double base, double height) implements Shape {}
// JDK 21: Pattern Matching for switch(正式版)
public static double area(Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.w() * r.h();
case Triangle t -> 0.5 * t.base() * t.height();
}; // 无需default,编译器知道所有子类
}
// JDK 21: Record Patterns(解构)
record Point(int x, int y) {}
record Line(Point from, Point to) {}
Object obj = new Line(new Point(0, 0), new Point(3, 4));
if (obj instanceof Line(Point(var x1, var y1), Point(var x2, var y2))) {
System.out.printf("(%d,%d) → (%d,%d)%n", x1, y1, x2, y2);
}
// switch中使用Record Patterns
String describe(Object obj) {
return switch (obj) {
case Point(int x, int y) when x == y -> "diagonal point";
case Point(int x, int y) -> "point " + x + "," + y;
case Line l -> "line of length " + l.length();
case null -> "null";
default -> "unknown";
};
}
// JDK 21: 虚拟线程 + 函数式并发
// 用函数式风格编写高并发代码
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
List<Future<String>> futures = urls.stream()
.map(url -> executor.submit(() -> fetchUrl(url))) // 每个URL一个虚拟线程
.toList();
List<String> results = futures.stream()
.map(f -> {
try { return f.get(); }
catch (Exception e) { return "ERROR"; }
})
.filter(s -> !s.equals("ERROR"))
.toList();
}
// JDK 21: SequencedCollection(有序集合新接口)
SequencedCollection<String> seq = new ArrayList<>(List.of("a", "b", "c"));
seq.addFirst("z");
seq.addLast("d");
String first = seq.getFirst();
String last = seq.getLast();
List<String> reversed = seq.reversed().stream().toList();
14.5 各版本改进速查表
| 版本 | 关键改进 | 影响 |
|---|---|---|
| JDK 9 | takeWhile/dropWhile/iterate(3参)/ofNullable |
Stream控制力增强 |
| JDK 9 | Optional.ifPresentOrElse/or/stream |
Optional链式更流畅 |
| JDK 9 | Collectors.flatMapping/filtering |
分组收集更灵活 |
| JDK 9 | List.of/Set.of/Map.of |
不可变集合一行创建 |
| JDK 10 | toUnmodifiableList/Set/Map |
收集为不可变集合 |
| JDK 11 | String.lines/strip/repeat |
字符串Stream化 |
| JDK 12 | Collectors.teeing |
一次遍历双路归约 |
| JDK 12 | String.transform |
函数式字符串转换 |
| JDK 16 | Stream.toList() |
简化最常见收集操作 |
| JDK 16 | Record正式 | 不可变数据+函数式天然搭配 |
| JDK 17 | Sealed Classes | 类型安全的模式匹配基础 |
| JDK 21 | Pattern Matching for switch | 函数式解构+类型分发 |
| JDK 21 | Record Patterns | 嵌套解构 |
| JDK 21 | 虚拟线程 | 函数式并发新范式 |
总结
Java 函数式编程的核心知识脉络:
- Lambda 是语法基础 → 简化匿名函数书写
- 函数式接口 是类型系统 → 43个接口覆盖所有函数签名
- 方法引用 是Lambda的语法糖 → 4种引用方式
- Stream API 是核心应用 → 声明式数据处理管道
- Collector 是归约框架 → 可自定义的收集策略
- Optional 是空值处理 → 链式安全的null替代
- 并行流 是性能手段 → ForkJoinPool + work-stealing
- 函数组合 是设计思想 → 小函数组合成复杂逻辑
- JDK持续演进 → 从JDK8奠基到JDK21模式匹配,函数式能力不断增强
