Version 0.01:使用 linux API (epoll) 實現一個 echo toy.
阿新 • • 發佈:2020-11-27
需求
專案中經常會遇到折線圖等隨日期、月份變化的趨勢圖,但有時會出現日期不連續的情況,圖表就會有中斷,需要在後臺將日期資料補全,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。