開發記錄:關於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中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM