在开发中可能会遇到很多需要去重的情况,比如Person对象有name跟age两个属性,需要根据age进行去重。本文主要是基于java8提供的stream流进行处理。
public class test {
public static void main(String[] args) {
List<Person> ps=new ArrayList<>();
ps.add(new Person(11,"tom"));
ps.add(new Person(11,"张三"));
ps.add(new Person(12,"tom"));
ps.add(new Person(11,"tom"));
//根据name进行去重
List<Person> list = ps.stream().collect(
Collectors.collectingAndThen(Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparing(p -> p.getName()))), ArrayList::new)
);
list.forEach(System.out::println);
System.out.println("-----------");
//根据name与age进行去重
List<Person> list1 = ps.stream().collect(
Collectors.collectingAndThen(Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparing(p -> p.getName()+";"+p.getAge()))), ArrayList::new)
);
list1.forEach(System.out::println);
}
}
@Data
class Person{
String name;
int age;
Person(int age,String name){
this.name=name;
this.age=age;
}
}
执行结果
Person(name=tom, age=11)
Person(name=张三, age=11)
-----------
Person(name=tom, age=11)
Person(name=tom, age=12)
Person(name=张三, age=11)
//获取list中所有的name
List<String> list=ps.stream().map(Person::getName).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
list.forEach(System.out::println);
执行结果
tom
张三
List<Person> list=ps.stream().filter(p -> p.getAge()>11).collect(Collectors.toList());
list.forEach(System.out::println);
执行结果
Person(name=tom, age=12)
Map<Integer,List<Person>> map=ps.stream().collect(Collectors.groupingBy(Person::getAge));
System.out.println(map.get(11));
执行结果:
[Person(name=tom, age=11), Person(name=张三, age=11), Person(name=tom, age=11)]
根据类型分组,并分别计算每组的年龄总和
public class test {
public static void main(String[] args) {
List<User> list=new ArrayList<>();
list.add(new User("张三",20,"A"));
list.add(new User("tom",21,"A"));
list.add(new User("jack",22,"B"));
//stream根据年龄字段计算总和
int ageSum= list.stream().mapToInt(User::getAge).sum();
//根据A,B分组,并分别计算每组的年龄总和
List<User> list1=list.stream()
.collect(Collectors.groupingBy(User::getType))
.entrySet()
.stream().map((entry)-> {
String key=entry.getKey();
List<User> typeList=entry.getValue();
int sum=typeList.stream().mapToInt(User::getAge).sum();
return new User("A",sum,key);
})
// 根据age倒序排序
.sorted(Comparator.comparing(User::getAge).reversed())
.collect(Collectors.toList());
System.out.println(list1);
}
}
@Data
class User{
String username;
Integer age;
String type;
User(String username,Integer age,String type){
this.username=username;
this.age=age;
this.type=type;
}
}
执行结果:
[User(username=A, age=41, type=A), User(username=A, age=22, type=B)]
list转map若key重复,则需要指定重复策略(如重复时新的替换旧的),否则会报错。
List<Person> ps=new ArrayList<>();
ps.add(new Person(11,"tom"));
ps.add(new Person(11,"张三"));
// 将list转换为 map,注意name作为 key 不能重复,应先做去重处理,否则会报错
Map<String, Integer> map = ps.stream().collect(Collectors.toMap(Person::getName, Person::getAge));
map.forEach((s, i) -> System.out.println(s+"|"+i));
// 用 name 做 key 将 List 转成 Map
Map<String, Person> map1 = ps.stream().collect(Collectors.toMap(Person::getName, item -> item));
//将list转成Map, 若key重复,则使用旧的,解决key重复报错的问题
Map<String, Person> map2 = ps.stream().collect(Collectors.toMap(Person::getName, Function.identity(), (oldValue, newValue) -> oldValue));
//根据name进行去重,转换为Map,然后再转换为list
ps.stream().collect(Collectors.toMap(Person::getName, Function.identity(), (oldValue, newValue) -> oldValue))
.values()
.stream();
for (Person p : ps) {
System.out.println(p);
}
执行结果
张三|11
tom|11
public class test {
public static void main(String[] args) {
List<Person> ps=new ArrayList<>();
ps.add(new Person(11,"tom"));
ps.add(new Person(11,"张三"));
ps.add(new Person(12,"tom"));
ps.add(new Person(11,"tom"));
// 按照年龄从高到低排序
// 方式一
ps.sort((o1, o2)
-> o1.getAge() == null ? 1 : (o2.getAge() == null ? -1 : o2.getAge().compareTo(o1.getAge())));
System.out.println(ps);
// 方式二
ps.sort(Comparator.comparing(Person::getAge, (o1, o2)
-> o1 == null ? 1 : (o2 == null ? -1 : o2.compareTo(o1))));
System.out.println(ps);
// 方式三 (age 字段不能为 null, null 会导致排序失败)
ps.sort(Comparator.comparing(Person::getAge).reversed());
System.out.println(ps);
// 先按照年龄排序,再按照姓名从高到低排序
ps.sort(Comparator.comparing(Person::getAge, (o1, o2)
-> o1 == null ? 1 : (o2 == null ? -1 : o1.compareTo(o2))).thenComparing((o1, o2)
-> o1.getName() == null ? 1 : (o2.getName() == null ? -1 : o2.getName().compareTo(o1.getName()))));
System.out.println(ps);
}
}
@Data
class Person{
String name;
Integer age;
Person(Integer age,String name){
this.name=name;
this.age=age;
}
}
执行结果
[Person(name=tom, age=12), Person(name=tom, age=11), Person(name=张三, age=11), Person(name=tom, age=11)]
[Person(name=tom, age=12), Person(name=tom, age=11), Person(name=张三, age=11), Person(name=tom, age=11)]
[Person(name=tom, age=12), Person(name=tom, age=11), Person(name=张三, age=11), Person(name=tom, age=11)]
[Person(name=张三, age=11), Person(name=tom, age=11), Person(name=tom, age=11), Person(name=tom, age=12)]
List<Person> ps=new ArrayList<>();
ps.add(new Person(11,"tom"));
ps.add(new Person(11,"张三"));
ps.add(new Person(12,"tom"));
ps.add(new Person(11,"tom"));
ps.stream()
//Collectors.toMap(Person::getAge 或者这样写 Collectors.toMap(m -> m.getUserId()
.collect(Collectors.toMap(Person::getAge,
Function.identity(), (oldValue, newValue) -> oldValue))
.values()
.stream()
.forEach(System.out::println); //打印
执行结果:
Person(name=tom, age=11)
Person(name=tom, age=12)
代码讲解
ps.stream()
.collect(Collectors.toMap(Person::getAge,
Function.identity(), (oldValue, newValue) -> oldValue))
如上代码返回的是Map
List<Person> ps=new ArrayList<>();
ps.add(new Person(11,"tom"));
ps.add(new Person(11,"张三"));
ps.add(new Person(12,"tom"));
ps.add(new Person(11,"tom"));
ps.stream()
.collect(Collectors.toCollection(() ->
new TreeSet<>(Comparator.comparing(Person::getName))))
.stream()
.forEach(System.out::println); //打印
利用TreeSet原理去重,TreeSet内部使用的是TreeMap,使用指定Comparator比较元素,如果元素相同,则新元素代替旧元素,如果不想要返回TreeSet类型,那也可以使用Collectors.collectingAndThen转换成ArrayList,也可以用new ArrayList(set),原理一样,如下:
List<Person> list = ps.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(()
-> new TreeSet<>(Comparator.comparing(Person::getName))), ArrayList::new));
** 如果想根据多个去重,可以将上述方法中的Comparator.comparing(Person::getName))修改为Comparator.comparing(p -> p.getName() +“;” + p.getAge() )) 这样就是根据两个字段去重,中间的 ; 作用就是为了增加辨识度,也可以不加这个 ; ,无论多少个字段去重只用在这里用+连接就可以了