1.概述
在前一篇文章中已经整理流的一些创建方式,流的一些操作等知识,这一篇针对流的收集进行介绍。
流在经历过一些过滤、去重或其他的操作后,最终的结果还是被封装进入数组、集合或Map中。
2.收集到数组中
1.对于Int | Long | Double Stream 三个基本数据类型流来说,它们的toArray方法,会生成相应基本类型数组
@Test
public 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[]
,当然也可以指定类型
@Test
public 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.使用默认的收集方式
@Test
public void testToArray() {
String[] array ={"hello","Java","World","Durant","Durant"};
List<String> collect = Arrays.stream(array).collect(Collectors.toList());
//默认是ArrayList
if(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());
//默认是HashSet
if(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的具体实现类
@Test
public 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
@Test
public 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='男'}
@Test
public 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中的值
第二个参数: 新增的值
*/
@Test
public 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
@Test
public 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集合。
@Test
public 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.还是按照年龄分组,这次我只想知道每个年龄有多少人 (经典的词频统计也使用这个做)
@Test
public 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]的相乘结果
@Test
public 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.如果集合为空则会没有值,于是可以设置一个默认返回
@Test
public void testToArray() {
List<Integer> integers = new ArrayList<Integer>();
Integer reduce = integers.stream().reduce(0, (x, y) -> x * y);
System.out.println(reduce);
}