Java Stream流操作


前言

Java Stream 是 Java 8 中引入的一个新特性,它的出现主要是为了解决传统操作方式的一些问题,并提供更为简洁、灵活和高效的操作方式,可以大大提高代码的开发效率和质量。因此,在使用 Java 编程时,推荐使用 Stream 流来进行数据处理和操作。


一、Java Stream 简介

Java Stream 是一种处理集合数据的新方法,它提供了一种简单、高效、并行化的方式来处理集合数据。Java Stream 可以用于任何类型的集合数据,包括 List、Set、Map 等。

优点如下:

  1. 更为简洁和灵活:使用 Stream 流可以大大简化代码逻辑,避免繁琐的循环和条件判断,使代码更加简洁、易读和易维护。同时,Stream 流提供了丰富的中间操作和终止操作,可以根据具体的需求选择不同的操作方式,实现更为灵活和多样化的操作。

  2. 更高效的处理方式:Stream 流采用的是惰性求值的方式,即只有在终止操作时才会进行计算,避免了不必要的计算和内存占用。同时,Stream 流还可以利用多核处理器进行并行计算,提高处理效率和性能。

  3. 更为安全和可靠:Stream 流提供了类型检查和空指针检查等机制,避免了一些常见的编程错误和异常情况,提高了代码的安全性和可靠性。

  4. 更好的代码可读性:Stream 流提供了丰富的操作方法和语法糖,可以使代码更加简洁、易读和易懂,提高了代码的可读性和可维护性。


二、流与集合的区别

流(Stream)和集合(Collection)是 Java 中两种不同的概念,它们虽然都可以用来存储一组数据,但在使用方式、处理方式和特性上存在很大的区别。

2.1 数据存储方式

  1. 集合是一种数据结构,它可以存储一组对象或基本类型的值。常见的集合包括 List、Set、Map 等,它们都有自己的特点和适用场景。
  2. 流则是一种数据处理方式,它并不直接存储数据,而是对数据进行操作和处理。流可以从集合、数组、文件等数据源中获取数据,并将数据流式地传输到下一个操作中。

2.2 处理方式

  1. 集合提供了一系列的方法来操作其中的元素,比如添加、删除、遍历、查找等。集合中的元素是立即求值的,也就是说,当你调用集合的方法时,会立即执行相应的操作。

  2. 流则是惰性求值的,它不会立即执行操作,而是等到需要结果时才会执行。流的操作可以分为两类:中间操作和终端操作。中间操作返回的仍然是流,可以进行链式调用;终端操作则返回一个结果或副作用,触发流的处理。

  3. 特性

集合具有以下特性:

  • 可以重复存储相同的元素;
  • 可以按照插入顺序或自定义顺序进行排序;
  • 可以通过索引访问元素;
  • 可以通过迭代器遍历元素。

流具有以下特性:

  • 不存储数据,不会改变数据源的内容;
  • 可以进行并行处理,提高处理效率;
  • 可以进行多次操作,每次操作都返回一个新的流;
  • 可以对无限流进行操作,比如生成一系列随机数。

三、流的组成

Java Stream 是由一系列操作组成的,这些操作可以被串联起来形成一个流水线,对数据进行处理和转换。Stream 流的组成主要包括以下几个部分:

3.1 数据源(Source):

数据源是 Stream 流的起点,可以是集合、数组、I/O 通道、生成器等。Stream 可以从数据源中获取元素并传递给后续的操作。

3.2 中间操作(Intermediate Operations):

中间操作是对数据进行处理和转换的操作,它们可以接收一个流作为输入,返回一个新的流作为输出。中间操作可以有零个或多个,常见的中间操作包括过滤、映射、排序、去重等。

3.3 终端操作(Terminal Operations):

终端操作是对流进行最终操作的操作,它们会触发流的处理并产生一个结果或副作用。终端操作可以有一个或多个,常见的终端操作包括收集到集合、聚合计算、迭代遍历、条件匹配等。

