1.概述
在前一篇文章中已经整理流的一些创建方式,流的一些操作等知识,这一篇针对流的收集进行介绍。
流在经历过一些过滤、去重或其他的操作后,最终的结果还是被封装进入数组、集合或Map中。
2.收集到数组中
1.对于Int | Long | Double Stream 三个基本数据类型流来说,它们的toArray方法,会生成相应基本类型数组
@Testpublic void testToArray() {int[] array = {1,2,3,4,5,5,6,4};int[] ints = Arrays.stream(array).toArray();System.out.println(Arrays.toString(ints));long[] array1 = {1L,2L,3L,4L};long[] longs = Arrays.stream(array1).toArray();System.out.println(Arrays.toString(longs));}
2.对于引用类型的流默认 toArray() 方法返回的是 Object[],当然也可以指定类型
@Testpublic void testToArray() {String[] array ={"hello","Java","World","Durant","Kobe"};//默认返回Object 数组Object[] objects = Arrays.stream(array).toArray();//提供一个构造方法,可以返回相应的类型String[] strings = Arrays.stream(array).toArray(String[]::new);Person[] array2={new Person(1L,"阿美","女",24),new Person(2L,"路路","男",23)};Object[] objects1 = Arrays.stream(array2).toArray();Person[] people = Arrays.stream(array2).toArray(Person[]::new);System.out.println(Arrays.toString(people));}
3.收集到集合中
集合的话包含两类:List、Set
1.使用默认的收集方式
@Testpublic void testToArray() {String[] array ={"hello","Java","World","Durant","Durant"};List<String> collect = Arrays.stream(array).collect(Collectors.toList());//默认是ArrayListif(collect instanceof ArrayList){System.out.println("hello");}else if(collect instanceof LinkedList){System.out.println("world");}else {System.out.println("bye");}Set<String> collect2 = Arrays.stream(array).collect(Collectors.toSet());//默认是HashSetif(collect2 instanceof HashSet){System.out.println("hello");}else if (collect2 instanceof TreeSet){System.out.println("world");}else {System.out.println("bye");}Person[] array2={new Person(1L,"阿美","女",24),new Person(2L,"路路","男",23)};List<Person> collect1 = Arrays.stream(array2).collect(Collectors.toList());}
如果用户想要自定义生成Set或List的具体实现类
@Testpublic void testToArray() {String[] array ={"hello","Java","World","Durant","Durant"};List<String> collect = Arrays.stream(array).collect(Collectors.toCollection(LinkedList::new));Set<String> collect2 = Arrays.stream(array).collect(Collectors.toCollection(TreeSet::new));if(collect instanceof LinkedList){System.out.println("hello");}if(collect2 instanceof TreeSet){System.out.println("world");}}
4.收集到映射表中
在实际项目中,往往在查询数据库后,将数据映射到Map中,主键作为key,元素本身作为value,存放后在程序后面根据主键取相应的值使用。
1.编号做key,元素本身做为value
@Testpublic void testToArray() {Person[] array={new Person(1L,"阿美","女",24),new Person(2L,"路路","男",23)};//x - 代表元素本身Map<Long, Person> personMap = Arrays.stream(array).collect(Collectors.toMap(x -> x.getId(), x -> x));//可以使用Function.identity()代表使用元素本身Map<Long,Person> personMap1 = Arrays.stream(array).collect(Collectors.toMap(x->x.getId(), Function.identity()));//再换种写法Map<Long,Person> personMap2 = Arrays.stream(array).collect(Collectors.toMap(Person::getId, Function.identity()));}
2.问题来了,当出现key相同,即id相同如何解决
java.lang.IllegalStateException: Duplicate key Person{id=2, name='路路', sex='男'}@Testpublic void testToArray() {Person[] array = {new Person(1L, "阿美", "女", 24),new Person(2L, "路路", "男", 23),new Person(2L, "嘻嘻", "男", 3)};Map<Long, Person> personMap2 = Arrays.stream(array).collect(Collectors.toMap(Person::getId, Function.identity()));}
解决方式
/*这里我选择了替换原value,当然具体情况具体写。但本质就是在第三个参数中,添加一个Lamda表达式第一个参数:在map中的值第二个参数: 新增的值*/@Testpublic void testToArray() {Person[] array = {new Person(1L, "阿美", "女", 24),new Person(2L, "路路", "男", 23),new Person(2L, "嘻嘻", "男", 3)};Map<Long, Person> personMap2 = Arrays.stream(array).collect(Collectors.toMap(Person::getId,Function.identity(),//(已经存在的value,当前新增的value) -> 返回当前value(existValue, nowValue) -> nowValue));}
4.自定义Map的实现类
默认的是HashMap
@Testpublic void testToArray() {Person[] array = {new Person(1L, "阿美", "女", 24),new Person(2L, "路路", "男", 23),new Person(2L, "嘻嘻", "男", 3)};Map<Long, Person> personMap2 = Arrays.stream(array).collect(Collectors.toMap(Person::getId,Function.identity(),//(已经存在的value,当前新增的value) -> 返回当前value(existValue, nowValue) -> nowValue,Hashtable::new));}
5.分组
分组的还是将流映射为Map,但是其用法上有不同。
1.将人按照年龄分组,年龄作为key,当取某个年龄时,获得这个年龄所有人的list集合。
@Testpublic void testToArray() {Person[] array = {new Person(1L, "阿美", "女", 24),new Person(2L, "路路", "男", 23),new Person(2L, "嘻嘻", "男", 3),new Person(3L,"华华","女",23)};//默认的你只需要提供一个key,之后分组会将相同key的人放入 List中Map<Integer, List<Person>> collect = Arrays.stream(array).collect(Collectors.groupingBy(x -> x.getAge()));System.out.println(collect);}
2.还是按照年龄分组,这次我只想知道每个年龄有多少人 (经典的词频统计也使用这个做)
@Testpublic void testToArray() {Person[] array = {new Person(1L, "阿美", "女", 24),new Person(2L, "路路", "男", 23),new Person(2L, "嘻嘻", "男", 3),new Person(3L,"华华","女",23)};//默认的你只需要提供一个key, 之后将相同年龄的List<Person>的流 使用 Collectors.counting进行收集//相同于 List<Person>.stream.collect(Collectors.counting())Map<Integer, Long> collect = Arrays.stream(array).collect(Collectors.groupingBy(x -> x.getAge(),Collectors.counting()));System.out.println(collect);}
6.约简
当你需要对一个集合的元素做类似   v1+v2+v3+v4+…+vn的操作时,可以使用这种方法
1.计算[1,3,4,5,6,7]的相乘结果
@Testpublic void testToArray() {List<Integer> integers = Arrays.asList(1, 3, 4, 5, 6, 7, 8, 8, 7);Optional<Integer> reduce = integers.stream().reduce((x, y) -> x * y);System.out.println(reduce.get());}
2.如果集合为空则会没有值,于是可以设置一个默认返回
@Testpublic void testToArray() {List<Integer> integers = new ArrayList<Integer>();Integer reduce = integers.stream().reduce(0, (x, y) -> x * y);System.out.println(reduce);}
