Java 8 Stream相关知识点的归纳总结-重点groupby总结

Java 8 Stream是处理集合数据的新方式。它提供了一种更高效、更简洁的方法来处理数据,使用 Stream API 你可以完成很多原先需要写循环才能解决的问题。

Stream提供了很多操作方法,包括中间操作和终止操作。中间操作返回一个新的Stream对象,你可以进行进一步的操作;终止操作不再返回Stream对象,它们可能返回一个结果,也可能不返回任何结果。

一些常用的中间操作方法包括 filter、map、flatMap、distinct、sorted、peek、limit、skip。一些常用的终止操作方法包括 forEach、forEachOrdered、count、collect、min、max、reduce、anyMatch、allMatch、noneMatch、findFirst、findAny。

在对Stream进行操作时,需要注意以下几点:

  • 操作不会改变原始的集合元素。
  • 操作通常是延迟执行的。
  • 操作可以按需执行,不必要全部执行。
  • 操作时可以并行化操作的,提高处理效率。

下面是一些常见场景下的Stream用法:

  1. 集合元素遍历
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
list.stream().forEach(System.out::println);

Copy

Java

  1. 过滤操作
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
List<String> result = list.stream().filter(s -> s.startsWith("A")).collect(Collectors.toList());

Copy

Java

  1. 转换操作
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
List<Integer> result = list.stream().map(String::length).collect(Collectors.toList());

Copy

Java

  1. 合并操作
List<String> list1 = Arrays.asList("A", "B", "C");
List<String> list2 = Arrays.asList("D", "E", "F");
List<String> result = Stream.concat(list1.stream(), list2.stream()).collect(Collectors.toList());

Copy

Java

  1. 统计操作
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
IntSummaryStatistics statistics = list.stream().mapToInt(Integer::intValue).summaryStatistics();
System.out.println(statistics.getMax());
System.out.println(statistics.getMin());
System.out.println(statistics.getSum());
System.out.println(statistics.getAverage());

Copy

Java

  1. 分组操作
List<Person> persons = Arrays.asList(
    new Person("Alice", 25),
    new Person("Bob", 30),
    new Person("Charlie", 35),
    new Person("David", 40),
    new Person("Eddie", 45)
);
Map<Integer, List<Person>> result = persons.stream().collect(Collectors.groupingBy(Person::getAge));

Copy

Java

  1. 去重操作
List<Integer> list = Arrays.asList(1, 2, 3, 3, 4, 5, 5, 5);
List<Integer> result = list.stream().distinct().collect(Collectors.toList());

Copy

Java

  1. 拆分操作
List<String> list = Arrays.asList("Apple,Banana", "Orange,Mango", "Grape,Peach");
List<String> result = list.stream().flatMap(s -> Arrays.stream(s.split(","))).collect(Collectors.toList());

Copy

Java

  1. 排序操作
List<Integer> list = Arrays.asList(2, 4, 1, 3, 5);
List<Integer> result1 = list.stream().sorted().collect(Collectors.toList());
List<Integer> result2 = list.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
List<Integer> result3 = list.stream().sorted((o1, o2) -> o2.compareTo(o1)).collect(Collectors.toList());

Copy

Java

这些只是Stream API的一些常见用法,理解了这些基本用法之后,可以根据实际的需求进行更丰富的操作。Stream API 的出现,使得Java集合操作更加简捷、高效,也拓宽了Java 8的应用场景。

对象中某个键值对应

如果你想将 List<Person> 对象中的姓名和年龄转换为 Map<String, Integer> 格式,可使用下面的代码:

Map<String, Integer> ageByName = persons.stream()
        .collect(Collectors.toMap(Person::getName, Person::getAge));

Copy

Java

该代码首先将流中的元素映射为键值对,其中键是姓名,值是年龄,最后使用 Collectors.toMap() 方法将映射结果存储到 Map<String, Integer> 对象中。

输出结果为:

{Bob=30, CCC=35, Alice=25}

其中,Bob 的年龄是30,CCC 的年龄是35,Alice 的年龄是25。

对象中,某个键和对象对应

如果你想将 List<Person> 对象中的姓名和对象映射为 Map<String, Person> 格式,可使用下面的代码:

Map<String, Person> personByName = persons.stream()
        .collect(Collectors.toMap(Person::getName, person -> person));

Copy

Java

该代码首先将流中的元素映射为键值对,其中键是姓名,值是对象本身,最后使用 Collectors.toMap() 方法将映射结果存储到 Map<String, Person> 对象中。

输出结果为:

{Bob=Person{name='Bob', age=30}, CCC=Person{name='CCC', age=35}, Alice=Person{name='Alice', age=25}}

其中,Bob 的对象是 Person{name='Bob', age=30},CCC 的对象是 Person{name='CCC', age=35},Alice 的对象是 Person{name='Alice', age=25}

如果有相同的键,则对应的有策略

如果你想将 List<Person> 对象中的姓名和对象映射为 Map<String, Person> 格式,但是存在相同的姓名,那么你需要定义一个规则来解决冲突。可以使用 toMap() 方法的第三个参数来指定合并规则:

Map<String, Person> personByName = persons.stream()
        .collect(Collectors.toMap(
                Person::getName,  // 键:姓名
                person -> person, // 值:对象本身
                (p1, p2) -> p2   // 同名的情况下,选择新对象覆盖旧对象
        ));

Copy

Java

在这个例子中,我们使用了 (p1, p2) -> p2 作为合并规则,表示对于相同的键,返回新值覆盖旧值。 这样,对于 Alice 这个键,会获取到最后一个 Person 对象,即 Person{name='Alice', age=35}

输出结果为:

{Bob=Person{name='Bob', age=30}, Alice=Person{name='Alice', age=35}}

其中,Bob 的对象是 Person{name='Bob', age=30},Alice 的对象是 Person{name='Alice', age=35}

默认使用名字分组

如果要按照名字进行分组,可以使用以下代码:

List<Person> persons = Arrays.asList(
        new Person("John", 20),
        new Person("Mary", 25),
        new Person("Alice", 30),
        new Person("Jack", 20)
);
比如这个, 按照名字 怎样分组?
Map<String, List<Person>> personsByName = persons.stream()
        .collect(Collectors.groupingBy(Person::getName));

上述代码中,我们调用了stream()方法将persons列表转换为一个Stream对象,然后使用groupingBy方法传入了Person::getName方法引用作为参数。最终返回的是一个Map>对象,其中key表示分组属性(即名字),value表示该分组后的所有元素。

需要注意的是,Person类需要有一个getName()方法用于获取名字属性。如果不存在该方法,则需要替换为对应的属性名称,例如:

Map<String, List<Person>> personsByName = persons.stream()
        .collect(Collectors.groupingBy(p -> p.name));

这里我们使用了lambda表达式,p -> p.name表示获取Person类中的name属性值作为分组属性。

来对年龄进行分组统计 输出 Map<String, Long>

Map<String, Long> ageCounts = persons.stream()
    .collect(Collectors.groupingBy(Person::getName, Collectors.counting()));

Copy

Java

上述代码中,我们首先使用stream()方法将List转换成一个流(stream),然后使用collect()方法将这些人按照名字分组并进行统计。

其中groupingBy()用于根据名字对人群进行分组,Collectors.counting()用于统计每个分组中有多少人。注意,这里使用了Person::getName作为分组条件,所以Map的键是名字,值是该名字对应的人数。

最终结果是一个Map,键是名字,值是该名字对应的年龄。

### 如果能找到则输出某个值,否则判空,或者异常

Integer age = persons.stream()
    .filter(p -> p.getName().equals("Bob"))
    .findFirst()
    .map(Person::getAge)
    .orElse(null);

System.out.println("Bob的年龄是:" + age);


int iAge2 = optionalBob.map(Person::getAge).orElseThrow(() -> new RuntimeException("未找到符合条件的Person对象")); // 如果找不到Person对象,抛出异常

**** 可以使用Java 8的stream和filter方法来实现对Bob的筛选和查询,具体代码如下:

Optional<Person> bob = persons.stream()
    .filter(p -> p.getName().equals("Bob"))
    .findFirst();
if (bob.isPresent()) {
    System.out.println("Bob的年龄是:" + bob.get().getAge());
} else {
    System.out.println("不存在名为Bob的人");
}



Java

上述代码中,我们使用stream()方法将List转换成一个流(stream),然后使用filter()方法对流中的每个Person对象进行判断。

在这里,我们使用p -> p.getName().equals("Bob")作为判断条件,意思是筛选出名字等于"Bob"的人。然后,我们使用findFirst()方法获取符合条件的第一个Person对象。

由于结果可能为空,因此我们需要使用Optional类来包装结果。如果存在名为Bob的人,我们使用System.out.println()方法输出他的年龄;否则,我们输出一个提示信息,表明不存在名为Bob的人。

Java 8 Stream相关知识点的归纳总结-重点groupby总结

本作品采用《CC 协议》,转载必须注明作者和本文链接
zhaozhangxiao
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!