3.4并行与顺序处理:

Stream 流可以进行并行处理,即利用多线程同时处理数据,提高处理效率。通过调用 parallel() 方法可以将流切换为并行流,而调用 sequential() 方法可以将并行流切换为顺序流。

Stream 流的组成使得我们可以通过链式调用的方式来对数据进行一系列的处理操作,使代码更加简洁、易读、易维护。同时,Stream 流的惰性求值特性也能够避免不必要的计算,提高了处理效率。需要注意的是,Stream 流是一次性使用的,一旦对流进行了终端操作,就无法再对其进行其他操作。如果需要多次使用流,可以通过创建新的流来实现。


四、流的操作分类

4.1 中间操作(Intermediate Operations):

中间操作是指在流上执行的操作,它们不会产生最终结果,而是返回一个新的流,用于进一步的操作。中间操作可以分为两种类型:

  1. 无状态操作(Stateless Operations):
    无状态操作是指不依赖于流中前面的元素,每个元素的处理都是独立的。常见的无状态操作有:map()、filter()、flatMap() 等。
  2. 有状态操作(Stateful Operations):
    有状态操作是指需要依赖于流中前面的元素进行计算的操作,这些操作需要维护状态,并且可能会影响后面的操作。常见的有状态操作有:distinct()、sorted()、peek() 等。

4.2 终端操作(Terminal Operations):

终端操作是指流的最终操作,在执行终端操作后,流将被消耗,不能再进行其他操作。常见的终端操作有:forEach()、count()、collect()、reduce() 等。

  1. 非短路操作(Non-Short-Circuiting Operations):
    非短路操作是指流中的所有元素都会被处理的操作,即无论流中有多少元素,都会对其进行操作,直到处理完所有元素。常见的非短路操作有:forEach()、collect()、reduce() 等。
  2. 短路操作(Short-Circuiting Operations):
    短路操作是指在处理流时,只处理部分元素,而不是全部元素,可以提高处理效率。常见的短路操作有:findFirst()、findAny()、limit()、skip() 等。

五、流的使用

流操作可以分为中间操作和终端操作两种类型。中间操作是指对流进行处理并返回一个新的流,而终端操作是指对流进行最终的处理并产生一个结果。

5.1 中间操作(无状态):

  • filter:根据指定的条件过滤流中的元素,只保留满足条件的元素。
  • map:将流中的每个元素通过指定的函数进行映射转换,生成一个新的流。
  • flatMap:将流中的每个元素通过指定的函数进行映射转换,并将映射结果扁平化为一个新的流。
  • peek:对流中的每个元素执行指定的操作,可以用于调试或观察流中的元素。

5.2 中间操作(有状态):

  • distinct:去除流中重复的元素,使用元素的 equals 方法进行比较。
  • skip:跳过指定数量的元素,返回剩下的元素组成的新流。
  • limit:限制流中元素的数量,截取前面指定数量的元素组成新流。
  • sorted:对流中的元素进行排序,可以使用自然顺序或指定的比较器。

5.3 终端操作(短路):

  • allMatch:判断流中的所有元素是否都满足指定条件,如果有一个不满足则返回 false。
  • anyMatch:判断流中是否存在任意一个元素满足指定条件,如果有则返回 true。
  • noneMatch:判断流中是否不存在任何一个元素满足指定条件,如果没有则返回 true。
  • findFirst:返回流中的第一个元素。
  • findAny:返回流中的任意一个元素。

5.4 终端操作(非短路):

  • forEach:对流中的每个元素执行指定的操作。
  • reduce:将流中的元素通过指定的操作进行归约计算,得到一个结果。
  • max:返回流中的最大元素,根据自然顺序或指定的比较器进行比较。
  • min:返回流中的最小元素,根据自然顺序或指定的比较器进行比较。
  • collect:将流中的元素收集到一个集合或其他数据结构中。
  • count:返回流中的元素数量。

