# Java Stream详解

## 创建Stream

### Stream.builder()创建

```java
Stream<Integer> build = Stream.<Integer>builder()
        .add(1)
        .add(12)
        .add(3)
        .add(34)
        .build();
```

### Stream.of创建

```java
Stream<Integer> integerStream = Stream.of(1, 2, 34, 5);
```

### 空Stream创建

```java
Stream<Object> objectStream = Stream.empty();
```

### Stream.generate创建

如果不加限制运行时会一直创建像死循环一样

```java
// Stream.generate创建
Stream<Integer> 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<Map.Entry<String, String>>

```java
// 创建Stream<Map.Entry<String, String>>
Stream<Map.Entry<String, String>> stream = new HashMap<String, String>() {{
    put("a", "b");
    put("c", "d");
}}.entrySet().stream();
```

### Files中的Stream

```java
// Files中的Stream
Stream<String> lines = Files.lines(Paths.get("xxx.md"), StandardCharsets.UTF_8);
```

## Stream的操作

### distinct操作

```java
Stream<Object> 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<Integer> list = new ArrayList<>() {{
    add(1);
    add(2);
    add(2);
    add(3);
    add(3);
    add(4);
}};
List<ArrayList<Integer>> 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<Integer> 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<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> upperCaseNames = names.stream()
                                   .map(String::toUpperCase)
                                   .collect(Collectors.toList());
```

### toSet

将元素输出到 Set

```java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Set<String> uniqueNames = names.stream()
                                .collect(Collectors.toSet());
```

### toMap

将元素输出到 Map

- 2个参数：key，value
- 3个参数：key，value，处理key冲突问题
- 4个参数：key，value，处理key冲突问题，转换map类型

```java
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Map<String, Integer> nameLengthMap = names.stream()
                                          .collect(Collectors.toMap(name -> name, String::length));
```

### reduce

语法

```java
Optional<T> reduce(BinaryOperator<T> accumulator)
Optional<T> reduce(T identity, BinaryOperator<T> accumulator)
```

使用

```java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 使用 reduce 求和
Optional<Integer> 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<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper)
```

使用

```java
public class StreamExample07 {
    public static void main(String[] args) {
        List<Product> 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<Person> people = Arrays.asList(
                new Person("Alice", 30),
                new Person("Bob", 25),
                new Person("Charlie", 30),
                new Person("David", 25)
        );

        // 根据年龄将一组人分组
        Map<Integer, List<Person>> groupedByAge = people.stream()
                .collect(Collectors.groupingBy(Person::getAge));

        // 自定义收集器：可以传递第二个参数来指定下游收集器。
        Map<Integer, Long> groupedByAgeCount = people.stream()
                .collect(Collectors.groupingBy(Person::getAge, Collectors.counting()));

        // 多级分组：可以嵌套使用 groupingBy 进行多级分组。
        Map<Integer, Map<String, List<Person>>> 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<Long> numbers = Arrays.asList(1L, 2L, 3L, 4L, 5L);
double averagingLongNumbers = numbers.stream()
        .collect(Collectors.averagingLong(Long::longValue));
System.out.println("Average: " + averagingLongNumbers);

// averagingDouble
List<Double> 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<Integer> 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<Person> 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<Person> 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<Person> 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<Integer> 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<Person> 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<Person> 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<Product> 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<Transaction> 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<Person> people = Arrays.asList(
                new Person("Alice", 30),
                new Person("Bob", 25),
                new Person("Charlie", 35)
        );

        // 使用 Collectors.minBy 找到年龄最小的人
        Optional<Person> 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<Person> people = Arrays.asList(
                new Person("Alice", 30),
                new Person("Bob", 25),
                new Person("Charlie", 35)
        );

        // 使用 Collectors.maxBy 找到年龄最大的人
        Optional<Person> 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<Person> 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<Transaction> 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<Product> 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<Person> people = Arrays.asList(
                new Person("Alice", 30),
                new Person("Bob", 17),
                new Person("Charlie", 25),
                new Person("David", 15)
        );

        // 使用 Collectors.partitioningBy 按年龄分组
        Map<Boolean, List<Person>> 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;
        }
    }
}
```