Java Stream API 编程实战

发布于:2025-08-05 ⋅ 阅读:(17) ⋅ 点赞:(0)

1. 前言

本文通过一些Stream API的编程题目和示例,来加强对Java函数式编程的理解

2. 题目合集

2.1 求两个列表的并集(降序排列)

// 给定两个整数列表
List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> list2 = Arrays.asList(4, 5, 6, 7, 8, 9);

// 预期输出 — [9, 8, 7, 6, 5, 4, 3, 2, 1]

要求:使用Java Stream API编写代码,找出两个列表的并集——即包含所有不重复元素的列表,并按降序排列。

解决方案

public static void main(String args[]) {
    // 输出 - [9, 8, 7, 6, 5, 4, 3, 2, 1]
    List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5, 6);
    List<Integer> list2 = Arrays.asList(4, 5, 6, 7, 8, 9);

    // 方案1:使用Stream.of和flatMap
    List<Integer> unionDescList = Stream.of(list1, list2)
            .flatMap(Collection::stream)  // 将两个列表扁平化为一个流
            .distinct()                  // 去重
            .sorted(Comparator.reverseOrder()) // 降序排序
            .toList();                   // 收集为列表

    System.out.println("并集(降序): 方案1 - " + unionDescList);

    // 方案2:使用Stream.concat
    List<Integer> unionDescList1 = Stream.concat(list1.stream(), list2.stream())
            .distinct()
            .sorted(Comparator.reverseOrder())
            .toList();
    System.out.println("并集(降序): 方案2 - " + unionDescList1);
}

技术要点
• flatMap用于将多个流合并为一个流
• distinct确保元素唯一性
• sorted(Comparator.reverseOrder())实现降序排列
• Java 16+的toList()方法比collect(Collectors.toList())更简洁

2.2 找出满足目标和的元素对

// 给定两个整数列表
List<Integer> list1 = Arrays.asList(1, 2, 3, 6, 17, 1, 10, 8);
List<Integer> list2 = Arrays.asList(1, 17, 12, 12, 2, 4, 6);

// 预期输出 — (a, b)形式的元素对

要求:使用Java Stream API编写程序,找出所有满足以下条件的元素对(a, b):
a来自list1,b来自list2,a和b的和为18。

解决方案

public static void main(String args[]) {
    
    List<Integer> list1 = Arrays.asList(1, 2, 3, 6, 17, 1, 10, 8);
    List<Integer> list2 = Arrays.asList(1, 17, 12, 12, 2, 4, 6);
	
	// 方案1:使用flatMap
	System.out.println("----方案1 ----");
    List<String> result = list1.stream()
            .flatMap(a -> list2.stream()
                    .filter(b -> a + b == 18)
                    .map(b -> a + "," + b))
            .toList();
    result.forEach(System.out::println);

    // 方案2:使用Stream.of和filter
    System.out.println("----方案2 ----");
    list1.stream().map(a -> list2.stream()
                    .filter(b -> a + b == 18)
                    .map(b -> a + "," + b))
            .flatMap(s -> s)
            .forEach(System.out::println);
}

技术要点:
• flatMap用于处理嵌套流结构
• filter条件判断实现业务逻辑

2.3 找出两个列表的共同元素(交集)

// 给定两个整数列表
List<Integer> list1 = Arrays.asList(10, 20, 30, 40, 50);
List<Integer> list2 = Arrays.asList(30, 40, 50, 60, 70);

// 预期输出: [30, 40, 50]

要求:使用Java Stream API,找出两个列表中共同的元素(交集),并将它们作为列表返回。

解决方案

public static void main(String args[]) {
    List<Integer> list1 = Arrays.asList(10, 20, 30, 40, 50);
    List<Integer> list2 = Arrays.asList(30, 40, 50, 60, 70);

    // 方案1:使用filter和flatMap
    System.out.println("----方案1 ----");
    list1.stream()
            .map(a -> list2.stream().filter(b -> Objects.equals(a, b)))
            .flatMap(s -> s)
            .forEach(System.out::println);

    // 方案2:使用Filter和contains
    System.out.println("----方案2 ----");
    list1.stream().filter(list2::contains)
            .toList()
            .forEach(System.out::println);
}

技术要点:
• 方案2更简洁高效,推荐在实际开发中使用
• list2::contains是方法引用,相当于b -> list2.contains(b)
• 注意使用Objects.equals进行null安全的比较

2.4 找出列表中所有重复出现的元素

// 给定一个整数列表
List<Integer> list = Arrays.asList(1, 2, 3, 2, 4, 5, 3, 6);

// 预期输出: [2, 3]

要求:使用Stream API,找出并返回列表中所有重复出现的元素。

解决方案

public static void main(String args[]) {
    List<Integer> list = Arrays.asList(1, 2, 3, 2, 4, 5, 3, 6);

    list.stream()
    		// groupingBy(Function.identity(), counting()) → 统计每个元素的出现次数
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) 
            .entrySet()
            .stream()
            .filter(a -> a.getValue() > 1) // 只保留出现次数大于1的元素
            .map(Map.Entry::getKey) // 提取元素本身
            .toList() // collect(Collectors.toList()) → 收集重复元素到列表
            .forEach(System.out::println);
}

技术要点:
• groupingBy+counting是统计元素频率的经典组合
• 使用entrySet().stream()将Map转换为流进行处理

2.5 使用Java Stream查找字符串中第一个不重复的字符

// 示例如下
String input = "swiss";

/*
• 's'重复出现
• 'w'是唯一的
• 因此,答案应该是:'w'
*/ 

解决方案

public static void main(String args[]) {
    String input = "swiss";

    Optional<Character> firstNonRepeating = input.chars()  // 将String转换为IntStream
            .mapToObj(c -> (char) c)  // 将int值转换为Character对象
            .collect(Collectors.groupingBy( // 使用LinkedHashMap保持插入顺序,这对找到第一个唯一字符至关重要
                    Function.identity(), LinkedHashMap::new, Collectors.counting() // Collectors.counting() → 统计每个字符的出现次数
            ))
            .entrySet()
            .stream()
            .filter(entry -> entry.getValue() == 1) // 只保留不重复的字符
            .map(Map.Entry::getKey)
            .findFirst(); // .map(...).findFirst() → 按插入顺序找到第一个符合条件的字符

    firstNonRepeating.ifPresent(System.out::println);  // 输出: w
}

技术要点:
• 使用LinkedHashMap保持字符顺序是关键
• findFirst返回Optional,安全处理可能为空的情况

3. 总结

掌握Stream API能极大地提升编写代码的简洁性和表达力,为了更好地掌握其使用,一定要在理解每个Stream方法的工作原理的基础上动手实践。


网站公告

今日签到

点亮在社区的每一天
去签到