六、流的构建

6.1 通过集合(Collection)创建流

List<String> list = Arrays.asList("apple", "banana", "orange");
Stream<String> stream = list.stream();

6.2 通过数组创建流

String[] array = {"apple", "banana", "orange"};
Stream<String> stream = Arrays.stream(array);

6.3 通过值创建流

Stream<String> stream = Stream.of("apple", "banana", "orange");

6.4 通过函数生成流

Stream<Integer> stream = Stream.generate(() -> 1); // 生成一个无限流,每个元素都是 1
Stream<Integer> stream = Stream.iterate(0, n -> n + 2); // 生成一个无限流,每个元素递增 2

6.5 通过文件生成流

try {
    Stream<String> stream = Files.lines(Paths.get("file.txt"));
} catch (IOException e) {
    // 处理异常
}

6.6 通过其他流生成流

Stream<String> originalStream = Stream.of("apple", "banana", "orange");
Stream<String> newStream = originalStream.filter(s -> s.startsWith("a")); // 过滤以字母"a"开头的元素
Stream stream = Stream.generate(Math::random);
stream.limit(100).forEach(System.out::println);

七、流实战

7.1 实体

public class Person {
    private String name;  // 姓名
    private Integer salary; // 薪资
    private int age; // 年龄
    private String sex; //性别
    private String area;  // 地区

    public Person() {
    }

    public Person(String name, Integer salary, int age, String sex, String area) {
        this.name = name;
        this.salary = salary;
        this.age = age;
        this.sex = sex;
        this.area = area;
    }

    public Person(String name, Integer salary, String sex, String area) {
        this.name = name;
        this.salary = salary;
        this.sex = sex;
        this.area = area;
    }

    public String getName() {
        return name;
    }

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

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

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("Person{");
        sb.append("name='").append(name).append('\'');
        sb.append(", salary=").append(salary);
        sb.append(", age=").append(age);
        sb.append(", sex='").append(sex).append('\'');
        sb.append(", area='").append(area).append('\'');
        sb.append('}');
        return sb.toString();
    }
}
public class User {

    String name;
    Integer sex;
    Integer age;
    User user;

    public String getName() {
        return name;
    }

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

    public Integer getSex() {
        return sex;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public User(String name, Integer sex, Integer age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }

    public User(String name, Integer sex, Integer age, User user) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.user = user;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user1 = (User) o;
        return Objects.equals(name, user1.name) && Objects.equals(sex, user1.sex) && Objects.equals(age, user1.age) && Objects.equals(user, user1.user);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, sex, age, user);
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", sex=" + sex +
                ", age=" + age +
                '}';
    }
}

7.2 创建并行流(多线程处理)

@Test
 public void test02() {
     List<Integer> list = Arrays.asList(3, 8, 2, -3, 10, 0, 10);
     // Optional类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
     Optional<Integer> findFirst = list.stream().parallel().filter(x -> x > 6).findFirst();
     findFirst.ifPresent(System.out::println);
     System.out.println("findFirst.isPresent() = " + findFirst.isPresent());
 }

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

@Test
public void test03() {
    List<Integer> list = Arrays.asList(7, 9, 3, 8, 12, 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 < 1);
    System.out.println("匹配第一个值:" + findFirst.orElse(null)); // 7
    System.out.println("匹配任意一个值:" + findAny.orElse(null)); // 8
    System.out.println("是否存在小于1的值:" + anyMatch); // false
}

7.4 filter

@Test
public void test04() {
    List<Person> personList = new ArrayList<>();
    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> fiterList = personList.stream()
            .filter(x -> "male".equals(x.getSex()) && x.getSalary() > 8000)
            .map(Person::getName)
            .collect(Collectors.toList());
    System.out.print("高于8000的男员工姓名:" + fiterList);
}

7.5 聚合(max/min/count)

