← Java 学习路线(共 8 章)

第 8 章 Lambda、Stream 与综合实战

red wenzi · 2026-09-15 · 编程语言 · Java · 📖 预计阅读 15 分钟 · 共 2 道练习
🎯 本章你会学到:用 Stream 把“过滤/映射/排序/统计”写成一条链,并完成词频 Top-N。建议边读边敲,每节练习先自己做,再展开答案对照。

Stream 是 Java 8 之后处理集合的推荐方式:把“对一堆数据做什么”写成一条链,读起来跟描述需求一样。写数据结构作业时未必用得上,但处理数据、写脚本时非常好用。

filter / map / sum / count

Stream 三件套:过滤、映射、排序
import java.util.List;

public class Main {
    record Student(String name, int score) { }

    public static void main(String[] args) {
        List<Student> list = List.of(
                new Student("Ann", 90),
                new Student("Bob", 59),
                new Student("Cid", 88));

        long pass = list.stream()
                .filter(s -> s.score() >= 60)      // 过滤:及格
                .count();
        int total = list.stream()
                .mapToInt(Student::score)          // 映射成 int 流
                .sum();

        System.out.println("pass=" + pass);
        System.out.printf("avg=%.1f%n", total / (double) list.size());

        list.stream()
                .sorted((a, b) -> Integer.compare(b.score(), a.score()))
                .forEach(s -> System.out.println(s.name() + " " + s.score()));
    }
}
运行结果
pass=2
avg=79.0
Ann 90
Cid 88
Bob 59

groupingBy:一行做词频

词频 Top-N
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("apple", "banana", "apple", "cherry", "banana", "apple");

        Map<String, Long> freq = words.stream()
                .collect(Collectors.groupingBy(w -> w, Collectors.counting()));

        freq.entrySet().stream()
                .sorted((a, b) -> {
                    int c = Long.compare(b.getValue(), a.getValue());   // 次数降序
                    return c != 0 ? c : a.getKey().compareTo(b.getKey()); // 同次数按字典序
                })
                .limit(2)
                .forEach(e -> System.out.println(e.getKey() + " " + e.getValue()));
    }
}
运行结果
apple 3
banana 2
操作写法说明
过滤.filter(x -> 条件)保留满足条件的元素
映射.map(x -> 新值) / .mapToInt(...)把元素变成另一种形式
排序.sorted(comparator)默认升序
统计.count() / .sum() / .average()count 返回 long
收集.collect(Collectors.toList())把流变回集合
分组.collect(Collectors.groupingBy(f))返回 Map
⚠️ 易错点 Stream 是“一次性的”:同一个流只能消费一次,重复使用会抛 IllegalStateException。要复用就用集合本身。
⚠️ 易错点 Stream 适合表达“做什么”,不适合塞复杂逻辑;有副作用(改外部变量、写文件)时用普通循环更清楚。

✍️ 本节练习

8.1必做用 Stream 统计

读入 n 个整数,输出其中 ≥ 60 的个数与总和(用 Stream 完成)。

输入 第一行 n;第二行 n 个整数。

输出 两行:pass=sum=

样例输入
5
90 59 88 60 30
样例输出
pass=3
sum=238

💡 提示 把数组转成流:Arrays.stream(a).filter(v -> v >= 60)

✅ 查看参考答案与解析
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = sc.nextInt();
        }
        long pass = Arrays.stream(a).filter(v -> v >= 60).count();
        int sum = Arrays.stream(a).filter(v -> v >= 60).sum();
        System.out.println("pass=" + pass);
        System.out.println("sum=" + sum);
    }
}

解析 数组没有 stream() 方法,要用 Arrays.stream(a);集合才有 .stream()

8.2挑战成绩榜(综合练习)

读入若干行「姓名 分数」直到输入结束,输出人数、平均分(2 位小数)和按分数降序的前 3 名(格式 name score,用逗号分隔)。

输入 若干行「姓名 分数」,读到输入结束。

输出 三行:count=avg=top3=...

样例输入
Ann 90
Bob 59
Cid 88
Dan 95
Eve 72
样例输出
count=5
avg=80.80
top3=Dan 95,Ann 90,Cid 88

💡 提示 用 List<Student> 收集后 stream().sorted(...),取前 3 个再 Collectors.joining(",")

✅ 查看参考答案与解析
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;

public class Main {
    record Student(String name, int score) { }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        List<Student> list = new ArrayList<>();
        while (sc.hasNext()) {
            String name = sc.next();
            if (!sc.hasNextInt()) {
                break;
            }
            list.add(new Student(name, sc.nextInt()));
        }
        if (list.isEmpty()) {
            return;
        }

        double avg = list.stream().mapToInt(Student::score).average().orElse(0);
        String top3 = list.stream()
                .sorted((a, b) -> Integer.compare(b.score(), a.score()))
                .limit(3)
                .map(s -> s.name() + " " + s.score())
                .collect(Collectors.joining(","));

        System.out.println("count=" + list.size());
        System.out.printf("avg=%.2f%n", avg);
        System.out.println("top3=" + top3);
    }
}

解析 average() 返回 OptionalDouble(可能没有元素),用 orElse(0) 兜底;Collectors.joining 负责拼接。这道题把集合、Stream、异常安全的输入处理串在一起。

📚 本文概念都在知识大全:

JVM 与字节码 · JDK · String 与 StringBuilder · 集合框架 · 泛型 · 受检异常 · 继承与接口 · record · Stream API