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用法:
- 集合元素遍历
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
list.stream().forEach(System.out::println);
Copy
Java
- 过滤操作
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
List<String> result = list.stream().filter(s -> s.startsWith("A")).collect(Collectors.toList());
Copy
Java
- 转换操作
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
List<Integer> result = list.stream().map(String::length).collect(Collectors.toList());
Copy
Java
- 合并操作
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
- 统计操作
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
- 分组操作
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
- 去重操作
List<Integer> list = Arrays.asList(1, 2, 3, 3, 4, 5, 5, 5);
List<Integer> result = list.stream().distinct().collect(Collectors.toList());
Copy
Java
- 拆分操作
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
- 排序操作
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的人。
departmentList.stream().collect(Collectors.toMap(u -> u.getUuid(), u -> u.getDepartName(), (d1, d2) -> d1));
好的,以下是关于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 协议》,转载必须注明作者和本文链接