@Test
public void test05() {
    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());

    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"));
    System.out.println(personList.stream().max(Comparator.comparingInt(Person::getSalary)).get());
    System.out.println(personList.stream().min(Comparator.comparing(Person::getSalary)).get());

    List<Integer> integers = Arrays.asList(7, 6, 9, 4, 11, 6);
    System.out.println(integers.stream().min(Integer::compareTo).get());
    System.out.println(integers.stream().max(Comparator.comparingInt(param -> param)).get());
}

7.6 map/flatMap 映射

@Test
public void test06() {
    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);// 每个元素大写:[ABCD, BCDD, DEFDE, FTR]
    System.out.println("每个元素+3:" + intListNew);// 每个元素+3:[4, 6, 8, 10, 12, 14]

    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 newPerson = new Person();
        BeanUtils.copyProperties(person, newPerson);
        newPerson.setSalary(person.getSalary() + 1000);
        return newPerson;
    }).collect(Collectors.toList());
    System.out.println("一次改动前:" + personList.get(0).getName() + "-->" + personList.get(0).getSalary()); // 一次改动前:Tom-->8900
    System.out.println("一次改动后:" + personListNew.get(0).getName() + "-->" + personListNew.get(0).getSalary());// 一次改动后:Tom-->9900
    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());// 二次改动前:Tom-->9900
    System.out.println("二次改动后:" + personListNew2.get(0).getName() + "-->" + personListNew.get(0).getSalary());// 二次改动后:Tom-->9900

    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);// 处理前的集合:[m/k/l/a, 1/3/5/7]
    System.out.println("处理后的集合:" + listNew);// 处理后的集合:[m, k, l, a, 1, 3, 5, 7]
}
// 并行流写法
 Map<Integer, List<User>> collect3 = list.parallelStream()
                .filter((User user) -> user.getAge() != null && Integer.valueOf(10).compareTo(user.getAge()) < 0)
                .collect(Collectors.groupingBy(User::getAge));

7.7 reduce 归约

@Test
public void test07() {

    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", null, 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<Integer> reduce = personList.stream().map(Person::getSalary)
            .filter(Objects::nonNull).reduce(Integer::sum);
    Integer sumSalary = reduce.orElse(0);
    Integer sumSalary2 = personList.stream().filter(person -> person.getSalary() != null)
            .reduce(0, (sum, p) -> sum += p.getSalary(), Integer::sum);
    Integer sumSalary3 = personList.stream().filter(person -> person.getSalary() != null)
            .reduce(0, (sum, p) -> sum += p.getSalary(), Integer::sum);
    System.out.println("工资之和:" + sumSalary + "," + sumSalary2 + "," + sumSalary3); // 工资之和:41500,41500,41500
    // 最高工资
    Integer maxSalary = personList.stream()
            .filter(person -> person.getSalary() != null)
            .reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(), Integer::max);
    Integer maxSalary2 = personList.stream()
            .filter(person -> person.getSalary() != null)
            .reduce(0, (max, p) -> max > p.getSalary() ? max : p.getSalary(), (max1, max2) -> max1 > max2 ? max1 : max2);
    System.out.println("工资最大值:" + maxSalary + "," + maxSalary2); // 工资最大值:9500,9500
    List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4);
    // 求和方式1
    Optional<Integer> sum = list.stream().reduce(Integer::sum);
    // 求和方式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);// list求和:29,29,29
    System.out.println("list求积:" + product.get());// list求积:2112
    System.out.println("list求和:" + max.get() + "," + max2);// list求和:11,11
}

7.8 collect(toList/toSet/toMap)

