20 个实例玩转 Java 8 Stream

news2024/11/18 23:25:39

20 个实例玩转 Java 8 Stream

在这里插入图片描述

1、Stream概述

Java 8 是一个非常成功的版本,这个版本新增的 Stream,配合同版本出现的 Lambda,给我们操作集合

Collection 提供了极大的便利。

那么什么是 Stream?

Stream 将要处理的元素集合看作一种流,在流的过程中,借助 Stream API 对流中的元素进行操作,比如:

筛选、排序、聚合等。

Stream 可以由数组或集合创建,对流的操作分为两种:

1、中间操作,每次返回一个新的流,可以有多个。

2、终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或

值。

另外,Stream 有几个特性:

1、stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。

2、stream不会改变数据源,通常情况下会产生一个新的集合或一个值。

3、stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。

2、Stream的创建

Stream 可以通过集合数组创建。

package com.stream.test1;

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class Test1 {

    public static void main(String[] args) {
        a1();
        a2();
        a3();
    }

    /**
     * 1.通过 `java.util.Collection.stream()` 方法用集合创建流
     */
    public static void a1() {
        // 通过 `java.util.Collection.stream()` 方法用集合创建流
        List<String> list = Arrays.asList("a", "b", "c");
        // 创建一个顺序流
        Stream<String> stream = list.stream();
        // 创建一个并行流
        Stream<String> parallelStream = list.parallelStream();
        stream.forEach(System.out::println);
        parallelStream.forEach(System.out::println);
    }

    /**
     * 2.使用`java.util.Arrays.stream(T[] array)`方法用数组创建流
     */
    public static void a2() {
        // 使用`java.util.Arrays.stream(T[] array)`方法用数组创建流
        int[] array = {1, 3, 5, 6, 8};
        IntStream intStream = Arrays.stream(array);
        intStream.forEach(System.out::println);
    }

    /**
     * 3.使用`Stream`的静态方法:`of()、iterate()、generate()`
     */
    public static void a3() {
        // 使用`Stream`的静态方法:`of()、iterate()、generate()`
        Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6);
        stream1.forEach(System.out::println);
        Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
        stream2.forEach(System.out::println);
        Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
        stream3.forEach(System.out::println);
    }

}
# 程序输出
a
b
c
b
c
a
----------
1
3
5
6
8
----------
1
2
3
4
5
6
0
3
6
9
0.7408527501587401
0.5636765964381898
0.36334100319238094

stream 和 parallelStream 的简单区分:stream 是顺序流,由主线程按顺序对流执行操作,而 parallelStream 是

并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。例如筛选集合中的

奇数,两者的处理不同之处:

在这里插入图片描述

如果流中的数据量足够大,并行流可以加快处速度。

Java 8 创建 Stream 的 10 种方式:

(1)、Stream.of 可变参数

Stream<String> stream1 = Stream.of("A", "B", "C");
System.out.println("stream1:" + stream1.collect(joining()));

程序输出:stream1: ABC

(2)、Stream.of 数组

String[] values = new String[]{"A", "B", "C"};
Stream<String> stream2 = Stream.of(values);
System.out.println("stream2:" + stream2.collect(joining()));

程序输出:stream2: ABC

看 Stream.of 源码,上面这两种方式其实就是第三种方式的包装版。

public static<T> Stream<T> of(T... values) {
    return Arrays.stream(values);
}

我们直接使用源码中的方式也是一样的。

(3)、Arrays.stream

String[] values = new String[]{"A", "B", "C"};
Stream<String> stream3 = Arrays.stream(values);
System.out.println("stream3:" + stream3.collect(joining()));

程序输出:stream3: ABC

(4)、List

List<String> list = Arrays.asList("A", "B", "C");
Stream<String> stream4 = list.stream();
System.out.println("stream4:" + stream4.collect(joining()));

程序输出:stream4: ABC

(5)、Set

Set<String> set = new HashSet<>(Arrays.asList("A", "B", "C"));
Stream<String> stream5 = set.stream();
System.out.println("stream5:" + stream5.collect(joining()));

程序输出:stream5: ABC

(6)、Map

Map<String, String> map = new HashMap<>();
map.put("1", "A");
map.put("2", "B");
map.put("3", "C");
Stream<String> stream6 = map.values().stream();
System.out.println("stream6:" + stream6.collect(joining()));

程序输出:stream6: ABC

(7)、Stream.iterate

Stream<String> stream7 = Stream.iterate("A", e -> String.valueOf((char) (e.charAt(0) + 1))).limit(3);
System.out.println("stream7:" + stream7.collect(joining()));

程序输出:stream7: ABC

(8)、Pattern

