Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
上述流程转换为Java代码为:
List<Integer> transactionsIds = widgets.stream() .filter(b -> b.getColor() == RED) .sorted((x,y) -> x.getWeight() - y.getWeight()) .mapToInt(Widget::getWeight) .sum();
Stream(流)是一个来自数据源的元素队列并支持聚合操作
和以前的Collection操作不同, Stream操作还有两个基础的特征:
forEach():迭代流中的每个数据
map():映射每个元素到对应的结果
Collectors类:实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串。通常在 .collect(Collectors.方法)
filter():设置的条件过滤出元素
案例一:根据医院编号,查询医院所有科室列表(并封装)
collect分组
DepartmentVo
@Data @ApiModel(description = "Department") public class DepartmentVo { @ApiModelProperty(value = "科室编号") private String depcode; @ApiModelProperty(value = "科室名称") private String depname; @ApiModelProperty(value = "下级节点") private List<DepartmentVo> children; }
Department
@Data @ApiModel(description = "Department") @Document("Department") public class Department extends BaseMongoEntity { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "医院编号") @Indexed //普通索引 private String hoscode; @ApiModelProperty(value = "科室编号") @Indexed(unique = true) //唯一索引 private String depcode; @ApiModelProperty(value = "科室名称") private String depname; @ApiModelProperty(value = "科室描述") private String intro; @ApiModelProperty(value = "大科室编号") private String bigcode; @ApiModelProperty(value = "大科室名称") private String bigname; }
stream流的功能代码
List
使用collect方法,对departmentList中所有Department对象进行分组,按照大科室的code分组,即Department中的bigcode字段。相同bigcode分在一个list中,key则是bigcode
//根据大科室编号 bigcode 分组,每个value是一个大科室list,其中成员是所对应的小科室对象 Map<String, List<Department>> deparmentMap = departmentList.stream().collect(Collectors.groupingBy(Department::getBigcode));
返回的数据,一部分:
{ a4e171f4cf9b6816acdfb9ae62c414d7=[Department(hoscode=1000_0, depcode=200040878, depname=多发性硬化专科门诊, intro=多发性硬化专科门诊, bigcode=a4e171f ...), Department(...), Department(...) ....], 0551a547cc19d3d09f2e57bd2931b7d0=[Department ......], ... }
//根据医院编号,查询医院所有科室列表(并封装) @Override public List<DepartmentVo> findDeptTree(String hoscode) { //########################################################### //创建list集合,用于最终数据封装 List<DepartmentVo> result = new ArrayList<>(); // DepartmentVo实体类,与数据库Department表建立映射关系 //根据医院编号,查询医院所有科室信息 Department departmentQuery = new Department(); departmentQuery.setHoscode(hoscode); // 设置科室表中的医院编号 Example example = Example.of(departmentQuery); // 传入实体 //所有科室列表 departmentList List<Department> departmentList = departmentRepository.findAll(example); // 得到医院编号字段为指定id的所有科室 //########################################################### //根据大科室编号 bigcode 分组,每个value是一个大科室list,其中成员是所对应的小科室对象 Map<String, List<Department>> deparmentMap = departmentList.stream().collect(Collectors.groupingBy(Department::getBigcode)); System.out.println(deparmentMap); //########################################################### //遍历map集合 deparmentMap,遍历每一个大科室:对每一个大科室重新进行封装,包含其下级子科室 for(Map.Entry<String,List<Department>> entry : deparmentMap.entrySet()) { //大科室编号 String bigcode = entry.getKey(); // 即 key //大科室编号对应的所有下级科室数据,已经建立好bigcode对应下级科室的列表 List<Department> deparment1List = entry.getValue(); //封装大科室 DepartmentVo departmentVo1 = new DepartmentVo(); departmentVo1.setDepcode(bigcode); departmentVo1.setDepname(deparment1List.get(0).getBigname()); // 每一个下级科室,都有对应的大科室名称,随便选一个子科室获取即可 //封装小科室,将数据库中的科室数据重新封装成DepartmentVo类型,方便之后前端使用 List<DepartmentVo> children = new ArrayList<>(); for(Department department: deparment1List) { DepartmentVo departmentVo2 = new DepartmentVo(); departmentVo2.setDepcode(department.getDepcode()); departmentVo2.setDepname(department.getDepname()); //封装到list集合 children.add(departmentVo2); } //把小科室list集合放到大科室children里面 departmentVo1.setChildren(children); //放到最终result里面 result.add(departmentVo1); } //返回 return result; }
案例二:获取list集合,使用遍历,重新对集合中的元素进行封装
foreach
// 创建example对象 Example<Hospital> example = Example.of(hospital, matcher); // 调用方法实现查询,从MongoDB中,获取对象 Page<Hospital> pages = hospitalRepository.findAll(example, pageable); // 获取查询list集合,遍历进行医院等级封装 pages.getContent().stream().forEach(item -> { // HosType 医院等级,如三甲 this.setHospitalHosType(item); // item 传入的是 Hospital 对象 });
案例三:将List类型转换为Map类型
Collectors.toMap
List<BookingScheduleRuleVo> scheduleVoList = aggregateResult.getMappedResults(); // List // List转Map,以workdate为key,value是BookingScheduleRuleVo类型的对象 Map<Date, BookingScheduleRuleVo> scheduleVoMap = new HashMap<>(); if(!CollectionUtils.isEmpty(scheduleVoList)) { scheduleVoMap = scheduleVoList.stream(). collect( Collectors.toMap(BookingScheduleRuleVo::getWorkDate, BookingScheduleRuleVo -> BookingScheduleRuleVo)); }
案例四:从List
stream().map().collect(Collectors.toList())
// List<OrderCountVo> orderCountVoList //获取x需要数据 ,将OrderCountVo中的date过滤,并形成日期列表 List<String> dateList = orderCountVoList.stream().map(OrderCountVo::getReserveDate).collect(Collectors.toList()); //获取y需要数据,过滤OrderCountVo中的count,并形成数量列表 List<Integer> countList =orderCountVoList.stream().map(OrderCountVo::getCount).collect(Collectors.toList());
等效于:用一个for循环,遍历orderCountVoList,并将每个item的getReserveDate()和getCount()的值,添加到各自的list中。