# Java Stream详解 ## 创建Stream ### Stream.builder()创建 ```java Stream build = Stream.builder() .add(1) .add(12) .add(3) .add(34) .build(); ``` ### Stream.of创建 ```java Stream integerStream = Stream.of(1, 2, 34, 5); ``` ### 空Stream创建 ```java Stream objectStream = Stream.empty(); ``` ### Stream.generate创建 如果不加限制运行时会一直创建像死循环一样 ```java // Stream.generate创建 Stream generate = Stream.generate(() -> ThreadLocalRandom.current().nextInt(10)) .limit(10); ``` ### Stream.iterate创建 ``` // 不加限制会一直创建 Stream.iterate(100, seed -> seed + 1) .limit(10) .forEach(System.out::println); ``` ### IntStream创建创建 ```java // IntStream创建[1,10) IntStream.range(1, 10) .forEach(System.out::println); ``` ### IntStream.rangeClosed创建闭区间 ```java // 创建闭区间[1,10] IntStream.rangeClosed(1,10) .forEach(System.out::println); ``` ### Arrays.asList创建 ```java // Arrays.asList创建 Arrays.asList("a","b","c","d","e","f") .forEach(System.out::println); ``` ### 创建Stream> ```java // 创建Stream> Stream> stream = new HashMap() {{ put("a", "b"); put("c", "d"); }}.entrySet().stream(); ``` ### Files中的Stream ```java // Files中的Stream Stream lines = Files.lines(Paths.get("xxx.md"), StandardCharsets.UTF_8); ``` ## Stream的操作 ### distinct操作 ```java Stream stream = new ArrayList<>() {{ add(1); add(2); add(2); add(3); add(3); add(4); }}.stream(); // 去重操作 stream.distinct().forEach(System.out::println); ``` > 输出: > > ``` > 1 > 2 > 3 > 4 > ``` ### filter操作 ```java stream = new ArrayList<>() {{ add(1); add(2); add(2); add(3); add(3); add(4); }}.stream(); // 过滤器,满足值为2的筛选 stream.filter(x -> x.equals(2)).forEach(System.out::println); ``` ### limit操作 ```java stream = new ArrayList<>() {{ add(1); add(2); add(2); add(3); add(3); add(4); }}.stream(); // 选择序列个数为3 stream.limit(3).forEach(System.out::println); ``` ### map操作 ```java stream = new ArrayList<>() {{ add(1); add(2); add(2); add(3); add(3); add(4); }}.stream(); // 映射,可以修改原本的类型 stream.map(Object::toString).forEach(System.out::println); ``` ### skip操作 ```java stream = new ArrayList<>() {{ add(1); add(2); add(2); add(3); add(3); add(4); }}.stream(); // 跳过前两个数 stream.skip(2).forEach(System.out::println); ``` ### peek操作 如果对一个对象进行操作,比如Person中有姓名和年龄,这时候通过peek修改了其中的年龄,那么这个值会被改变 ```java stream = new ArrayList<>() {{ add(1); add(2); add(2); add(3); add(3); add(4); }}.stream(); // 不会使元素数据、类型产生改变 stream.peek(x -> ThreadLocalRandom.current().nextInt(100)).limit(10).forEach(System.out::println); ``` ### sorted操作 排序操作,也可以指定内容进行排序 ```java stream = new ArrayList<>() {{ add(1); add(2); add(2); add(3); add(3); add(4); }}.stream(); // 从小到大排序 stream.sorted().forEach(System.out::println); // 提供重载方法 stream.sorted(Comparator.comparing(Object::toString)).forEach(System.out::println); ``` ### flatMap操作 扁平化数据,JavaScript中也有这个 ```java ArrayList list = new ArrayList<>() {{ add(1); add(2); add(2); add(3); add(3); add(4); }}; List> arrayListList = List.of(list); // 扁平化数组 arrayListList.stream().flatMap(Collection::stream).forEach(System.out::println); ``` ### match操作 ```java // 需要满足所有元素都匹配条件 boolean allMatch = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9) .allMatch(i -> i > 4); System.out.println(allMatch);// false // 只要有一个元素满足匹配条件 boolean anyMatch = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9) .anyMatch(x -> x > 4); System.out.println(anyMatch);// true // 所有元素都不满足条件 boolean noneMatch = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9) .noneMatch(x -> x > 4); System.out.println(noneMatch);// false ``` ### find操作 ```java // 找到第一个数字 Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9) .findFirst() .ifPresent(System.out::println); // 获取任意一个数字 Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9) .findAny() .ifPresent(System.out::println); ``` ### forEach操作 不解释,放在最后,如果使用了forEach那么后面就无法再跟其它流函数 ### 计数、求和、最小值、最大值 ```java // 计数 long count = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9) .count(); System.out.println(count);// 9 // 求和 long sum = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9) .mapToLong(Integer::longValue) .sum(); System.out.println(sum); // 查找最小值 Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9) .min(Comparator.comparing(i -> i)) .ifPresent(System.out::println); // 查找最大值 Optional max = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9) .max(Comparator.comparing(i -> i)); System.out.println(max.get()); ``` ## Collectors使用 收集器 ### toList 将元素输出到 list ```java List names = Arrays.asList("Alice", "Bob", "Charlie"); List upperCaseNames = names.stream() .map(String::toUpperCase) .collect(Collectors.toList()); ``` ### toSet 将元素输出到 Set ```java List names = Arrays.asList("Alice", "Bob", "Charlie"); Set uniqueNames = names.stream() .collect(Collectors.toSet()); ``` ### toMap 将元素输出到 Map - 2个参数:key,value - 3个参数:key,value,处理key冲突问题 - 4个参数:key,value,处理key冲突问题,转换map类型 ```java List names = Arrays.asList("Alice", "Bob", "Charlie"); Map nameLengthMap = names.stream() .collect(Collectors.toMap(name -> name, String::length)); ``` ### reduce 语法 ```java Optional reduce(BinaryOperator accumulator) Optional reduce(T identity, BinaryOperator accumulator) ``` 使用 ```java List numbers = Arrays.asList(1, 2, 3, 4, 5); // 使用 reduce 求和 Optional sum = numbers.stream() .reduce(Integer::sum); sum.ifPresent(System.out::println); // 输出: 15 // 使用带初始值的 reduce int sumWithIdentity = numbers.stream() .reduce(0, Integer::sum); System.out.println(sumWithIdentity); // 输出: 15 ``` ### summingDouble 将求和后的结果转成Double 语法 ```java static Collector summingDouble(ToDoubleFunction mapper) ``` 使用 ```java public class StreamExample07 { public static void main(String[] args) { List products = Arrays.asList( new Product("Apple", 1.20), new Product("Banana", 0.80), new Product("Orange", 1.00) ); double totalCost = products.stream().mapToDouble(Product::getPrice).sum(); System.out.println("Total Cost: " + totalCost); // 输出: Total Cost: 3.0 } @Getter private static class Product { private final String name; private final double price; public Product(String name, double price) { this.name = name; this.price = price; } } } ``` ### groupingBy - 1个参数:指定key是什么 - 2个参数:指定key和value - 3个参数:key,value,value类型 ```java public class StreamExample08 { public static void main(String[] args) { List people = Arrays.asList( new Person("Alice", 30), new Person("Bob", 25), new Person("Charlie", 30), new Person("David", 25) ); // 根据年龄将一组人分组 Map> groupedByAge = people.stream() .collect(Collectors.groupingBy(Person::getAge)); // 自定义收集器:可以传递第二个参数来指定下游收集器。 Map groupedByAgeCount = people.stream() .collect(Collectors.groupingBy(Person::getAge, Collectors.counting())); // 多级分组:可以嵌套使用 groupingBy 进行多级分组。 Map>> groupedByAgeAndName = people.stream() .collect(Collectors.groupingBy(Person::getAge, Collectors.groupingBy(Person::getName))); System.out.println(groupedByAge); } @Getter static class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return name + " (" + age + ")"; } } } ``` > 输出: > > ```java > {25=[Bob (25), David (25)], 30=[Alice (30), Charlie (30)]} > {25=2, 30=2} > {25={Bob=[Bob (25)], David=[David (25)]}, 30={Alice=[Alice (30)], Charlie=[Charlie (30)]}} > ``` ### Collectors.averaging 求平均值 ```java // averagingLong List numbers = Arrays.asList(1L, 2L, 3L, 4L, 5L); double averagingLongNumbers = numbers.stream() .collect(Collectors.averagingLong(Long::longValue)); System.out.println("Average: " + averagingLongNumbers); // averagingDouble List averagingDoubleNumbers = Arrays.asList(1.5, 2.5, 3.5, 4.5, 5.5); double averagingDouble = averagingDoubleNumbers.stream() .collect(Collectors.averagingDouble(Double::doubleValue)); System.out.println("Average: " + averagingDouble); // averagingInt List averagingIntNumbers = Arrays.asList(1, 2, 3, 4, 5); double averagingInt = averagingIntNumbers.stream() .collect(Collectors.averagingInt(Integer::intValue)); System.out.println("Average: " + averagingInt); ``` ### Collectors.collectingAndThen 先计算平均年龄,之后将计算结果转为整数,可以理解为:先收集之后再干嘛 ```java public class StreamExample10 { public static void main(String[] args) { List people = Arrays.asList( new Person("Alice", 30), new Person("Bob", 25), new Person("Charlie", 35) ); // 使用 Collectors.collectingAndThen 计算平均年龄并转换为整数 int averageAge = people.stream() .collect(Collectors.collectingAndThen( Collectors.averagingInt(Person::getAge),// 先计算平均年龄 Double::intValue // 之后将结果转换为整数 )); System.out.println("Average Age: " + averageAge); } @Getter static class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return name + " (" + age + ")"; } } } ``` ### Collectors.counting使用 求总数,和SQL中count类似 ```java public class StreamExample11 { public static void main(String[] args) { List people = Arrays.asList( new Person("Alice", 30), new Person("Bob", 25), new Person("Charlie", 35) ); // 使用 Collectors.counting 统计人数 long count = people.stream() .collect(Collectors.counting()); System.out.println("Total number of people: " + count); } @Getter static class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return name + " (" + age + ")"; } } } ``` ### Collectors.mapping 类似Stream中的map,先操作(此操作会可以改变其类似),之后在做处理 ```java public class StreamExample12 { public static void main(String[] args) { List people = Arrays.asList( new Person("Alice", 30), new Person("Bob", 25), new Person("Charlie", 35), new Person("David", 40) ); // 使用 Collectors.mapping 和 Collectors.toSet 只收集大于 30 岁的人的年龄 Set agesAbove30 = people.stream() .filter(person -> person.getAge() > 30) .collect(Collectors.mapping(Person::getAge, Collectors.toSet())); System.out.println("Ages above 30: " + agesAbove30); } @Getter static class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return name + " (" + age + ")"; } } } ``` ### Collectors.joining - 无参数:将元素连接在一起,中间没有内容分隔 - 1个参数:将元素连接,使用传入的符号进行分割 - 3个参数:将元素连接,传入第一个参数进行分割,第二个参数是整个处理完成元素的前缀,第三个参数是整个处理完成的后缀 ```java public class StreamExample13 { public static void main(String[] args) { List people = Arrays.asList( new Person("Alice"), new Person("Bob"), new Person("Charlie") ); // 使用 Collectors.joining 连接名字,添加前缀和后缀 String result = people.stream() .map(Person::getName) // 提取名字 .collect(Collectors.joining(", ", "[", "]")); // 使用逗号和空格作为分隔符,添加前缀和后缀 System.out.println("Names: " + result);// Names: [Alice, Bob, Charlie] } @Getter static class Person { private final String name; public Person(String name) { this.name = name; } @Override public String toString() { return name; } } } ``` ### Collectors.summing使用 #### summingInt 求和转成int ```java public class StreamExample14 { public static void main(String[] args) { List people = Arrays.asList( new Person("Alice", 30), new Person("Bob", 25), new Person("Charlie", 35) ); // 使用 Collectors.summingInt 计算年龄总和 int totalAge = people.stream() .collect(Collectors.summingInt(Person::getAge)); System.out.println("Total Age: " + totalAge); } @Getter static class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return name + " (" + age + ")"; } } } ``` #### summingDouble 求和转成double ```java public class StreamExample15 { public static void main(String[] args) { List products = Arrays.asList( new Product("Laptop", 999.99), new Product("Smartphone", 499.99), new Product("Tablet", 299.99) ); // 使用 Collectors.summingDouble 计算价格总和 double totalPrice = products.stream() .collect(Collectors.summingDouble(Product::getPrice)); System.out.println("Total Price: " + totalPrice); } @Getter static class Product { private final String name; @Getter private final double price; public Product(String name, double price) { this.name = name; this.price = price; } } } ``` #### summingLong 求和转成long ```java public class StreamExample16 { public static void main(String[] args) { List transactions = Arrays.asList( new Transaction(1000L), new Transaction(2500L), new Transaction(1500L) ); // 使用 Collectors.summingLong 计算总金额 long totalAmount = transactions.stream() .collect(Collectors.summingLong(Transaction::getAmount)); System.out.println("Total Amount: " + totalAmount); } @Getter static class Transaction { private final long amount; public Transaction(long l) { this.amount = l; } } } ``` ### Collectors.minBy和Collectors.maxBy #### minBy 求最小值 ```java public class StreamExample17 { public static void main(String[] args) { List people = Arrays.asList( new Person("Alice", 30), new Person("Bob", 25), new Person("Charlie", 35) ); // 使用 Collectors.minBy 找到年龄最小的人 Optional youngest = people.stream() .collect(Collectors.minBy(Comparator.comparingInt(Person::getAge))); youngest.ifPresent(person -> System.out.println("Youngest Person: " + person.getName() + ", Age: " + person.getAge())); } @Getter static class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } } } ``` #### maxBy 求最大值 ```java public class StreamExample18 { public static void main(String[] args) { List people = Arrays.asList( new Person("Alice", 30), new Person("Bob", 25), new Person("Charlie", 35) ); // 使用 Collectors.maxBy 找到年龄最大的人 Optional oldest = people.stream() .collect(Collectors.maxBy(Comparator.comparingInt(Person::getAge))); oldest.ifPresent(person -> System.out.println("Oldest Person: " + person.getName() + ", Age: " + person.getAge())); } @Getter static class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } } } ``` ### Collectors.summarizing #### Collectors.summarizingInt 求和转成类型 ```java public class StreamExample19 { public static void main(String[] args) { List people = Arrays.asList( new Person("Alice", 30), new Person("Bob", 25), new Person("Charlie", 35) ); // 使用 Collectors.summarizingInt 统计年龄信息 IntSummaryStatistics ageStats = people.stream() .collect(Collectors.summarizingInt(Person::getAge)); System.out.println("Count: " + ageStats.getCount()); System.out.println("Sum: " + ageStats.getSum()); System.out.println("Min: " + ageStats.getMin()); System.out.println("Max: " + ageStats.getMax()); System.out.println("Average: " + ageStats.getAverage()); } @Getter static class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } } } ``` #### Collectors.summarizingLong 求和转成类型 ```java public class StreamExample20 { public static void main(String[] args) { List transactions = Arrays.asList( new Transaction(1000L), new Transaction(2500L), new Transaction(1500L) ); // 使用 Collectors.summarizingLong 统计金额信息 LongSummaryStatistics amountStats = transactions.stream() .collect(Collectors.summarizingLong(Transaction::getAmount)); System.out.println("Count: " + amountStats.getCount()); System.out.println("Sum: " + amountStats.getSum()); System.out.println("Min: " + amountStats.getMin()); System.out.println("Max: " + amountStats.getMax()); System.out.println("Average: " + amountStats.getAverage()); } @Getter static class Transaction { private final long amount; public Transaction(long amount) { this.amount = amount; } } } ``` #### Collectors.summarizingDouble 求和转成类型 ```java public class StreamExample21 { public static void main(String[] args) { List products = Arrays.asList( new Product("Laptop", 1200.50), new Product("Phone", 800.75), new Product("Tablet", 300.00) ); // 使用 Collectors.summarizingDouble 统计价格信息 DoubleSummaryStatistics priceStats = products.stream() .collect(Collectors.summarizingDouble(Product::getPrice)); System.out.println("Count: " + priceStats.getCount()); System.out.println("Sum: " + priceStats.getSum()); System.out.println("Min: " + priceStats.getMin()); System.out.println("Max: " + priceStats.getMax()); System.out.println("Average: " + priceStats.getAverage()); } @Getter static class Product { private final String name; private final double price; public Product(String name, double price) { this.name = name; this.price = price; } } } ``` ### Collectors.partitioningBy 以Boolean为 key的分组,key为Boolean值,后面是value值,属于Map集合 ```java public class StreamExample22 { public static void main(String[] args) { List people = Arrays.asList( new Person("Alice", 30), new Person("Bob", 17), new Person("Charlie", 25), new Person("David", 15) ); // 使用 Collectors.partitioningBy 按年龄分组 Map> partitionedByAge = people.stream() .collect(Collectors.partitioningBy(person -> person.getAge() >= 18)); // 输出结果 System.out.println("成年人:"); partitionedByAge.get(true).forEach(person -> System.out.println(person.getName())); System.out.println("未成年人:"); partitionedByAge.get(false).forEach(person -> System.out.println(person.getName())); } @Getter static class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } } } ```