1. 前言
本文通过一些Stream API的编程题目和示例,来加强对Java函数式编程的理解
2. 题目合集
2.1 求两个列表的并集(降序排列)
java
// 给定两个整数列表
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编写代码,找出两个列表的并集------即包含所有不重复元素的列表,并按降序排列。
解决方案
java
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 找出满足目标和的元素对
java
// 给定两个整数列表
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。
解决方案
java
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 找出两个列表的共同元素(交集)
java
// 给定两个整数列表
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,找出两个列表中共同的元素(交集),并将它们作为列表返回。
解决方案
java
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 找出列表中所有重复出现的元素
java
// 给定一个整数列表
List<Integer> list = Arrays.asList(1, 2, 3, 2, 4, 5, 3, 6);
// 预期输出: [2, 3]
要求:使用Stream API,找出并返回列表中所有重复出现的元素。
解决方案
java
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查找字符串中第一个不重复的字符
java
// 示例如下
String input = "swiss";
/*
• 's'重复出现
• 'w'是唯一的
• 因此,答案应该是:'w'
*/
解决方案
java
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方法的工作原理的基础上动手实践。