Java Stream流式处理集合 去重排序分组转换操作

工作中Stream流操作集合 很方便快捷,以下是记录常用的去重排序分组转换操作

去重

1.首先使用Integer 和String 类型集合 进行操作 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//定义两组数据类型集合
List<Integer> integers = Arrays.asList(12, 13, 5, 4, 6, 6, 8);
List<String> strs = Arrays.asList("12", "23","3","a","8","3","a");

//数据去重
integers.stream().distinct().forEach(System.out::println);
strs.stream().distinct().forEach(System.out::println);

//数据排序 默认正序
integers.stream().sorted().forEach(System.out::println);
strs.stream().sorted().forEach(System.out::println);

//倒叙写法
integers.stream().sorted(Comparator.comparingInt(x->-x)).forEach(System.out::println);
//integers.stream().sorted(Collections.reverseOrder()).forEach(System.out::println);
strs.stream().sorted(Collections.reverseOrder()).forEach(System.out::println);


2.定义实体Person及组装数据:

1
2
3
4
5
6
7
8
9
10
11
List<Person> list = new ArrayList<>();
list.add(new Person("zhangsan", 20, "男"));
list.add(new Person("lisi", 22, "男"));
list.add(new Person("chensan", 25, "男"));
list.add(new Person("zhaosi", 22, "男"));
list.add(new Person("zhaosi", 40, "男"));
list.add(new Person("liuliu", 22, "女"));
list.add(new Person("lisi", 24, "女"));
list.add(new Person("lisi", 23, "女"));


按名字去重后展示

1
2
list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person::getName)))
, ArrayList::new)).forEach(System.out::println);

执行输出:

Person(name=chensan, age=25, sex=男)
Person(name=lisi, age=22, sex=男)
Person(name=liuliu, age=22, sex=女)
Person(name=zhangsan, age=20, sex=男)
Person(name=zhaosi, age=22, sex=男)

按名字 年龄去重

1
2
3
list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() ->
new TreeSet<>(Comparator.comparing(x -> String.join("-", x.getName(), String.valueOf(x.getAge())))))
, ArrayList::new)).forEach(System.out::println);

执行输出:

Person(name=chensan, age=25, sex=男)
Person(name=lisi, age=22, sex=男)
Person(name=lisi, age=23, sex=女)
Person(name=lisi, age=24, sex=女)
Person(name=liuliu, age=22, sex=女)
Person(name=zhangsan, age=20, sex=男)
Person(name=zhaosi, age=22, sex=男)
Person(name=zhaosi, age=40, sex=男)

按名字 年龄 性别去重

1
2
3
list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() ->
new TreeSet<>(Comparator.comparing(x -> String.join("-", x.getName(), String.valueOf(x.getAge()), x.getSex()))))
, ArrayList::new)).forEach(System.out::println);

执行输出:

Person(name=chensan, age=25, sex=男)
Person(name=lisi, age=22, sex=男)
Person(name=lisi, age=23, sex=女)
Person(name=lisi, age=24, sex=女)
Person(name=liuliu, age=22, sex=女)
Person(name=zhangsan, age=20, sex=男)
Person(name=zhaosi, age=22, sex=男)
Person(name=zhaosi, age=40, sex=男)

排序

根据年龄排序 再根据名字排序 从小到大

1
list.stream().sorted(Comparator.comparing(Person::getAge).thenComparing(Person::getName)).forEach(System.out::println);

执行输出:

Person(name=zhangsan, age=20, sex=男)
Person(name=lisi, age=22, sex=男)
Person(name=liuliu, age=22, sex=女)
Person(name=zhaosi, age=22, sex=男)
Person(name=lisi, age=23, sex=女)
Person(name=lisi, age=24, sex=女)
Person(name=chensan, age=25, sex=男)
Person(name=zhaosi, age=40, sex=男)

根据年龄排序 再根据名字排序 从大到小

1
2
list.stream().sorted(Comparator.comparing(Person::getAge,Comparator.reverseOrder())).forEach(System.out::println);
//list.stream().sorted(Comparator.comparing(Person::getAge).reversed()).forEach(System.out::println);

执行输出:

Person(name=zhaosi, age=40, sex=男)
Person(name=chensan, age=25, sex=男)
Person(name=lisi, age=24, sex=女)
Person(name=lisi, age=23, sex=女)
Person(name=lisi, age=22, sex=男)
Person(name=zhaosi, age=22, sex=男)
Person(name=liuliu, age=22, sex=女)
Person(name=zhangsan, age=20, sex=男)

当存在字段为null时,执行会报空指针异常,此时可用Comparator.nullsLast 或Comparator.nullsFirst 比较器 将null值数据放到最前或最后