String value = "A B C";
Stream<String> stream8 = Pattern.compile("\\W").splitAsStream(value);
System.out.println("stream8:" + stream8.collect(joining()));

程序输出:stream8: ABC

(9)、Files.lines

try {
    Stream<String> stream9 = Files.lines(Paths.get("d:/data.txt"));
    System.out.println("stream9:" + stream9.collect(joining()));
} catch (IOException e) {
    e.printStackTrace();
}

data.txt文件内容如下:

A
B
C

程序输出:stream9: ABC

(10)、Stream.generate

Stream<String> stream10 = Stream.generate(() -> "A").limit(3);
System.out.println("stream10:" + stream10.collect(joining()));

程序输出:stream10: AAA

(11)、顺序流转换为并行流

除了直接创建并行流,还可以通过 parallel() 把顺序流转换成并行流:

Optional<Integer> findFirst = list.stream().parallel().filter(x->x>6).findFirst();

完整代码:

package com.stream.test2;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Stream;

public class Test2 {

    public static void main(String[] args) {
        a1();
        System.out.println("----------");
        a2();
        System.out.println("----------");
        a3();
        System.out.println("----------");
        a4();
        System.out.println("----------");
        a5();
        System.out.println("----------");
        a6();
        System.out.println("----------");
        a7();
        System.out.println("----------");
        a8();
        System.out.println("----------");
        a9();
        System.out.println("----------");
        a10();
        System.out.println("----------");
        a11();
    }

    /**
     * 1.Stream.of 可变参数
     */
    public static void a1() {
        Stream<String> stream1 = Stream.of("A", "B", "C");
        stream1.forEach(System.out::println);
    }

    /**
     * 2.Stream.of 数组
     */
    public static void a2() {
        String[] values = new String[]{"A", "B", "C"};
        Stream<String> stream2 = Stream.of(values);
        stream2.forEach(System.out::println);
    }

    /**
     * 3.Arrays.stream
     */
    public static void a3() {
        String[] values = new String[]{"A", "B", "C"};
        Stream<String> stream3 = Arrays.stream(values);
        stream3.forEach(System.out::println);
    }

    /**
     * 4.List
     */
    public static void a4() {
        List<String> list = Arrays.asList("A", "B", "C");
        Stream<String> stream4 = list.stream();
        stream4.forEach(System.out::println);
    }

    /**
     * 5.Set
     */
    public static void a5() {
        Set<String> set = new HashSet<>(Arrays.asList("A", "B", "C"));
        Stream<String> stream5 = set.stream();
        stream5.forEach(System.out::println);
    }

    /**
     * 6.Map
     */
    public static void a6() {
        Map<String, String> map = new HashMap<>();
        map.put("1", "A");
        map.put("2", "B");
        map.put("3", "C");
        Stream<String> stream6 = map.values().stream();
        stream6.forEach(System.out::println);
    }


    /**
     * 7.Stream.iterate
     */
    public static void a7() {
        Stream<String> stream7 = Stream.iterate("A", e -> String.valueOf((char) (e.charAt(0) + 1))).limit(3);
        stream7.forEach(System.out::println);
    }


    /**
     * 8.Pattern
     */
    public static void a8() {
        String value = "A B C";
        Stream<String> stream8 = Pattern.compile("\\W").splitAsStream(value);
        stream8.forEach(System.out::println);
    }

