1.概述

在前一篇文章中已经整理流的一些创建方式,流的一些操作等知识,这一篇针对流的收集进行介绍。
流在经历过一些过滤、去重或其他的操作后,最终的结果还是被封装进入数组、集合或Map中。

2.收集到数组中

1.对于Int | Long | Double Stream 三个基本数据类型流来说,它们的toArray方法,会生成相应基本类型数组

  1. @Test
  2. public void testToArray() {
  3. int[] array = {1,2,3,4,5,5,6,4};
  4. int[] ints = Arrays.stream(array).toArray();
  5. System.out.println(Arrays.toString(ints));
  6. long[] array1 = {1L,2L,3L,4L};
  7. long[] longs = Arrays.stream(array1).toArray();
  8. System.out.println(Arrays.toString(longs));
  9. }

2.对于引用类型的流默认 toArray() 方法返回的是 Object[],当然也可以指定类型

  1. @Test
  2. public void testToArray() {
  3. String[] array ={"hello","Java","World","Durant","Kobe"};
  4. //默认返回Object 数组
  5. Object[] objects = Arrays.stream(array).toArray();
  6. //提供一个构造方法,可以返回相应的类型
  7. String[] strings = Arrays.stream(array).toArray(String[]::new);
  8. Person[] array2={new Person(1L,"阿美","女",24),
  9. new Person(2L,"路路","男",23)};
  10. Object[] objects1 = Arrays.stream(array2).toArray();
  11. Person[] people = Arrays.stream(array2).toArray(Person[]::new);
  12. System.out.println(Arrays.toString(people));
  13. }

3.收集到集合中

集合的话包含两类:List、Set
1.使用默认的收集方式

  1. @Test
  2. public void testToArray() {
  3. String[] array ={"hello","Java","World","Durant","Durant"};
  4. List<String> collect = Arrays.stream(array).collect(Collectors.toList());
  5. //默认是ArrayList
  6. if(collect instanceof ArrayList){
  7. System.out.println("hello");
  8. }else if(collect instanceof LinkedList){
  9. System.out.println("world");
  10. }else {
  11. System.out.println("bye");
  12. }
  13. Set<String> collect2 = Arrays.stream(array).collect(Collectors.toSet());
  14. //默认是HashSet
  15. if(collect2 instanceof HashSet){
  16. System.out.println("hello");
  17. }else if (collect2 instanceof TreeSet){
  18. System.out.println("world");
  19. }else {
  20. System.out.println("bye");
  21. }
  22. Person[] array2={new Person(1L,"阿美","女",24),
  23. new Person(2L,"路路","男",23)};
  24. List<Person> collect1 = Arrays.stream(array2).collect(Collectors.toList());
  25. }

如果用户想要自定义生成Set或List的具体实现类

  1. @Test
  2. public void testToArray() {
  3. String[] array ={"hello","Java","World","Durant","Durant"};
  4. List<String> collect = Arrays.stream(array).collect(Collectors.toCollection(LinkedList::new));
  5. Set<String> collect2 = Arrays.stream(array).collect(Collectors.toCollection(TreeSet::new));
  6. if(collect instanceof LinkedList){
  7. System.out.println("hello");
  8. }
  9. if(collect2 instanceof TreeSet){
  10. System.out.println("world");
  11. }
  12. }

4.收集到映射表中

在实际项目中,往往在查询数据库后,将数据映射到Map中,主键作为key,元素本身作为value,存放后在程序后面根据主键取相应的值使用。
1.编号做key,元素本身做为value

  1. @Test
  2. public void testToArray() {
  3. Person[] array={new Person(1L,"阿美","女",24),
  4. new Person(2L,"路路","男",23)};
  5. //x - 代表元素本身
  6. Map<Long, Person> personMap = Arrays.stream(array).collect(Collectors.toMap(x -> x.getId(), x -> x));
  7. //可以使用Function.identity()代表使用元素本身
  8. Map<Long,Person> personMap1 = Arrays.stream(array).collect(Collectors.toMap(x->x.getId(), Function.identity()));
  9. //再换种写法
  10. Map<Long,Person> personMap2 = Arrays.stream(array).collect(Collectors.toMap(Person::getId, Function.identity()));
  11. }

