Java深入解析篇四之函数式编程详解

Java深入解析篇四之函数式编程(Functional Programming)详解


目录

  1. 函数式编程概念与Java实现
  2. Lambda表达式语法与原理
  3. 函数式接口体系
  4. 方法引用
  5. [Stream API完整操作](#Stream API完整操作)
  6. Stream内部原理
  7. Collector自定义
  8. 并行流原理与ForkJoinPool
  9. Optional正确使用
  10. 函数组合
  11. 函数式异常处理
  12. 函数式编程在Spring/框架中的应用
  13. Stream性能分析与最佳实践
  14. [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 匿名函数语法
高阶函数 方法参数/返回值为函数式接口
不可变 finalStream不修改源、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 函数式编程的核心知识脉络:

  1. Lambda 是语法基础 → 简化匿名函数书写
  2. 函数式接口 是类型系统 → 43个接口覆盖所有函数签名
  3. 方法引用 是Lambda的语法糖 → 4种引用方式
  4. Stream API 是核心应用 → 声明式数据处理管道
  5. Collector 是归约框架 → 可自定义的收集策略
  6. Optional 是空值处理 → 链式安全的null替代
  7. 并行流 是性能手段 → ForkJoinPool + work-stealing
  8. 函数组合 是设计思想 → 小函数组合成复杂逻辑
  9. JDK持续演进 → 从JDK8奠基到JDK21模式匹配,函数式能力不断增强
相关推荐
李迟2 小时前
一种轻量级C++ CSV文件读写库的实现方案
开发语言·c++
音符犹如代码2 小时前
Arthas Profiler 火焰图实战:CPU 热点在哪一目了然
java·jvm·spring boot
小园子的小菜2 小时前
Java 并发编程:线程安全队列全解 —— 阻塞与非阻塞实现原理及源码深度剖析
java·开发语言
好好沉淀2 小时前
Windows 下升级 Maven 3.6.1 到 3.9.9 踩坑全记录
java·windows·maven
CodexDave2 小时前
Python 自动化接单实战(一):把 CSV 需求做成配置驱动解析器
java·python·自动化·json·数据清洗·python自动化·csv处理
Y3815326622 小时前
2026 年 7 月,SERP API 调用的稳定性实战:超时、重试、降级
开发语言·数据库·人工智能·php
Wang's Blog2 小时前
Go-Zero项目开发38:深入限流器实现与应用
开发语言·golang·go-zero
XS0301063 小时前
Spring框架
java·后端·spring
风吹心凉3 小时前
python3基础2026.7.28
开发语言·python
Rabitebla3 小时前
C++ 内存管理全面复习:从内存分布到 operator new/delete
java·c语言·开发语言·c++·算法·leetcode