Java8系列--玩转Stream流

108 阅读3分钟

Stream流概述

Java 8 是一个非常成功的版本,这个版本新增的Stream,配合同版本出现的 Lambda ,给我们操作集合(Collection)提供了极大的便利。

那么什么是Stream?

Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。

Stream可以由数组或集合创建,对流的操作分为两种:

  1. 中间操作,每次返回一个新的流,可以有多个。
  2. 终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。

另外,Stream有几个特性:

  1. stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
  2. stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
  3. stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。

Stream流的常用操作

1.List集合转Map

用到的是Stream中Collectors的toMap方法:Collectors.toMap

具体用法实例如下:

//声明一个List集合
List<Person> list = new ArrayList(); 
  list.add(new Person("1001", "小A")); 
  list.add(new Person("1002", "小B")); 
  list.add(new Person("1003", "小C"));
  System.out.println(list);
//将list转换map
Map<String, String> map = list.stream().collect(Collectors.toMap(Person::getId, Person::getName));
  System.out.println(map);

输出结果为:

注意:用Collectors的toMap方法转换List,一般会遇到两个问题。

一个是转换map,key重复问题;另一个是空指针异常,即转为map的value是null。

问题解决!!!

一、第一种问题报的错误如下:Duplicate key

原因是声明List集合时,有的Key重复,如图:

解决方法:(分三种,具体哪种看业务需求)

1.重复时用后面的value 覆盖前面的value

Map<String, String> map = list.stream().collect(Collectors.toMap(Person::getId, Person::getName,(key1 , key2)-> key2 ));
  System.out.println(map); 

2.重复时将前面的value 和后面的value拼接起来;

Map<String, String> map = list.stream().collect(Collectors.toMap(Person::getId, Person::getName,(key1 , key2)-> key1+","+key2 ));  System.out.println(map);

3.重复时将重复key的数据组成集合

Map<String, List<String>> map = list.stream().collect(Collectors.toMap(Person::getId,
	 		p -> {
	 		 	List<String> getNameList = new ArrayList<>();
	 		 		getNameList.add(p.getName());
	 		 		return getNameList;
	 		 	},
 		  	(List<String> value1, List<String> value2) -> {
 		  		value1.addAll(value2);
 		  		return value1;
 		  	}
	 		 ));
  
   System.out.println(map);

输出结果:

二:value为空导致 空指针

未重现此异常

TODO

2.对象List转另一个对象List

List<Student> studentList = persons.stream().map(v -> {
            return new Student(v.getName(), v.getSex());
        }).collect(Collectors.toList());

3.按某个属性统计分组

// 学生信息按照班级ID分组,返回map,key为班级ID,value为学生列表
Map<String, List<Student>> student = students.stream().collect(Collectors.groupingBy(Student::getClassId));

4.按某个属性分组并统计数量

//按城市分组统计count


Map<String, Long> map = employees.stream().collect(Collectors.groupingBy(Employee::getCity, Collectors.counting()));

5.按某个属性分组统计并计算平均值

Map<String, Double> map = employees.stream()
				.collect(Collectors.groupingBy(Employee::getCity, Collectors.averagingInt(Employee::getAge)));

6.按某个属性分组统计并计算总值

Map<String, Long> map = employees.stream()
				.collect(Collectors.groupingBy(Employee::getCity, Collectors.summingLong(Employee::getAmount)));

7.JSONArray和List互转

1.List转JSONArray

List list = new ArrayList();
JSONArray array= JSONArray.parseArray(JSON.toJSONString(list));
2.JSONArray转List

JSONArray array = new JSONArray();
List list = JSONObject.parseArray(array.toJSONString(), UserProfileInterval.class);
3.String转JSONArray

List list = JSONArray.parseArray(JSON.toJSONString(array), Population.class);

8.List分组

Map<String, List> dicCollect = dicAllList.stream().collect(Collectors.groupingBy(Dictionary::getDicType));

可以对结果进行映射,求和,统计

映射:
Map <String,List > collect = users.stream().collect(Collectors.groupingBy(User: :getEdu, //第二个参数对Map的value进行处理(映射) Collectors.mapping(User: :getId, Collectors.toList())));

求和:

Map <String,Double> collect = users.stream().collect(Collectors.groupingBy(User: :getEdu, //对参数进行累计求和 Collectors.summingDouble(User: :getPrice)));

统计:

Map < String,Long > collect = users.stream().collect(Collectors.groupingBy(User: :getEdu, //获取count数量 Collectors.counting()));

统计:需要三个参数,第三个参数添加了对结果Map的生成方式,默认是HashMap

Map <String,Double > collect = users.stream().collect(Collectors.groupingBy(User: :getEdu, //决定map的生成方式,使用TreeMap TreeMap: :new, //对参数进行累计求和 Collectors.summingDouble(User: :getPrice)));