1.stream排序
string集合
List<String> sortStringList = new ArrayList<>();
sortStringList.add("F001");
sortStringList.add("F040");
sortStringList.add("F040");
sortStringList.add("F005");
sortStringList.add("F047");
sortStringList.add("F005");
sortStringList.add("F056");
sortStringList.add("F999");
System.out.println("排序之前的List:" + sortStringList);
//方式一 默认为正序排序,若想倒序排序则将o1、o2倒过来即可!
Comparator<Object> comparator = new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
Collator collator = Collator.getInstance();
return collator.getCollationKey(String.valueOf(o1)).compareTo(collator.getCollationKey(String.valueOf(o2)));
}
};
Collections.sort(sortStringList,comparator);
System.out.println("排序之后的List:" + sortStringList);
//方式二 这里是倒序排序,若去掉‘reversed()’则为正序排序
sortStringList.sort(Comparator.comparing(item -> String.valueOf(item)).reversed());
System.out.println("排序之后的List:" + sortStringList);
对象集合
AlarmInfo alarmInfo = new AlarmInfo("F001",50,20,"Aily");
AlarmInfo alarmInfo2 = new AlarmInfo("F086",30,30,"Jerry");
AlarmInfo alarmInfo3 = new AlarmInfo("F026",58,25,"Tony");
AlarmInfo alarmInfo4 = new AlarmInfo("F061",109,27,"Zeroe");
List<AlarmInfo> alarmInfos = new ArrayList<>();
alarmInfos.add(alarmInfo);
alarmInfos.add(alarmInfo2);
alarmInfos.add(alarmInfo3);
alarmInfos.add(alarmInfo4);
Stream<AlarmInfo> infoStream = alarmInfos.stream();
infoStream = infoStream.sorted(Comparator.nullsLast(Comparator.comparing(
alarmInfo1 -> alarmInfo1.getWindField())));
infoStream.forEach(alarmInfo1 -> {
System.out.println(alarmInfo1.toString());
});
List<Map<String,Object>> mapList = Lists.newArrayList();
for (AlarmInfo alerm:alarmInfos
) {
Map<String,Object> map = beanToMap(alerm);
mapList.add(map);
}
Stream<Map<String,Object>> mapStream = mapList.stream().sorted(Comparator.comparing(item -> {
Map<String,Object> map = (Map<String,Object>)item;
return String.valueOf(map.get("message"));
}).reversed());
mapStream.forEach(item -> {
System.out.println(item);
});
2.distinct去重、list转string
String listStr = sortStringList.stream().distinct().collect(Collectors.joining(","));
System.out.println(listStr);
3.filter过滤
list = list.stream().filter(record ->
record.endsWith("40")).collect(Collectors.toList());
list.forEach(item -> {
System.out.println(item);
});
4.map获取对象中某个值的集合
List<String> windFields = alarmInfos.stream().map(item ->
String.valueOf(item.getWindField())).collect(Collectors.toList());
System.out.println(windFields.toString());
5.使用collect()生成Map
构造对象
@Data
class Student{
String name; //姓名
String class1; //班级
Integer age; //年龄
Integer score; //成绩
public Student (String name,String class1,Integer age,Integer score){
this.name = name;
this.class1 = class1;
this.age = age;
this.score = score;
}
}
构造对象集合
List<Student> list = new ArrayList<>();
list.add(new Student("李思","一班",16,95));
list.add(new Student("王武","三班",15,84));
list.add(new Student("赵柳","三班",17,79));
list.add(new Student("Lusay","二班",16,90));
list.add(new Student("Weufa","一班",18,80));
list.add(new Student("Cary","二班",14,100));
stream()生成Map对象一般分为一下三种情况:
- 使用
Collectors.toMap()
生成的收集器,用户需要指定如何生成Map的key和value。 - 使用
Collectors.partitioningBy()
生成的收集器,对元素进行二分区操作时用到。 - 使用
Collectors.groupingBy()
生成的收集器,对元素做group操作时用到。
情况1:使用toMap()
生成的收集器,这种情况是最直接的,前面例子中已提到,这是和Collectors.toCollection()
并列的方法。下面代码是对每个学生进行分组,对每个学生的成绩进行处理
Map<Student, String> collect2 = list.parallelStream().collect(Collectors.toMap(Function.identity(),item->computer(item)));
for(Map.Entry<Student, String> map : collect2.entrySet()){
System.out.println(map);
}
//结果打印
//Student(name=王武, class1=三班, age=15, score=84)=优秀
//Student(name=李思, class1=一班, age=16, score=95)=优秀
//Student(name=Weufa, class1=一班, age=18, score=80)=一般般~
//Student(name=Lusay, class1=二班, age=16, score=90)=优秀
//Student(name=Cary, class1=二班, age=14, score=100)=优秀
//Student(name=赵柳, class1=三班, age=17, score=79)=一般般~
情况2:使用partitioningBy()
生成的收集器,这种情况适用于将Stream
中的元素依据某个二值逻辑(满足条件,或不满足)分成互补相交的两部分,比如男女性别、成绩及格与否等。下列代码展示将学生分成一班和其他班两部分。
Map<Boolean, List<Student>> collect1 = list.stream().collect(Collectors.partitioningBy(item -> item.getClass1() == "一班"));
for(Map.Entry<Boolean, List<Student>> map : collect1.entrySet()){
System.out.println(map);
}
// 结果打印
// false=[Student(name=王武, class1=三班, age=15, score=84), Student(name=赵柳, class1=三班, age=17, score=79), Student(name=Lusay, class1=二班, age=16, score=90), Student(name=Cary, class1=二班, age=14, score=100)]
// true=[Student(name=李思, class1=一班, age=16, score=95), Student(name=Weufa, class1=一班, age=18, score=80)]
情况3:使用groupingBy()
生成的收集器,这是比较灵活的一种情况。跟SQL中的group by语句类似,这里的groupingBy()也是按照某个属性对数据进行分组,属性相同的元素会被对应到Map的同一个key上。下列代码展示将学生按班级进行分组:
Map<String, List<Student>> collect = list.stream().collect(Collectors.groupingBy(item -> item.getClass1()));
for(Map.Entry<String,List<Student>> map : collect.entrySet()){
System.out.println(map);
}
// 结果打印:
// 一班=[Student(name=李思, class1=一班, age=16, score=95), Student(name=Weufa, class1=一班, age=18, score=80)]
// 二班=[Student(name=Lusay, class1=二班, age=16, score=90), Student(name=Cary, class1=二班, age=14, score=100)]
// 三班=[Student(name=王武, class1=三班, age=15, score=84), Student(name=赵柳, class1=三班, age=17, score=79)]
以上只是分组的最基本用法,有些时候仅仅分组是不够的。在SQL中使用group by是为了协助其他查询,比如1. 先将学生按照班级分组,2. 然后统计每个班级的人数。Java类库设计者也考虑到了这种情况,增强版的groupingBy()
能够满足这种需求。增强版的groupingBy()
允许我们对元素分组之后再执行某种运算,比如求和、计数、平均值、类型转换等。这种先将元素分组的收集器叫做上游收集器,之后执行其他运算的收集器叫做下游收集器(downstream Collector)。
Map<String, Long> collect3 = list.stream().collect(Collectors.groupingBy(item -> item.getClass1(), Collectors.counting()));
for (Map.Entry<String, Long> map : collect3.entrySet()) {
System.out.println(map);
}
// 结果打印:
// 一班=2
// 二班=2
// 三班=2
上面代码的逻辑是不是越看越像SQL?高度非结构化。还有更狠的,下游收集器还可以包含更下游的收集器,这绝不是为了炫技而增加的把戏,而是实际场景需要。考虑将学生按照班级分组的场景,如果我们想得到每个学生的名字(字符串),而不是一个个Student对象,可通过如下方式做到:
Map<String, List<String>> collect3 = list.stream().collect(Collectors.groupingBy(Student :: getClass1, Collectors.mapping(
Student::getName,Collectors.toList()
)));
for (Map.Entry<String, List<String>> map : collect3.entrySet()) {
System.out.println(map);
}
// 结果打印:
// 一班=[李思, Weufa]
// 二班=[Lusay, Cary]
// 三班=[王武, 赵柳]
持续更新中~~~