深入探讨 Java 8 集合操作:全面解析 Stream API 的强大功能
Java 8 引入的 Stream API 使得集合操作更加简洁和高效。本文通过详细示例,展示如何利用 Stream API 进行各种集合操作,包括遍历、转换、过滤、排序、分组、去重等。
1. 遍历集合
示例:使用 forEach 遍历列表
import java.util.Arrays; import java.util.List; public class ForEachExample { public static void main(String[] args) { List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia"); // 使用 forEach 遍历列表 names.forEach(name -> System.out.println(name)); } }
import java.util.HashMap; import java.util.Map; public class ForEachMapExample { public static void main(String[] args) { Map<String, Integer> ages = new HashMap<>(); ages.put("Peter", 30); ages.put("Anna", 25); ages.put("Mike", 35); // 使用 forEach 遍历 Map ages.forEach((name, age) -> System.out.println(name + ": " + age)); } }
2. List 转 Map
示例:将 List 转换为 Map
import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; class Person { private String name; private int age; // 构造方法和 getter 方法 public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } public class ListToMapExample { public static void main(String[] args) { List<Person> people = Arrays.asList(new Person("Peter", 30), new Person("Anna", 25), new Person("Peter", 28)); // 将 List 转换为 Map Map<String, Integer> personMap = people.stream() .collect(Collectors.toMap(Person::getName, Person::getAge, (existing, replacement) -> existing)); personMap.forEach((name, age) -> System.out.println(name + ": " + age)); // 有序写法 Map<String, Person> personOrderlyMap = people .stream() .collect(Collectors.toMap(Person::getName, a -> a, (oldValue, newValue) -> newValue, LinkedHashMap::new)); // value为对象时,也可以这样写,注意ID相同时,会抛异常 Map<String, Person> personMapOther = people .stream() .collect(Collectors.toMap(Person::getName, person -> person)); // 还可以这样写 输出跟输入一样的Lambda表达式对象,等价于person -> person Map<String, Person> personAscMap = people .stream() .collect(Collectors.toMap(Person::getName, Function.identity())); // map按key排序 默认正序,反序为: Map.Entry.comparingByKey().reversed() Map<String, Person> personDescMap = personAscMap .entrySet() .stream() .sorted(Map.Entry.comparingByKey()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new)); } }
3. 过滤和映射
示例:过滤列表
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class FilterExample { public static void main(String[] args) { List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia"); // 过滤名字以 "P" 开头的元素 List<String> filteredNames = names.stream() .filter(name -> name.startsWith("P")) .collect(Collectors.toList()); System.out.println(filteredNames); // 输出:[Peter] } }
示例:映射列表
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class MapExample { public static void main(String[] args) { List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia"); // 将名字转换为大写 List<String> upperCaseNames = names.stream() .map(String::toUpperCase) .collect(Collectors.toList()); System.out.println(upperCaseNames); // 输出:[PETER, ANNA, MIKE, XENIA] } }
4. 聚合操作
示例:求和
import java.util.Arrays; import java.util.List; public class SumExample { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 使用 Stream API 计算总和 int sum = numbers.stream() .mapToInt(Integer::intValue) .sum(); System.out.println("Sum: " + sum); // 输出:Sum: 15 } }
示例:求平均值
import java.util.Arrays; import java.util.List; import java.util.OptionalDouble; public class AverageExample { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 使用 Stream API 计算平均值 OptionalDouble average = numbers.stream() .mapToInt(Integer::intValue) .average(); System.out.println("Average: " + (average.isPresent() ? average.getAsDouble() : "N/A")); } }
5. 分组和分区
示例:按条件分组
import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class GroupingByExample { public static void main(String[] args) { List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia"); // 按名字的长度分组 Map<Integer, List<String>> groupedByLength = names.stream() .collect(Collectors.groupingBy(String::length)); groupedByLength.forEach((length, nameList) -> System.out.println(length + ": " + nameList)); } }
示例:按条件分区
import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class PartitioningByExample { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6); // 按是否为偶数分区 Map<Boolean, List<Integer>> partitionedByEven = numbers.stream() .collect(Collectors.partitioningBy(n -> n % 2 == 0)); partitionedByEven.forEach((isEven, numList) -> System.out.println(isEven + ": " + numList)); } }
6. 并行流
示例:使用并行流提高性能
import java.util.Arrays; import java.util.List; public class ParallelStreamExample { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // 使用并行流计算总和 int sum = numbers.parallelStream() .mapToInt(Integer::intValue) .sum(); System.out.println("Sum: " + sum); // 输出:Sum: 55 } }
7. 去重操作
示例:去除列表中的重复元素
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class DistinctExample { public static void main(String[] args) { List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Anna", "Xenia", "Peter"); // 使用 distinct 去重 List<String> uniqueNames = names.stream() .distinct() .collect(Collectors.toList()); System.out.println(uniqueNames); // 输出:[Peter, Anna, Mike, Xenia] // 对象,根据ID去重 List<User> duplicateRemoval = zxrMaps.stream().collect( Collectors.collectingAndThen( Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(User::getId))), ArrayList::new) ); } }
8. 收集结果
示例:将列表转换为 Set
import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class ToSetExample { public static void main(String[] args) { List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia"); // 将列表转换为 Set Set<String> nameSet = names.stream() .collect(Collectors.toSet()); System.out.println(nameSet); } }
示例:连接字符串
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class JoiningExample { public static void main(String[] args) { List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia"); // 连接字符串,使用逗号分隔 String joinedNames = names.stream() .collect(Collectors.joining(", ")); System.out.println(joinedNames); // 输出:Peter, Anna, Mike, Xenia } }
9. 映射和扁平化
示例:扁平化嵌套列表
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class FlatMapExample { public static void main(String[] args) { List<List<String>> nestedList = Arrays.asList( Arrays.asList("Peter", "Anna"), Arrays.asList("Mike", "Xenia") ); // 扁平化嵌套列表 List<String> flatList = nestedList.stream() .flatMap(List::stream) .collect(Collectors.toList()); System.out.println(flatList); // 输出:[Peter, Anna, Mike, Xenia] } }
10. 生成流
示例:生成数值范围
import java.util.stream.IntStream; public class IntStreamRangeExample { public static void main(String[] args) { // 生成 1 到 10 的数值范围 IntStream.rangeClosed(1, 10) .forEach(System.out::println); } }
11. 归约操作
示例:使用 reduce 求和
import java.util.Arrays; import java.util.List; public class ReduceSumExample { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 使用 reduce 求和 int sum = numbers.stream() .reduce(0, Integer::sum); System.out.println("Sum: " + sum); // 输出:Sum: 15 } }
示例:使用 reduce 求乘积
import java.util.Arrays; import java.util.List; public class ReduceProductExample { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 使用 reduce 求乘积 int product = numbers.stream() .reduce(1, (a, b) -> a * b); System.out.println("Product: " + product); // 输出:Product: 120 } }
12. 排序和查找
示例:排序列表
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class SortExample { public static void main(String[] args) { List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia"); // 排序列表 List<String> sortedNames = names.stream() .sorted() .collect(Collectors.toList()); System.out.println(sortedNames); // 输出:[Anna, Mike, Peter, Xenia] } }
示例:查找第一个匹配元素
import java.util.Arrays; import java.util.List; import java.util.Optional; public class FindFirstExample { public static void main(String[] args) { List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia"); // 查找第一个以 "P" 开头的元素 Optional<String> firstMatchingName = names.stream() .filter(name -> name.startsWith("P")) .findFirst(); System.out.println("First matching name: " + firstMatchingName.orElse("No match")); } }
13. 自定义收集器
示例:自定义收集器
import java.util.Arrays; import java.util.List; import java.util.stream.Collector; import java.util.stream.Collectors; public class CustomCollectorExample { public static void main(String[] args) { List<String> names = Arrays.asList("Peter", "Anna", "Mike", "Xenia"); // 自定义收集器 String result = names.stream() .collect(Collector.of( StringBuilder::new, (sb, name) -> sb.append(name).append("|"), StringBuilder::append, StringBuilder::toString )); System.out.println(result); // 输出:Peter|Anna|Mike|Xenia| } }
14. List 并集、差集、交集
// list1 List<String> list1 = Arrays.asList("a", "b", "c"); // list2 List<String> list2 = Arrays.asList("b", "c", "d"); // 交集 ("b", "c") List<String> intersection = list1.stream().filter(item -> list2.contains(item)).collect(toList()); // 差集 (list1 - list2) List<String> reduce1 = list1.stream().filter(item -> !list2.contains(item)).collect(toList()); // 差集 (list2 - list1) List<String> reduce2 = list2.stream().filter(item -> !list1.contains(item)).collect(toList()); // 并集 (list1 + list2) List<String> listAll = new ArrayList(); listAll.addAll(list1); listAll.addAll(list2); listAll.parallelStream().forEach(System.out :: println); // 并集去重 List<String> listAllDistinct = listAll.stream().distinct().collect(toList());
总结
Java 8 的 Stream API 通过提供流畅、声明式的编程方式,使集合操作更加灵活和高效。本文通过详尽的示例展示了 Stream API 在遍历、转换、过滤、分组、去重、并行处理等方面的强大功能。这些新特性不仅提高了代码的简洁性和可读性,还显著提升了开发效率。