    /**
     * 9.Files.lines
     */
    public static void a9() {
        try {
            Stream<String> stream9 = Files.lines(Paths.get("D:\\data.txt"));
            stream9.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 10.Stream.generate
     */
    public static void a10() {
        Stream<String> stream10 = Stream.generate(() -> "A").limit(3);
        stream10.forEach(System.out::println);
    }

    /**
     * 11.通过`parallel()`把顺序流转换成并行流
     */
    public static void a11() {
        List<Integer> list = Arrays.asList(1, 7, 14);
        Optional<Integer> findFirst = list.stream().parallel().filter(x -> (x > 6)).findFirst();
        System.out.println(findFirst.get());
    }

}
# 程序输出
A
B
C
----------
A
B
C
----------
A
B
C
----------
A
B
C
----------
A
B
C
----------
A
B
C
----------
A
B
C
----------
A
B
C
----------
11
22
----------
A
A
A
----------
7

3、Stream的使用

在使用 stream 之前,先理解一个概念:Optional。

Optional 类是一个可以为 null 的容器对象。如果值存在则 isPresent() 方法会返回 true,调用 get() 方法会返

回该对象。

3.1 员工类

package com.stream.common;

public class Person {

    /**
     * 姓名
     */
    private String name;

    /**
     * 薪资
     */
    private int salary;

    /**
     * 年龄
     */
    private int age;

    /**
     * 性别
     */
    private String sex;

    /**
     * 地区
     */
    private String area;

    /**
     * 构造方法
     *
     * @param name
     * @param salary
     * @param age
     * @param sex
     * @param area
     */
    public Person(String name, int salary, int age, String sex, String area) {
        this.name = name;
        this.salary = salary;
        this.age = age;
        this.sex = sex;
        this.area = area;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getArea() {
        return area;
    }

    public void setArea(String area) {
        this.area = area;
    }

}

3.2 遍历/匹配(foreach/find/match)

Stream 也是支持类似集合的遍历和匹配元素的,只是 Stream 中的元素是以 Optional 类型存在的。Stream 的遍

历、匹配非常简单。

在这里插入图片描述

package com.stream.test3;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class Test3 {

    /**
     * 遍历/匹配(foreach/find/match)
     *
     * @param args
     */
    public static void main(String[] args) {

        List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
        // 遍历输出符合条件的元素
        list.stream().filter(x -> x > 6).forEach(System.out::println);
        // 匹配第一个
        Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
        // 匹配任意(适用于并行流)
        Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
        // 是否包含符合特定条件的元素
        boolean anyMatch = list.stream().anyMatch(x -> x < 6);
        System.out.println("匹配第一个值:" + findFirst.get());
        System.out.println("匹配任意一个值:" + findAny.get());
        System.out.println("是否存在大于6的值:" + anyMatch);
    }
}
# 程序输出
7
9
8
匹配第一个值:7
匹配任意一个值:8
是否存在大于6的值:true

3.3 筛选(filter)

筛选,是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。

在这里插入图片描述

package com.stream.test4;

import com.stream.common.Person;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Test4 {

    /**
     * 筛选(filter)
     *
     * @param args
     */
    public static void main(String[] args) {
        a1();
        System.out.println("----------");
        a2();
    }

    /**
     * 案例一:筛选出`Integer`集合中大于7的元素,并打印出来
     */
    public static void a1() {
        List<Integer> list = Arrays.asList(6, 7, 3, 8, 1, 2, 9);
        Stream<Integer> stream = list.stream();
        stream.filter(x -> x > 7).forEach(System.out::println);
    }

    /**
     * 案例二:筛选员工中工资高于8000的人,并形成新的集合。
     */
    public static void a2() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));
        personList.add(new Person("Owen", 9500, 25, "male", "New York"));
        personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
        List<String> filterList = personList.stream().filter(x -> x.getSalary() > 8000).map(Person::getName).collect(Collectors.toList());
        System.out.print("高于8000的员工姓名:" + filterList);
    }
}
# 程序输出
8
9
----------
高于8000的员工姓名:[Tom, Anni, Owen]

3.4 聚合(max/min/count)

max、min、count 这些字眼你一定不陌生,没错,在mysql中我们常用它们进行数据统计。Java stream中也引

入了这些概念和用法,极大地方便了我们对集合、数组的数据统计工作。

在这里插入图片描述

package com.stream.test5;

import com.stream.common.Person;

import java.util.*;

public class Test5 {

    /**
     * 聚合(max/min/count)
     *
     * @param args
     */
    public static void main(String[] args) {
        a1();
        System.out.println("----------");
        a2();
        System.out.println("----------");
        a3();
        System.out.println("----------");
        a4();
    }

    /**
     * 案例一:获取`String`集合中最长的元素。
     */
    public static void a1() {
        List<String> list = Arrays.asList("adnm", "admmt", "pot", "xbangd", "weoujgsd");
        Optional<String> max = list.stream().max(Comparator.comparing(String::length));
        System.out.println("最长的字符串:" + max.get());
    }

    /**
     * 案例二:获取`Integer`集合中的最大值。
     */
    public static void a2() {
        List<Integer> list = Arrays.asList(7, 6, 9, 4, 11, 6);
        // 自然排序
        Optional<Integer> max = list.stream().max(Integer::compareTo);
        // 自定义排序
        Optional<Integer> max2 = list.stream().max(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });
        System.out.println("自然排序的最大值:" + max.get());
        System.out.println("自定义排序的最大值:" + max2.get());
    }

    /**
     * 案例三:获取员工工资最高的人。
     */
    public static void a3() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));
        personList.add(new Person("Owen", 9500, 25, "male", "New York"));
        personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
        Optional<Person> max = personList.stream().max(Comparator.comparingInt(Person::getSalary));
        System.out.println("员工工资最大值:" + max.get().getSalary());
    }

    /**
     * 案例四:计算`Integer`集合中大于6的元素的个数。
     */
    public static void a4() {
        List<Integer> list = Arrays.asList(7, 6, 4, 8, 2, 11, 9);
        long count = list.stream().filter(x -> x > 6).count();
        System.out.println("list中大于6的元素个数:" + count);
    }

}
# 程序输出
最长的字符串:weoujgsd
----------
自然排序的最大值:11
自定义排序的最大值:11
----------
员工工资最大值:9500
----------
list中大于6的元素个数:4