@Test
public void test08() {
    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());
    System.out.println(listNew); // [6, 4, 6, 6, 20]
    Set<Integer> set = list.stream().filter(x -> x % 2 == 0)
            .collect(Collectors.toSet());
    System.out.println(set); // [4, 20, 6]

    List<Person> personList = new ArrayList<Person>();
    personList.add(new Person("Tom", null, 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<String, Person> collect = personList.stream().filter(p -> p.getSalary() != null && p.getSalary() > 8000)
            .collect(Collectors.toMap(Person::getName, p -> p));
    Map<String, String> collect2 = personList.stream().filter(p -> p.getSalary() != null && p.getSalary() > 8000)
            .collect(Collectors.toMap(Person::getName, JSONObject::toJSONString));
    System.out.println(collect); // {Anni=Person{name='Anni', salary=8200, age=24, sex='female', area='New York'}}
    System.out.println(collect2); // {Anni={"age":24,"area":"New York","name":"Anni","salary":8200,"sex":"female"}}
}

7.9 统计(count/averaging)

/**
 * 计数:count
 * 平均值:averagingInt、averagingLong、averagingDouble
 * 最值:maxBy、minBy
 * 求和:summingInt、summingLong、summingDouble
 * 统计以上所有:summarizingInt、summarizingLong、summarizingDouble
 */
@Test
public void test09() {
    List<Person> personList = new ArrayList<Person>();
    personList.add(new Person("Tom", 3234, 23, "male", "New York"));
    personList.add(new Person("Jack", 433, 25, "male", "Washington"));
    personList.add(new Person("Lily", 4334, 21, "female", "Washington"));
    personList.add(new Person("test", null, 21, "female", "china"));
    // 数据条数
    long count = personList.stream().filter(p -> p.getSalary() != null).count();
    long count2 = personList.stream().filter(p -> p.getSalary() != null).count();
    // 平均工资
    Double average = personList.stream().filter(p -> p.getSalary() != null).collect(Collectors.averagingDouble(Person::getSalary));
    // 求工资之和
    int sum = personList.stream().filter(p -> p.getSalary() != null).mapToInt(Person::getSalary).sum();
    int sum2 = personList.stream().filter(p -> p.getSalary() != null).mapToInt(Person::getSalary).sum();
    // 工资最大值
    Optional<Integer> max = personList.stream().map(Person::getSalary).filter(Objects::nonNull).max(Integer::compare);
    Optional<Integer> max2 = personList.stream().map(Person::getSalary).filter(Objects::nonNull)
            .max(Integer::compare);
    // 一次性统计所有信息
    // DoubleSummaryStatistics{count=3, sum=23700.000000, min=7000.000000, average=7900.000000, max=8900.000000}
    // 包括条数,总和,平均值,最大值,最小值
    DoubleSummaryStatistics collect = personList.stream().filter(p -> p.getSalary() != null)
            .collect(Collectors.summarizingDouble(Person::getSalary));
    System.out.println("员工总数:" + count + "," + count2); // 员工总数:3,3
    System.out.println("员工平均工资:" + average);// 员工平均工资:2667.0
    System.out.println("员工工资总和:" + sum + "," + sum2);// 员工工资总和:8001,8001
    System.out.println("员工工资所有统计:" + collect);// 员工工资所有统计:DoubleSummaryStatistics{count=3, sum=8001.000000, min=433.000000, average=2667.000000, max=4334.000000}
    System.out.println("员工工资最大值:" + (max.orElseGet(() -> 0)) + "," + (max2.orElseGet(() -> 0)));// 员工工资最大值:4334,4334
}

7.10 分组(partitioningBy/groupingBy)

@Test
public void test10() {
    List<Person> personList = new ArrayList<Person>();
    personList.add(new Person("Tom", 8900, "male", "New York"));
    personList.add(new Person("Jack", 7000, "male", "Washington"));
    personList.add(new Person("Lily", 7800, "female", "Washington"));
    personList.add(new Person("Anni", 8200, "female", "New York"));
    personList.add(new Person("Owen", 9500, "male", "New York"));
    personList.add(new Person("Alisa", 7900, "female", "New York"));
    // 分区
    // 将员工按薪资是否高于8000分组
    Map<Boolean, List<Person>> collect = personList.stream()
            .collect(Collectors.partitioningBy(p -> p.getSalary() > 8000));
    List<Person> people = collect.get(false);
    // people = [Person{name='Jack', salary=7000, age=0, sex='male', area='Washington'}, 
    // Person{name='Lily', salary=7800, age=0, sex='female', area='Washington'}, 
    // Person{name='Alisa', salary=7900, age=0, sex='female', area='New York'}]
    System.out.println("people = " + people);
    List<Person> people2 = collect.get(true);
    // people2 = [Person{name='Tom', salary=8900, age=0, sex='male', area='New York'}, 
    // Person{name='Anni', salary=8200, age=0, sex='female', area='New York'}, 
    // Person{name='Owen', salary=9500, age=0, sex='male', area='New York'}]
    System.out.println("people2 = " + people2);
    // 将员工按性别分组
    Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));
    // group = {female=[Person{name='Lily', salary=7800, age=0, sex='female', area='Washington'}, 
    // Person{name='Anni', salary=8200, age=0, sex='female', area='New York'}, 
    // Person{name='Alisa', salary=7900, age=0, sex='female', area='New York'}], 
    // male=[Person{name='Tom', salary=8900, age=0, sex='male', area='New York'}, 
    // Person{name='Jack', salary=7000, age=0, sex='male', area='Washington'}, 
    // Person{name='Owen', salary=9500, age=0, sex='male', area='New York'}]}
    System.out.println("group = " + group);
    // 将员工先按性别分组,再按地区分组
    Map<String, Map<String, List<Person>>> group2 = personList.stream()
            .collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
    // 员工按性别、地区:{female={New York=[Person{name='Anni', salary=8200, age=0, sex='female', area='New York'}, 
    // Person{name='Alisa', salary=7900, age=0, sex='female', area='New York'}], 
    // Washington=[Person{name='Lily', salary=7800, age=0, sex='female', area='Washington'}]}, 
    // male={New York=[Person{name='Tom', salary=8900, age=0, sex='male', area='New York'}, 
    // Person{name='Owen', salary=9500, age=0, sex='male', area='New York'}], 
    // Washington=[Person{name='Jack', salary=7000, age=0, sex='male', area='Washington'}]}}
    System.out.println("员工按性别、地区:" + group2);
}