2.问题来了,当出现key相同,即id相同如何解决

  1. java.lang.IllegalStateException: Duplicate key Person{id=2, name='路路', sex='男'}
  2. @Test
  3. public void testToArray() {
  4. Person[] array = {new Person(1L, "阿美", "女", 24),
  5. new Person(2L, "路路", "男", 23),
  6. new Person(2L, "嘻嘻", "男", 3)};
  7. Map<Long, Person> personMap2 = Arrays.stream(array).collect(Collectors.toMap(Person::getId, Function.identity()));
  8. }

解决方式

  1. /*
  2. 这里我选择了替换原value,当然具体情况具体写。
  3. 但本质就是在第三个参数中,添加一个Lamda表达式
  4. 第一个参数:在map中的值
  5. 第二个参数: 新增的值
  6. */
  7. @Test
  8. public void testToArray() {
  9. Person[] array = {new Person(1L, "阿美", "女", 24),
  10. new Person(2L, "路路", "男", 23),
  11. new Person(2L, "嘻嘻", "男", 3)};
  12. Map<Long, Person> personMap2 = Arrays.stream(array)
  13. .collect(Collectors
  14. .toMap(Person::getId,
  15. Function.identity(),
  16. //(已经存在的value,当前新增的value) -> 返回当前value
  17. (existValue, nowValue) -> nowValue));
  18. }

4.自定义Map的实现类
默认的是HashMap

  1. @Test
  2. public void testToArray() {
  3. Person[] array = {new Person(1L, "阿美", "女", 24),
  4. new Person(2L, "路路", "男", 23),
  5. new Person(2L, "嘻嘻", "男", 3)};
  6. Map<Long, Person> personMap2 = Arrays.stream(array)
  7. .collect(Collectors
  8. .toMap(Person::getId,
  9. Function.identity(),
  10. //(已经存在的value,当前新增的value) -> 返回当前value
  11. (existValue, nowValue) -> nowValue,Hashtable::new));
  12. }

5.分组

分组的还是将流映射为Map,但是其用法上有不同。
1.将人按照年龄分组,年龄作为key,当取某个年龄时,获得这个年龄所有人的list集合。

  1. @Test
  2. public void testToArray() {
  3. Person[] array = {new Person(1L, "阿美", "女", 24),
  4. new Person(2L, "路路", "男", 23),
  5. new Person(2L, "嘻嘻", "男", 3),
  6. new Person(3L,"华华","女",23)};
  7. //默认的你只需要提供一个key,之后分组会将相同key的人放入 List中
  8. Map<Integer, List<Person>> collect = Arrays.stream(array)
  9. .collect(Collectors.groupingBy(x -> x.getAge()));
  10. System.out.println(collect);
  11. }

2.还是按照年龄分组,这次我只想知道每个年龄有多少人 (经典的词频统计也使用这个做)

  1. @Test
  2. public void testToArray() {
  3. Person[] array = {new Person(1L, "阿美", "女", 24),
  4. new Person(2L, "路路", "男", 23),
  5. new Person(2L, "嘻嘻", "男", 3),
  6. new Person(3L,"华华","女",23)};
  7. //默认的你只需要提供一个key, 之后将相同年龄的List<Person>的流 使用 Collectors.counting进行收集
  8. //相同于 List<Person>.stream.collect(Collectors.counting())
  9. Map<Integer, Long> collect = Arrays.stream(array)
  10. .collect(Collectors.groupingBy(x -> x.getAge(),Collectors.counting()));
  11. System.out.println(collect);
  12. }

6.约简

当你需要对一个集合的元素做类似 v1+v2+v3+v4+…+vn的操作时,可以使用这种方法
1.计算[1,3,4,5,6,7]的相乘结果

  1. @Test
  2. public void testToArray() {
  3. List<Integer> integers = Arrays.asList(1, 3, 4, 5, 6, 7, 8, 8, 7);
  4. Optional<Integer> reduce = integers.stream().reduce((x, y) -> x * y);
  5. System.out.println(reduce.get());
  6. }

2.如果集合为空则会没有值,于是可以设置一个默认返回

  1. @Test
  2. public void testToArray() {
  3. List<Integer> integers = new ArrayList<Integer>();
  4. Integer reduce = integers.stream().reduce(0, (x, y) -> x * y);
  5. System.out.println(reduce);
  6. }