3.5 映射(map/flatMap)

映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为 map 和 flatMap:

  • map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  • flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

在这里插入图片描述

package com.stream.test6;

import com.stream.common.Person;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Test6 {

    /**
     * 映射(map/flatMap)
     *
     * @param args
     */
    public static void main(String[] args) {
        a1();
        System.out.println("----------");
        a2();
        System.out.println("----------");
        a3();
    }

    /**
     * 案例一:英文字符串数组的元素全部改为大写。整数数组每个元素+3
     */
    public static void a1() {
        String[] strArr = {"abcd", "bcdd", "defde", "fTr"};
        List<String> strList = Arrays.stream(strArr).map(String::toUpperCase).collect(Collectors.toList());
        List<Integer> intList = Arrays.asList(1, 3, 5, 7, 9, 11);
        List<Integer> intListNew = intList.stream().map(x -> x + 3).collect(Collectors.toList());
        System.out.println("每个元素大写:" + strList);
        System.out.println("每个元素+3:" + intListNew);
    }

    /**
     * 案例二:将员工的薪资全部增加1000
     */
    public static void a2() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));
        personList.add(new Person("Owen", 9500, 25, "male", "New York"));
        personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
        // 不改变原来员工集合的方式
        List<Person> personListNew = personList.stream().map(person -> {
            Person personNew = new Person(person.getName(), 0, 0, null, null);
            personNew.setSalary(person.getSalary() + 10000);
            return personNew;
        }).collect(Collectors.toList());
        System.out.println("一次改动前:" + personList.get(0).getName() + "-->" + personList.get(0).getSalary());
        System.out.println("一次改动后:" + personListNew.get(0).getName() + "-->" + personListNew.get(0).getSalary());
        // 改变原来员工集合的方式
        List<Person> personListNew2 = personList.stream().map(person -> {
            person.setSalary(person.getSalary() + 10000);
            return person;
        }).collect(Collectors.toList());
        System.out.println("二次改动前:" + personList.get(0).getName() + "-->" + personListNew.get(0).getSalary());
        System.out.println("二次改动后:" + personListNew2.get(0).getName() + "-->" + personListNew.get(0).getSalary());
    }

    /**
     * 案例三:将两个字符数组合并成一个新的字符数组
     */
    public static void a3() {
        List<String> list = Arrays.asList("m,k,l,a", "1,3,5,7");
        List<String> listNew = list.stream().flatMap(s -> {
            // 将每个元素转换成一个stream
            String[] split = s.split(",");
            Stream<String> s2 = Arrays.stream(split);
            return s2;
        }).collect(Collectors.toList());

        System.out.println("处理前的集合:" + list);
        System.out.println("处理后的集合:" + listNew);
    }
}
# 程序输出
每个元素大写:[ABCD, BCDD, DEFDE, FTR]
每个元素+3:[4, 6, 8, 10, 12, 14]
----------
一次改动前:Tom-->8900
一次改动后:Tom-->18900
二次改动前:Tom-->18900
二次改动后:Tom-->18900
----------
处理前的集合:[m,k,l,a, 1,3,5,7]
处理后的集合:[m, k, l, a, 1, 3, 5, 7]

3.6 归约(reduce)

归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。

在这里插入图片描述

package com.stream.test7;

