1. 程式人生 > 實用技巧 >Version 0.01:使用 linux API (epoll) 實現一個 echo toy.

Version 0.01:使用 linux API (epoll) 實現一個 echo toy.

需求

  專案中經常會遇到折線圖等隨日期、月份變化的趨勢圖,但有時會出現日期不連續的情況,圖表就會有中斷,需要在後臺將日期資料補全,sql或者程式裡都可以處理。
  而Java8提供的無限流,可以更方便的實現補全日期的操作,因為日期是連續遞增的,看似無限序列。

無限流的基礎用法

原始資料

  自2020-11-27 過去一週的資料

demo

  沒有的日期資料,預設補0

Controller

/**
 * 折線圖資料
 *
 * @param preDate 開始日期,不傳預設近一週
 * @return
 */
@GetMapping("chart")
public List<DailyDataChartVo> getChartData(@RequestParam(value = "date", required = false)
                                           @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate preDate) {
    return this.dailyDataService.getChartData(preDate);
}

Service

/**
 * 折線圖資料
 *
 * @param preDate 開始日期,不傳預設近一週
 * @return
 */
public List<DailyDataChartVo> getChartData(LocalDate preDate) {
    if (Objects.isNull(preDate)) {
        preDate = LocalDate.now().minusWeeks(1);
    }
    LocalDate endDate = LocalDate.now();
    List<DailyDataChartVo> list = this.dailyDataMapper.selectChartData(preDate, endDate);
    return this.completeData(preDate, endDate, list);
}

/**
 * 補全資料
 *
 * @param preDate 開始日期
 * @param endDate 截止日期
 * @param oldList 未補全的列表
 * @return 補全後的列表
 */
private List<DailyDataChartVo> completeData(LocalDate preDate, LocalDate endDate, List<DailyDataChartVo> oldList) {
    List<DailyDataChartVo> newList = new ArrayList<>();
    if (CollectionUtils.isEmpty(oldList)) {
        return newList;
    }
    //間隔的日期列表
    List<LocalDate> dates = this.getRangeDays(preDate, endDate);
    Map<LocalDate, DailyDataChartVo> map = oldList.stream()
            .collect(Collectors.toMap(DailyDataChartVo::getDate, Function.identity()));
    dates.forEach(c -> {
        if (map.containsKey(c)) {
            newList.add(map.get(c));
        } else {
            //沒有這一天的資料,預設補0
            newList.add(new DailyDataChartVo(c, BigDecimal.ZERO));
        }
    });
    return newList;
}

/**
 * 獲取間隔的日期列表
 *
 * @param preDate 開始日期
 * @param endDate 截止日期
 * @return
 */
private List<LocalDate> getRangeDays(LocalDate preDate, LocalDate endDate) {
    List<LocalDate> dates = new ArrayList<>();
    //間隔的天數
    long betweenDays = ChronoUnit.DAYS.between(preDate, endDate);
    if (betweenDays < 1) {
        //開始日期<=截止日期
        return dates;
    }
    //建立一個從開始日期、每次加一天的無限流,限制到截止日期為止
    Stream.iterate(preDate, c -> c.plusDays(1))
            .limit(betweenDays + 1)
            .forEach(dates::add);
    return dates;
}

補全後的資料

[
    {
        "date": "2020-11-20",
        "revenue": 22.88
    },
    {
        "date": "2020-11-21",
        "revenue": 93.06
    },
    {
        "date": "2020-11-22",
        "revenue": 0
    },
    {
        "date": "2020-11-23",
        "revenue": 7.99
    },
    {
        "date": "2020-11-24",
        "revenue": 0
    },
    {
        "date": "2020-11-25",
        "revenue": 50.98
    },
    {
        "date": "2020-11-26",
        "revenue": 0
    },
    {
        "date": "2020-11-27",
        "revenue": 0
    }
]

核心方法

Stream.iterate():接收一個初始元素seed,生成從seed到f的迭代流

/**
 * @param seed 初始元素
 * @param f UnaryOperator,函式式介面,接收T型別引數,呼叫apply後返回T本身,應用於上一個元素以產生新元素
 */
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {}

//建立一個從開始日期、每次加一天的無限流,限制到截止日期為止
Stream.iterate(preDate, c -> c.plusDays(1))
        .limit(betweenDays + 1)
        .forEach(dates::add);

  利用無限流,得到連續的日期list,遍歷,有該日的資料直接填充,沒有預設補0。