7.11 接合(joining)

@Test
public void test11() {
    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(Person::getName).collect(Collectors.joining(","));
    // 所有员工的姓名:Tom,Jack,Lily
    System.out.println("所有员工的姓名:" + names);
}

7.12 排序(sorted)

@Test
public void test13() {
    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 (Objects.equals(p1.getSalary(), p2.getSalary())) {
            return p2.getAge() - p1.getAge();
        } else {
            return p2.getSalary() - p1.getSalary();
        }
    }).map(Person::getName).collect(Collectors.toList());
    // 按工资升序排序:[Lily, Tom, Sherry, Jack, Alisa]
    // 按工资降序排序:[Sherry, Jack, Alisa, Tom, Lily]
    // 先按工资再按年龄升序排序:[Lily, Tom, Sherry, Jack, Alisa]
    // 先按工资再按年龄自定义降序排序:[Alisa, Jack, Sherry, Tom, Lily]
    System.out.println("按工资升序排序:" + newList);
    System.out.println("按工资降序排序:" + newList2);
    System.out.println("先按工资再按年龄升序排序:" + newList3);
    System.out.println("先按工资再按年龄自定义降序排序:" + newList4);
}

7.13 合并、去重、限制、跳过

@Test
public void test15() {
    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);// 流合并:[a, b, c, d, e, f, g]
    System.out.println("limit:" + collect);// limit:[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
    System.out.println("skip:" + collect2);// skip:[3, 5, 7, 9, 11]
}

八、总结

待续

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值