import com.stream.common.Person;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class Test7 {

    /**
     * 归约(reduce)
     *
     * @param args
     */
    public static void main(String[] args) {
        a1();
        System.out.println("----------");
        a2();
    }


    /**
     * 案例一:求`Integer`集合的元素之和、乘积和最大值
     */
    public static void a1() {
        List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4);
        // 求和方式1
        Optional<Integer> sum = list.stream().reduce((x, y) -> x + y);
        // 求和方式2
        Optional<Integer> sum2 = list.stream().reduce(Integer::sum);
        // 求和方式3
        Integer sum3 = list.stream().reduce(0, Integer::sum);
        // 求乘积
        Optional<Integer> product = list.stream().reduce((x, y) -> x * y);
        // 求最大值方式1
        Optional<Integer> max = list.stream().reduce((x, y) -> x > y ? x : y);
        // 求最大值写法2
        Integer max2 = list.stream().reduce(1, Integer::max);
        System.out.println("list求和:" + sum.get() + "," + sum2.get() + "," + sum3);
        System.out.println("list求积:" + product.get());
        System.out.println("list求和:" + max.get() + "," + max2);
    }

    /**
     * 案例二:求所有员工的工资之和和最高工资
     */
    public static void a2() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));
        personList.add(new Person("Owen", 9500, 25, "male", "New York"));
        personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
        // 求工资之和方式1:
        Optional<Integer> sumSalary = personList.stream().map(Person::getSalary).reduce(Integer::sum);
        // 求工资之和方式2:
        Integer sumSalary2 = personList.stream().reduce(0, (sum, p) -> sum += p.getSalary(), (sum1, sum2) -> sum1 + sum2);
        // 求工资之和方式3:
        Integer sumSalary3 = personList.stream().reduce(0, (sum, p) -> sum += p.getSalary(), Integer::sum);
        // 求最高工资方式1:
        Integer maxSalary = personList.stream().reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(), Integer::max);
        // 求最高工资方式2:
        Integer maxSalary2 = personList.stream().reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(), (max1, max2) -> max1 > max2 ? max1 : max2);
        System.out.println("工资之和:" + sumSalary.get() + "," + sumSalary2 + "," + sumSalary3);
        System.out.println("最高工资:" + maxSalary + "," + maxSalary2);
    }

}
# 程序输出
list求和:29,29,29
list求积:2112
list求和:11,11
----------
工资之和:49300,49300,49300
最高工资:9500,9500

3.7 收集(collect)

collect,收集,可以说是内容最繁多、功能最丰富的部分了。从字面上去理解,就是把一个流收集起来,最终可以

是收集成一个值也可以收集成一个新的集合。

collect 主要依赖 java.util.stream.Collectors 类内置的静态方法。

3.6.1 归集(toList/toSet/toMap)

因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toListtoSet

toMap比较常用,另外还有toCollectiontoConcurrentMap等复杂一些的用法。

package com.stream.test8;

import com.stream.common.Person;

import java.util.*;
import java.util.stream.Collectors;

public class Test8 {

    /**
     * 归集(toList/toSet/toMap)
     *
     * @param args
     */
    public static void main(String[] args) {
        a();
    }

    /**
     * toList`、`toSet`和`toMap`
     */
    public static void a() {
        List<Integer> list = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20);
        List<Integer> listNew = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
        Set<Integer> set = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));
        Map<?, Person> map = personList.stream().filter(p -> p.getSalary() > 8000)
                .collect(Collectors.toMap(Person::getName, p -> p));
        System.out.println("toList:" + listNew);
        System.out.println("toSet:" + set);
        System.out.println("toMap:" + map);
    }

}

运行结果:

# 程序输出
toList:[6, 4, 6, 6, 20]
toSet:[4, 20, 6]
toMap:{Tom=com.stream.common.Person@2dda6444, Anni=com.stream.common.Person@5e9f23b4}
3.6.2 统计(count/averaging)

Collectors 提供了一系列用于数据统计的静态方法:

  • 计数:count
  • 平均值:averagingIntaveragingLongaveragingDouble
  • 最值:maxByminBy
  • 求和:summingIntsummingLongsummingDouble
  • 统计以上所有:summarizingIntsummarizingLongsummarizingDouble
package com.stream.test9;

import com.stream.common.Person;

import java.util.ArrayList;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class Test9 {

    /**
     * 统计(count/averaging)
     *
     * @param args
     */
    public static void main(String[] args) {
        a();
    }

    /**
     * 案例:统计员工人数、平均工资、工资总额、最高工资
     */
    public static void a() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        // 求总数
        Long count = personList.stream().collect(Collectors.counting());
        // 求平均工资
        Double average = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
        // 求最高工资
        Optional<Integer> max = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compare));
        // 求工资之和
        Integer sum = personList.stream().collect(Collectors.summingInt(Person::getSalary));
        // 一次性统计所有信息
        DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
        System.out.println("员工总数:" + count);
        System.out.println("员工平均工资:" + average);
        System.out.println("员工工资总和:" + sum);
        System.out.println("员工工资所有统计:" + collect);
    }
}
# 程序输出
员工总数:3
员工平均工资:7900.0
员工工资总和:23700
员工工资所有统计:DoubleSummaryStatistics{count=3, sum=23700.000000, min=7000.000000, average=7900.000000, max=8900.000000}
3.6.3 分组(partitioningBy/groupingBy)
  • 分区:将 stream 按条件分为两个 Map,比如员工按薪资是否高于8000分为两部分。
  • 分组:将集合分为多个Map,比如员工按性别分组。有单级分组和多级分组。

