下载工作台
Java 编程实战

Lambda、Stream 与 Optional

试读上半部分 · 解锁后可读全文

第 9 章 · Lambda、Stream 与 Optional

本章目标:掌握 Lambda 表达式语法与函数式接口;熟练使用 Stream APImapfilterreduce 及聚合操作;理解 Optional 避免空指针;用 Stream 重构 toolkit-demo 商品筛选与统计逻辑。

学时建议:4~5 小时(含 1.5 小时跟练)

前置ch08 集合框架;ch06 接口与匿名内部类。


9.1 为什么需要 Lambda

Java 8 引入 Lambda,简化「只含一个抽象方法的接口」实现:

// 旧写法:匿名内部类
Runnable r1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello");
    }
};

// Lambda 写法
Runnable r2 = () -> System.out.println("Hello");
优势说明
代码简洁少写类名与 new
与 Stream 配合集合处理更直观
延迟执行可传给高阶函数

函数式接口:仅一个抽象方法,如 RunnableComparatorPredicate。可用 @FunctionalInterface 标注。


9.2 Lambda 语法

// 无参
() -> System.out.println("run")

// 单参(可省略括号与类型)
x -> x * 2
(x) -> x * 2
(int x) -> x * 2

// 多参
(a, b) -> a + b

// 多行需大括号与 return
(a, b) -> {
    int sum = a + b;
    return sum;
}

方法引用(当 Lambda 仅调用已有方法时):

import java.util.function.Function;

Function<String, Integer> len = String::length;
System.out.println(len.apply("Java"));  // 4

// 等价于 s -> s.length()
引用形式示例
静态方法Integer::parseInt
实例方法str::length
构造方法ArrayList::new

9.3 常用函数式接口

java.util.function 包:

import java.util.function.*;

Predicate<String> notEmpty = s -> s != null && !s.isEmpty();
System.out.println(notEmpty.test("abc"));  // true

Function<String, Integer> toLen = String::length;
System.out.println(toLen.apply("toolkit"));  // 7

Consumer<String> printer = System.out::println;
printer.accept("日志输出");

Supplier<Double> random = Math::random;
System.out.println(random.get());
接口方法用途
Predicate<T>test(T)条件判断
Function<T,R>apply(T)转换
Consumer<T>accept(T)消费,无返回
Supplier<T>get()供给
BiFunction<T,U,R>apply(T,U)双参转换

9.4 Stream 创建与中间操作

Stream 是对集合的「流水线」处理,不修改原集合(除非终端操作收集回原结构)。

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

List<String> books = List.of("Java 基础", "Web 开发", "数据分析", "Java 进阶");

// 从集合
Stream<String> s1 = books.stream();

// 从数组
Stream.of("A", "B", "C");

// 无限流(慎用)
Stream.iterate(0, n -> n + 1).limit(10);

filter — 筛选:

List<String> javaBooks = books.stream()
    .filter(b -> b.contains("Java"))
    .collect(Collectors.toList());
// [Java 基础, Java 进阶]

map — 转换:

List<Integer> lengths = books.stream()
    .map(String::length)
    .collect(Collectors.toList());
// [8, 6, 4, 8]

distinct / sorted / limit / skip

List<Integer> uniqueSorted = List.of(3, 1, 4, 1, 5, 9).stream()
    .distinct()
    .sorted()
    .limit(3)
    .collect(Collectors.toList());
// [1, 3, 4]

9.5 flatMap 展开嵌套

import java.util.List;
import java.util.stream.Collectors;

List<List<String>> nested = List.of(
    List.of("A", "B"),
    List.of("C", "D")
);

List<String> flat = nested.stream()
    .flatMap(List::stream)
    .collect(Collectors.toList());
// [A, B, C, D]

toolkit-demo:一行日志拆成多个 token 后统计,可用 flatMap


9.6 reduce 聚合

import java.util.List;

List<Integer> nums = List.of(1, 2, 3, 4, 5);

// 求和
int sum = nums.stream()
    .reduce(0, Integer::sum);
// 或 nums.stream().mapToInt(Integer::intValue).sum()

// 求最大值
int max = nums.stream()
    .reduce(Integer.MIN_VALUE, Integer::max);

// Optional 版本(无初始值)
nums.stream().reduce(Integer::sum).ifPresent(System.out::println);
reduce 形式说明
reduce(identity, accumulator)有初始值,返回确定类型
reduce(accumulator)无初始值,返回 Optional

9.7 终端操作与 Collectors

import java.util.*;
import java.util.stream.Collectors;

// 使用 ch06 学过的 record 作为数据载体(访问器为 title()、price() 等,而非 getTitle())
record Product(String sku, String title, double price, int sales) {}

List<Product> products = List.of(
    new Product("BK-001", "Java 基础", 59.9, 120),
    new Product("BK-002", "Web 开发", 79.0, 450),
    new Product("BK-003", "数据分析", 45.0, 89)
);

// 转 List
List<String> titles = products.stream()
    .map(Product::title)
    .collect(Collectors.toList());

// 转 Set
Set<String> skus = products.stream()
    .map(Product::sku)
    .collect(Collectors.toSet());

// 分组
Map<Double, List<Product>> byPrice = products.stream()
    .collect(Collectors.groupingBy(Product::price));

// 拼接字符串
String joined = products.stream()
    .map(Product::title)
    .collect(Collectors.joining(", "));

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。