Loading

1 2

开发记录:关于Java Stream,涉及遍历、分组以及list转map、list字段提取

开发记录:关于Java Stream,涉及遍历、分组以及list转map、list字段提取

简介和特点

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?

Stream(流)是一个来自数据源的元素队列并支持聚合操作

  • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
  • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等
  • 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

常见的方法

  • 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 departmentList:某指定医院的所有科室列表

使用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中,提取E的某个字段属性值,并形成新的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中。

posted @ 2022-02-24 15:53  Komorebi_WH  阅读(1437)  评论(0编辑  收藏  举报