在这里插入图片描述

package com.stream.test10;

import com.stream.common.Person;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Test10 {

    /**
     * 分组(partitioningBy/groupingBy)
     *
     * @param args
     */
    public static void main(String[] args) {
        a();
    }

    /**
     * 案例:将员工按薪资是否高于8000分为两部分;将员工按性别和地区分组
     */
    public static void a() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 27, "female", "New York"));
        personList.add(new Person("Owen", 9500, 22, "male", "New York"));
        personList.add(new Person("Alisa", 7900, 20, "female", "New York"));
        // 将员工按薪资是否高于8000分组
        Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
        // 将员工按性别分组
        Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));
        // 将员工先按性别分组,再按地区分组
        Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
        System.out.println("员工按薪资是否大于8000分组情况:" + part);
        System.out.println("员工按性别分组情况:" + group);
        System.out.println("员工按性别、地区:" + group2);
    }
}
# 程序输出
员工按薪资是否大于8000分组情况:{false=[com.stream.common.Person@5e9f23b4, com.stream.common.Person@4783da3f, com.stream.common.Person@378fd1ac], true=[com.stream.common.Person@49097b5d, com.stream.common.Person@6e2c634b, com.stream.common.Person@37a71e93]}
员工按性别分组情况:{female=[com.stream.common.Person@4783da3f, com.stream.common.Person@6e2c634b, com.stream.common.Person@378fd1ac], male=[com.stream.common.Person@49097b5d, com.stream.common.Person@5e9f23b4, com.stream.common.Person@37a71e93]}
员工按性别、地区:{female={New York=[com.stream.common.Person@6e2c634b, com.stream.common.Person@378fd1ac], Washington=[com.stream.common.Person@4783da3f]}, male={New York=[com.stream.common.Person@49097b5d, com.stream.common.Person@37a71e93], Washington=[com.stream.common.Person@5e9f23b4]}}
3.6.4 接合(joining)

joining 可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。

package com.stream.test11;

import com.stream.common.Person;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Test11 {

    /**
     * 接合(joining)
     *
     * @param args
     */
    public static void main(String[] args) {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        String names = personList.stream().map(p -> p.getName()).collect(Collectors.joining(","));
        System.out.println("所有员工的姓名:" + names);
        List<String> list = Arrays.asList("A", "B", "C");
        String string = list.stream().collect(Collectors.joining("-"));
        System.out.println("拼接后的字符串:" + string);
    }
}
# 程序输出
所有员工的姓名:Tom,Jack,Lily
拼接后的字符串:A-B-C
3.6.5 归约(reducing)

Collectors 类提供的 reducing 方法,相比于 stream 本身的 reduce 方法,增加了对自定义归约的支持。

package com.stream.test12;

import com.stream.common.Person;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class Test12 {

    /**
     * 归约(reducing)
     *
     * @param args
     */
    public static void main(String[] args) {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        // 每个员工减去起征点后的薪资之和
        Integer sum = personList.stream().collect(Collectors.reducing(0, Person::getSalary, (i, j) -> (i + j - 5000)));
        System.out.println("员工扣税薪资总和:" + sum);
        // stream的reduce
        Optional<Integer> sum2 = personList.stream().map(Person::getSalary).reduce(Integer::sum);
        System.out.println("员工薪资总和:" + sum2.get());
    }
}
# 程序输出
员工扣税薪资总和:8700
员工薪资总和:23700

3.7 排序(sorted)

sorted,中间操作。有两种排序:

  • sorted():自然排序,流中元素需实现Comparable接口
  • sorted(Comparator com):Comparator排序器自定义排序
package com.stream.test13;

import com.stream.common.Person;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class Test13 {

    /**
     * 排序(sorted)
     *
     * @param args
     */
    public static void main(String[] args) {
        a();
    }

    /**
     * 案例:将员工按工资由高到低(工资一样则按年龄由大到小)排序
     */
    public static void a() {
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Sherry", 9000, 24, "female", "New York"));
        personList.add(new Person("Tom", 8900, 22, "male", "Washington"));
        personList.add(new Person("Jack", 9000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 8800, 26, "male", "New York"));
        personList.add(new Person("Alisa", 9000, 26, "female", "New York"));
        // 按工资升序排序(自然排序)
        List<String> newList = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName).collect(Collectors.toList());
        // 按工资倒序排序
        List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed()).map(Person::getName).collect(Collectors.toList());
        // 先按工资再按年龄升序排序
        List<String> newList3 = personList.stream().sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName).collect(Collectors.toList());
        // 先按工资再按年龄自定义排序(降序)
        List<String> newList4 = personList.stream().sorted((p1, p2) -> {
            if (p1.getSalary() == p2.getSalary()) {
                return p2.getAge() - p1.getAge();
            } else {
                return p2.getSalary() - p1.getSalary();
            }
        }).map(Person::getName).collect(Collectors.toList());
        System.out.println("按工资升序排序:" + newList);
        System.out.println("按工资降序排序:" + newList2);
        System.out.println("先按工资再按年龄升序排序:" + newList3);
        System.out.println("先按工资再按年龄自定义降序排序:" + newList4);
    }
}
# 程序输出
按工资升序排序:[Lily, Tom, Sherry, Jack, Alisa]
按工资降序排序:[Sherry, Jack, Alisa, Tom, Lily]
先按工资再按年龄升序排序:[Lily, Tom, Sherry, Jack, Alisa]
先按工资再按年龄自定义降序排序:[Alisa, Jack, Sherry, Tom, Lily]

