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

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

//获取到的工单信息是以用户和工单为维度统计的,所以要去重
List<ItsmOrderExtend> valueList = v.stream().filter(DistinctKeyFunction.distinctByKey(t -> t.getOrderUuid())).collect(Collectors.toList());

多字段分组统计,你知道怎样做吗

    Map<String, List<ItsmOrderExtend>> sysNameMap = orderList.stream().filter(t -> StringUtil.isNotEmpty(t.getAppName()) &&  StringUtil.isNotEmpty(t.getSysName()))
            .collect(Collectors.groupingBy(t -> t.getSysName() + "_" + t.getAppName(), Collectors.mapping(c -> c, Collectors.toList())));
        sysNameMap.forEach((k, v) -> {
            // 获取到的工单信息是以用户和工单为维度统计的,所以要去重
            List<ItsmOrderExtend> valueList = v.stream().filter(DistinctKeyFunction.distinctByKey(t -> t.getOrderUuid())).collect(Collectors.toList());

            Map<String, ReportListData> countData = Maps.newHashMap();
            // 系统名称
            String[] sys = k.split("_");
            ReportListData sysNameData = new ReportListData(sys[0], sys[1]);
            countData.put("sys_name", sysNameData);
            // 各机构工单数量
            Map<String, List<ItsmOrderExtend>> orderByDepartMap = valueList.stream().filter(t -> ObjectUtil.isNotEmpty(t.getDepartUuid()))
                .collect(Collectors.groupingBy(t -> t.getDepartUuid(), Collectors.mapping(c -> c, Collectors.toList())));
            if(MapUtils.isEmpty(orderByDepartMap)) {
                orderByDepartMap = Maps.newHashMap();
            }
            for (ReportHeadColumn countHead : countHeadList) {
                if("total".equals(countHead.getColKey())) {
                    ReportListData totalData = new ReportListData(valueList.size());
                    countData.put("total", totalData);
                } else {
                    List<ItsmOrderExtend> departOrder = orderByDepartMap.get(countHead.getColKey());
                    ReportListData departData = new ReportListData(CollectionUtils.isEmpty(departOrder) ? 0 : departOrder.size());
                    countData.put(countHead.getColKey(), departData);
                }
            }
            dataList.add(countData);
        });
        vo.setDataList(dataList);
        return vo;

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总结

 departmentList.stream().collect(Collectors.toMap(u -> u.getUuid(), u -> u.getDepartName(), (d1, d2) -> d1));

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

好的,以下是关于Java 8的Stream API中Collectors类的学习笔记。

Collectors

在Java 8中,Stream API提供了各种各样的操作,用于对流进行操作和处理。其中,Collectors类就是用来将流中的元素收集到不同类型的集合中的工具类。Collectors提供了各种各样的静态方法,每个方法都返回一个Collector实例,用来对Stream进行不同的操作。

toList

toList方法可以将Stream中的所有元素收集到一个List集合中:

List<String> list = Stream.of("a", "b", "c")
                           .collect(Collectors.toList());

toSet

toSet方法可以将Stream中的所有元素收集到一个Set集合中:

Set<String> set = Stream.of("a", "b", "c")
                         .collect(Collectors.toSet());

toMap

toMap方法可以将Stream中的元素收集到一个Map集合中。其中,第一个参数是键的映射函数,第二个参数是值的映射函数。例如,下面的代码将一组人的姓名和年龄组合成一个Map集合:

List<Person> people = Arrays.asList(
        new Person("Tom", 20),
        new Person("Jack", 30),
        new Person("Lucy", 25)
);

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

System.out.println(nameAgeMap);

输出结果为:

{Tom=20, Lucy=25, Jack=30}

需要注意的是,如果键出现重复,则toMap方法可能会抛出异常。如果需要处理重复键的情况,可以使用第三个参数来指定一个合并函数,来处理键和值的重复。例如,下面的代码将一组人的姓名和年龄组合成一个Map集合,如果有重名的人,则将年龄相加:

Map<String, Integer> nameAgeMap = people.stream()
                     .collect(Collectors.toMap(Person::getName, Person::getAge, (existingValue, newValue) -> existingValue + newValue));

groupingBy

groupingBy方法可以将Stream中的元素分组,生成一个Map集合。其中,第一个参数是分组的函数,第二个参数是第一个函数的结果对应的元素如何收集的Collector。

例如,下面的代码将一组人按照年龄分组:

Map<Integer, List<Person>> ageGroupMap = people.stream()
                          .collect(Collectors.groupingBy(Person::getAge));

System.out.println(ageGroupMap);

输出结果为:

{25=[Person{name='Lucy', age=25}], 20=[Person{name='Tom', age=20}], 30=[Person{name='Jack', age=30}]}

需要注意的是,分组的结果是一个Map实例,其中的键是分组的函数的结果,值是原始Stream中满足该键的元素列表。

partitioningBy

partitioningBy方法可以将Stream中的元素按照指定的条件进行二分,生成一个Map集合。其中,第一个参数是分组的条件,第二个参数是对应条件的元素如何收集的Collector。

例如,下面的代码将一组人按照年龄是否大于等于25岁进行二分:

Map<Boolean, List<Person>> agePartitionMap = people.stream()
                               .collect(Collectors.partitioningBy(person -> person.getAge() >= 25));

System.out.println(agePartitionMap);

输出结果为:

{false=[Person{name='Tom', age=20}], true=[Person{name='Jack', age=30}, Person{name='Lucy', age=25}]}

需要注意的是,分组的结果是一个Map实例,其中的键是分组条件的结果(例如是true或false),值是原始Stream中满足该条件的元素列表。

 // 使用 Java Stream 实现统计操作
        Map<String, Integer> nameAgeMap = people.stream()
                .collect(Collectors.toMap(Person::getName, Person::getAge, (existingValue, newValue) -> existingValue + newValue));

        // 输出结果
        nameAgeMap.forEach((name, age) -> {
            System.out.println(name + ": " + age);
        });
    }
本作品采用《CC 协议》,转载必须注明作者和本文链接
zhaozhangxiao
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

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