MultiThread/README/Java Stream详解.md

23 KiB
Raw Blame History

Java Stream详解

创建Stream

Stream.builder()创建

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

Stream.of创建

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

空Stream创建

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

Stream.generate创建

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

// 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创建创建

// IntStream创建[1,10)
IntStream.range(1, 10)
        .forEach(System.out::println);

IntStream.rangeClosed创建闭区间

// 创建闭区间[1,10]
IntStream.rangeClosed(1,10)
        .forEach(System.out::println);

Arrays.asList创建

// Arrays.asList创建
Arrays.asList("a","b","c","d","e","f")
        .forEach(System.out::println);

创建Stream<Map.Entry<String, String>>

// 创建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

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

Stream的操作

distinct操作

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操作

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操作

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操作

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操作

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修改了其中的年龄那么这个值会被改变

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操作

排序操作,也可以指定内容进行排序

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中也有这个

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操作

// 需要满足所有元素都匹配条件
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操作

// 找到第一个数字
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那么后面就无法再跟其它流函数

计数、求和、最小值、最大值

// 计数
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

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> upperCaseNames = names.stream()
                                   .map(String::toUpperCase)
                                   .collect(Collectors.toList());

toSet

将元素输出到 Set

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

toMap

将元素输出到 Map

  • 2个参数keyvalue
  • 3个参数keyvalue处理key冲突问题
  • 4个参数keyvalue处理key冲突问题转换map类型
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Map<String, Integer> nameLengthMap = names.stream()
                                          .collect(Collectors.toMap(name -> name, String::length));

reduce

语法

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

使用

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

语法

static Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper)

使用

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类型
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 + ")";
        }
    }
}

输出:

{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

求平均值

// 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

先计算平均年龄,之后将计算结果转为整数,可以理解为:先收集之后再干嘛

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类似

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先操作(此操作会可以改变其类似),之后在做处理

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个参数将元素连接传入第一个参数进行分割第二个参数是整个处理完成元素的前缀第三个参数是整个处理完成的后缀
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

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

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

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

求最小值

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

求最大值

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

求和转成类型

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

求和转成类型

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

求和转成类型

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集合

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;
        }
    }
}