3.8 提取/组合

流也可以进行合并、去重、限制、跳过等操作。

在这里插入图片描述

package com.stream.test14;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Test14 {

    /**
     * 提取/组合
     *
     * @param args
     */
    public static void main(String[] args) {
        String[] arr1 = {"a", "b", "c", "d"};
        String[] arr2 = {"d", "e", "f", "g"};
        Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);
        // concat:合并两个流 distinct:去重
        List<String> newList = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
        // limit:限制从流中获得前n个数据
        List<Integer> collect = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
        // skip:跳过前n个数据
        List<Integer> collect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());
        System.out.println("流合并:" + newList);
        System.out.println("limit:" + collect);
        System.out.println("skip:" + collect2);
    }
}
# 程序输出
流合并:[a, b, c, d, e, f, g]
limit:[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
skip:[3, 5, 7, 9, 11]

至此,Stream 的常用功能介绍完毕!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1035883.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker部署MySQL8数据库

1、准备工作 docker pull mysql:8.0.27 Pwd"/data/software/mysql" mkdir ${Pwd}/{data,logs} -p chmod 777 ${Pwd}/logs2、添加配置文件 cat > ${Pwd}/my.cnf << EOF [mysqld] usermysql pid-file/var/run/mysqld/mysqld.pid socket/var/run/mysqld/mysq…

SQL和Python,哪个更容易自学?哪个更适合数据工作的编程新手?

如果你想从事数据工作&#xff0c;比如数据分析、数据开发、数据科学等&#xff0c;你可能会遇到这样的问题&#xff1a;SQL和Python哪个更容易自学&#xff1f;哪个更有用&#xff1f;哪个更有前途&#xff1f;其实这两种语言都是数据工作的重要技能&#xff0c;但它们的特点和…

react实现数据进度条展示组件

1.需求 在项目开发时&#xff0c;要展示一个操作的进度条&#xff0c;比如&#xff1a;要实现一个文件的上传下载进度条&#xff0c;或者实现类似拼夕夕砍一刀进度条&#xff0c;怎么实现呢&#xff1f;效果图如下&#xff1a; 对上面效果图说明&#xff1a; 进度条底色为棕黑色…

559. N 叉树的最大深度

给定一个 N 叉树&#xff0c;找到其最大深度。 最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。 N 叉树输入按层序遍历序列化表示&#xff0c;每组子节点由空值分隔&#xff08;请参见示例&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [1,null,3,2…

从统计语言模型到预训练语言模型---预训练语言模型(BERT,GPT,BART系列)

基于 Transformer 架构以及 Attention 机制&#xff0c;一系列预训练语言模型被不断提出。 ​BERT 2018 年 10 月&#xff0c; Google AI 研究院的 Jacob Devlin 等人提出了 BERT (Bidirectional Encoder Representation from Transformers ) 。具体的研究论文发布在 arXiv …

浅谈低压绝缘监测及定位系统在海上石油平台的研究与应用

安科瑞 华楠 摘要&#xff1a;海上石油平台低压系统与陆地电力系统有很大区别&#xff0c;其属于中性点绝缘系统&#xff0c;在出现单相接地故障时&#xff0c;系统允许带故障正常运行2 h&#xff0c;保证海上重要电气设备不会立即关停。现以渤海某海上平台为例&#xff0c;其…

LABVIEW 实战案例1--温度报警系统

图1 温度报警系统前面板 图2 温度报警系统后面板

1796_通过vmware打开VirtualBox虚拟机文件

全部学习汇总&#xff1a; GitHub - GreyZhang/toolbox: 常用的工具使用查询&#xff0c;非教程&#xff0c;仅作为自我参考&#xff01; 首先讲vdi格式转换成vmdk格式&#xff0c;以我自己的环境下的信息&#xff0c;处理如下&#xff1a; VBoxManage clonehd "LinuxMin…

Sentinel结合Nacos实现配置持久化(全面)

1、前言 我们在进行分布式系统的开发中&#xff0c;无论是在开发环境还是发布环境&#xff0c;配置一定不能是内存形式的&#xff0c;因为系统可能会在中途宕机或者重启&#xff0c;所以如果放在内存中&#xff0c;那么配置在服务停到就是就会消失&#xff0c;那么此时就需要重…

javascript 使用async/await简化异步操作实践

实现的功能简述&#xff1a; 新增申请单时&#xff0c;申请单的业务日期由两个因素决定&#xff1a; 异步获取的仓库的业务日期。异步获取的日期偏移天数规则。 业务日期 仓库的业务日期 偏移天数。比如仓库的业务日期是2023-01-01,偏移天数是5&#xff0c;那么最终的业务日期…

【轨道机器人】成功驱动伺服电机(学生电源、DCH调试软件、DH系列伺服驱动器)

1、硬件平台 工控机 学生电源 DH系列伺服驱动器 电机 调试平台&#xff1a;DCH 2、如何利用dch驱动电机 点击可驱动电机 下面的步骤是比较关键的几步&#xff1a; 3、遇到的问题 不能成功驱动电机&#xff0c;还和厂家那边打电话&#xff0c;询问 发现是这…

霍金《时间简史》A Brief History of Time 学习笔记(第二章)

CHAPTER 2 : SPACE & TIME Footnote: Second chapter. Mainly talks about spacetime. Footnote: “Thought Experiment”, which is quite common in the field of physics. False: Galileo dropping weights from the Tower of Pisa (Assertedly) True: Galileo rolling…

【企业级SpringBoot单体项目模板 】——Mybatis-plus自动代码生成

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;SpringBoot项目模版、企业级、模版☀️每日 一言&#xff1a;我们之所以这样认为&#xff0c;是因为他们这样说。他们之所以那样说&#xff0c;是因为他们想让我们那样认为。所以实践才是检验真理…

漏刻有时数据可视化Echarts组件开发(30):自定义方向的数据流向动画

let points = [{name: 市城市管理局,desc: {type: 1,},},{name: 科大讯飞,desc: {type: 2,},},{name: 市水利局,desc: {type: 1,},},{name: 市政法委,desc: {type: 1,},},{name: 市自然资源和规划局,desc: {type: 1,},},{name: 市生态环境局,desc: {type: 1,},},{name: 市大数据…

资源分享 | 情绪脑电研究公开数据集

SEED SEED数据集是由上海交大类脑计算与机器智能研究中心(BCMI)开发的。该数据集是基于脑电的情绪分类任务而设计的数据集。该数据集记录了15名被试在观看积极、中性和消极情绪电影片段时的EEG信号&#xff0c;每个视频片段的时间为3-5分钟。每个参与者重复采集三天&#xff0…

BST搜索二叉树

目录 二叉搜索树概念 ​编辑 1 二叉搜索树的构建 2. 二叉搜索树的删除 3二叉搜索树中放入元素 4. 二叉搜索树中元素的删除 5. 二叉搜索树中元素的遍历 6 二叉搜索树中元素的查找 7二叉搜索树的拷贝构造 二叉搜索树概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一…

【lesson10】fork创建进程的现象解答

文章目录 fork现象fork问题 fork现象 我们先来看一段代码。 大家觉得这段代码的printf会打印几次&#xff1f; 结果&#xff1a; 我们可以清楚的看到&#xff0c;第二个printf打印了2次。 我们再来看一段不可思议的代码&#xff1a; 运行结果&#xff1a; 我们可以看到这r…

编写Dockerfile

Dockerfile 编写Dockerfile 制作 FROM java:7 MAINTAINER bunny <邮箱qq.com> ADD easybbs-web-release-1.0.jar app.jar CMD java -jar app.jar构建 docker build -f ./my_dockerfile -t app:1.0 .启动 docker rm my_app docker ps -a docker run -d -p 9000:7070 …

前端教程-总览

现已经更新完毕图中教程汇总后期收集所有教程资料整理

【考研】2023暨南大学848答案 2020-2023 计算机基础综合 830答案

&#x1f525;&#x1f525; I 仓库 还在更新&#xff0c;敬请期待 &#x1f525;暨南大学计算机848报考信息汇总仓库 仓库内有20年真题答案 https://github.com/zhanjuex/JNU_848 备用仓库 (目录可能用不了 https://xindon.coding.net/public/open/JNU_848/git/files &#x1…