如:添加 一组年龄为空的数据

list.add(new Person(“ben”, null, “女”));

根据年龄排序 存在age字段为空时 ,null值排在最前面 后根据age倒序展示

1
list.stream().sorted(Comparator.comparing(Person::getAge,Comparator.nullsFirst(Collections.reverseOrder()))).forEach(System.out::println);

执行输出:

Person(name=ben, age=null, sex=女)
Person(name=zhaosi, age=40, sex=男)
Person(name=chensan, age=25, sex=男)
Person(name=lisi, age=24, sex=女)
Person(name=lisi, age=23, sex=女)
Person(name=lisi, age=22, sex=男)
Person(name=zhaosi, age=22, sex=男)
Person(name=liuliu, age=22, sex=女)
Person(name=zhangsan, age=20, sex=男)

根据年龄排序 存在age字段为空时 ,null值排在最后面 后根据age倒序展示

1
list.stream().sorted(Comparator.comparing(Person::getAge,Comparator.nullsLast(Collections.reverseOrder()))).forEach(System.out::println);

执行输出:

Person(name=zhaosi, age=40, sex=男)
Person(name=chensan, age=25, sex=男)
Person(name=lisi, age=24, sex=女)
Person(name=lisi, age=23, sex=女)
Person(name=lisi, age=22, sex=男)
Person(name=zhaosi, age=22, sex=男)
Person(name=liuliu, age=22, sex=女)
Person(name=zhangsan, age=20, sex=男)
Person(name=ben, age=null, sex=女)

获取年龄最大的人的名字

1
System.out.println(list.stream().max(Comparator.comparing(Person::getAge)).orElse(new Person()).getName());

分组统计

根据名字_性别 分组

1
list.stream().collect(Collectors.groupingBy(x->x.getName()+"_"+x.getSex())).forEach((x,y)-> System.out.println(x+"="+y));

执行输出:

lisi_男=[Person(name=lisi, age=22, sex=男)]
liuliu_女=[Person(name=liuliu, age=22, sex=女)]
chensan_男=[Person(name=chensan, age=25, sex=男)]
zhaosi_男=[Person(name=zhaosi, age=22, sex=男), Person(name=zhaosi, age=40, sex=男)]
lisi_女=[Person(name=lisi, age=24, sex=女), Person(name=lisi, age=23, sex=女)]
zhangsan_男=[Person(name=zhangsan, age=20, sex=男)]

根据姓名 统计数量

1
list.stream().collect(Collectors.groupingBy(Person::getName,Collectors.counting())).forEach((x, y)-> System.out.println(x+"="+y));

执行输出:

chensan=1
lisi=3
zhaosi=2
zhangsan=1
liuliu=1

根据名字分组 统计年龄总和

1
list.stream().collect(Collectors.groupingBy(Person::getName, Collectors.summingInt(Person::getAge))).forEach((x,y)-> System.out.println(x+"="+y));

执行输出:

chensan=25
lisi=69
zhaosi=62
zhangsan=20
liuliu=22

转换Map

按名字作为键 值为年龄最大的 转换成Map

1
2
3
list.stream().collect(Collectors.toMap(Person::getName,Function.identity(), BinaryOperator.maxBy(Comparator.comparing(Person::getAge)))).forEach((x,y)->
System.out.println(x+"="+y)
);

执行输出:

chensan=Person(name=chensan, age=25, sex=男)
lisi=Person(name=lisi, age=24, sex=女)
zhaosi=Person(name=zhaosi, age=40, sex=男)
zhangsan=Person(name=zhangsan, age=20, sex=男)
liuliu=Person(name=liuliu, age=22, sex=女)

按名字作为键 值为性别以分号追加展示 转换成Map

1
list.stream().collect(Collectors.toMap(Person::getName, Person::getSex, (m, n) -> m + ";" + n)).forEach((x, y) -> System.out.println(x + "=" + y));

执行输出:

chensan=男
lisi=男;女;女
zhaosi=男;男
zhangsan=男
liuliu=女

注:如果使用两个参数的toMap方法时,若存在键重复时会报 “ Duplicate key ” 错

1
list.stream().collect(Collectors.toMap(Person::getName, Person::getSex)).forEach((x, y) -> System.out.println(x + "=" + y));

执行输出:

Exception in thread “main” java.lang.IllegalStateException: Duplicate key zhaosi (attempted merging values 男 and 男)
at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:133)
at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:180)
at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)

Java8相关资料参考文档:

Java 8 教程汇总 https://wizardforcel.gitbooks.io/java8-tutorials/content/index.html

Java8简明教程 https://wizardforcel.gitbooks.io/modern-java

Java8新特性探究 https://wizardforcel.gitbooks.io/java8-new-features/content/