一. Stream API
1.1 基礎
代碼參數(shù)準備:
package com.weige.javaskillpoint.controller;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
public class JAVA8 {
@Data
static class User {
// 姓名
private String name;
// 手機號
private String phone;
// 年齡
private Integer age;
public User(String name, String phone, Integer age) {
this.name = name;
this.phone = phone;
this.age = age;
}
}
private static List<User> getUserList() {
return new ArrayList<User>() {{
add(new User("周潤發(fā)", "166", 52));
add(new User("周星馳", "155", 42));
add(new User("劉德華", "177", 62));
add(new User("伍佰", "188", 45));
add(new User("周傳雄", "133", 40));
add(new User("甄子丹", "199", 45));
}};
}
}
場景一:知道一個List<User>對象,如何獲取List<User>的所有用戶id?
public static void main(String[] args) {
// 知道一個List<User>對象,如何獲取List<User>的所有用戶手機號?
List<User> userList = getUserList();
List<String> phoneList = userList.stream().map(User::getPhone).collect(Collectors.toList());
// 打印內(nèi)容 - 所有用戶手機號為 [166, 155, 177, 188, 133, 199]
log.info("所有用戶手機號為 " + phoneList);
}
場景二:知道一個List<User>對象,如何獲取List<User>中年齡大于50的用戶?
public static void main(String[] args) {
// 知道一個List<User>對象,如何獲取List<User>中年齡大于50的用戶?
List<User> userList = getUserList();
List<User> filterUserList = userList.stream().filter(u -> u.getAge() > 50).collect(Collectors.toList());
// 打印內(nèi)容 - 年齡大于50的用戶為 [JAVA8.User(name=周潤發(fā), phone=166, age=52), JAVA8.User(name=劉德華, phone=177, age=62)]
log.info("年齡大于50的用戶為 " + filterUserList);
}
場景三:知道一個List<User>對象,如何按照年齡從小到小排序,從大到小排序?
public static void main(String[] args) {
// 知道一個List<User>對象,如何按照年齡從大到小排序?
List<User> userList = getUserList();
List<User> ascUserList = userList.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList());
List<User> reversedUserList = userList.stream().sorted(Comparator.comparing(User::getAge).reversed()).collect(Collectors.toList());
// 打印內(nèi)容 - 年齡從小到大 [JAVA8.User(name=周傳雄, phone=133, age=40), JAVA8.User(name=周星馳, phone=155, age=42), JAVA8.User(name=伍佰, phone=188, age=45), JAVA8.User(name=甄子丹, phone=199, age=45), JAVA8.User(name=周潤發(fā), phone=166, age=52), JAVA8.User(name=劉德華, phone=177, age=62)]
log.info("年齡從小到大 " + ascUserList);
// 打印內(nèi)容 - 年齡從大到小 [JAVA8.User(name=劉德華, phone=177, age=62), JAVA8.User(name=周潤發(fā), phone=166, age=52), JAVA8.User(name=伍佰, phone=188, age=45), JAVA8.User(name=甄子丹, phone=199, age=45), JAVA8.User(name=周星馳, phone=155, age=42), JAVA8.User(name=周傳雄, phone=133, age=40)]
log.info("年齡從大到小 " + reversedUserList);
}
場景四:知道一個List<User>對象,如何按照相同年齡進行分組,并獲取分組后的數(shù)量?
public static void main(String[] args) {
// 知道一個List<User>對象,如何按照相同年齡進行分組?
List<User> userList = getUserList();
Map<Integer, List<User>> groupingUserList = userList.stream().collect(Collectors.groupingBy(User::getAge));
// 打印內(nèi)容 - 相同年齡進行分組 {52=[JAVA8.User(name=周潤發(fā), phone=166, age=52)], 40=[JAVA8.User(name=周傳雄, phone=133, age=40)], 42=[JAVA8.User(name=周星馳, phone=155, age=42)], 45=[JAVA8.User(name=伍佰, phone=188, age=45), JAVA8.User(name=甄子丹, phone=199, age=45)], 62=[JAVA8.User(name=劉德華, phone=177, age=62)]}
log.info("相同年齡進行分組 " + groupingUserList);
// 知道一個List<User>對象,如何按照相同年齡進行分組后獲取其對應數(shù)量?
Map<Integer, Long> countUserList = userList.stream().collect(Collectors.groupingBy(User::getAge, Collectors.counting()));
// 打印內(nèi)容 - 相同年齡進行分組的數(shù)量 {52=1, 40=1, 42=1, 45=2, 62=1}
log.info("相同年齡進行分組的數(shù)量 " + countUserList);
}
1.2 進階
場景一:有一張用戶瀏覽記錄表,一個用戶可以有多條瀏覽記錄,且有不同的瀏覽類型;比如小明瀏覽娛樂模塊530秒,瀏覽軍事模塊600秒,則對應兩個瀏覽記錄數(shù)據(jù)。新建用戶瀏覽類型統(tǒng)計表,根據(jù)現(xiàn)有的用戶瀏覽記錄表數(shù)據(jù)對用戶瀏覽類型統(tǒng)計表進行新增,請用Stream優(yōu)雅的實現(xiàn)該功能?
package com.weige.javaskillpoint.controller;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
public class JAVA8 {
@Data
static class History {
// 用戶id
private Long userId;
// 用戶瀏覽類型 (1->娛樂 2->軍事 3->教育)
private Integer type;
// 用戶瀏覽時間(單位秒)
private Long seconds;
public History(Long userId, Integer type, Long seconds) {
this.userId = userId;
this.type = type;
this.seconds = seconds;
}
}
@Data
static class HistoryStatistics {
// 用戶id
private Long userId;
// 用戶瀏覽類型 (1->娛樂 2->軍事 3->教育)
private Integer type;
// 瀏覽類型統(tǒng)計數(shù)量
private Long count;
public HistoryStatistics(Long userId, Integer type, Long count) {
this.userId = userId;
this.type = type;
this.count = count;
}
}
public static void main(String[] args) {
// 模擬用戶瀏覽記錄數(shù)據(jù)
List<History> historyList = new ArrayList<History>() {
{
add(new History(20231L, 1, 360L));
add(new History(20231L, 1, 720L));
add(new History(20231L, 2, 1360L));
add(new History(20231L, 2, 2360L));
add(new History(20239L, 2, 2360L));
add(new History(20239L, 3, 360L));
add(new History(20233L, 3, 360L));
}
};
List<HistoryStatistics> insertHistoryStatisticsList = new ArrayList<>();
// 根據(jù)用戶id進行分組
Map<Long, List<History>> groupingByUserIdMap = historyList.stream().collect(Collectors.groupingBy(History::getUserId));
groupingByUserIdMap.forEach((key, value) -> {
Map<Integer, Long> countMap = historyList.stream()
// 篩選出對應用戶id的瀏覽記錄
.filter(h -> key.equals(h.getUserId()))
// 對用戶id的瀏覽記錄根據(jù)類型進行分組并獲取數(shù)量
.collect(Collectors.groupingBy(History::getType, Collectors.counting()));
// 將用戶瀏覽記錄類型分組的數(shù)量Map轉(zhuǎn)成List<HistoryStatistics>
List<HistoryStatistics> historyStatisticsList = countMap.entrySet().stream().map(u -> new HistoryStatistics(key, u.getKey(), u.getValue())).collect(Collectors.toList());
insertHistoryStatisticsList.addAll(historyStatisticsList);
});
// 批量新增用戶瀏覽記錄統(tǒng)計表
batchInsertHistoryStatistics(insertHistoryStatisticsList);
}
public static void batchInsertHistoryStatistics(List<HistoryStatistics> insertHistoryStatisticsList) {
log.info("------連接數(shù)據(jù)庫------");
log.info("------開始批量新增數(shù)據(jù)------");
log.info("------批量新增數(shù)據(jù): " + insertHistoryStatisticsList);
log.info("------批量新增數(shù)據(jù)結(jié)束------");
log.info("------關閉數(shù)據(jù)庫連接------");
}
}
場景二:有一張用戶瀏覽記錄表,一個用戶可以有多條瀏覽記錄,且有不同的瀏覽類型;比如小明瀏覽娛樂模塊530秒,瀏覽軍事模塊600秒;小紅瀏覽娛樂模塊1000秒,瀏覽軍事模塊100秒,則對應四條瀏覽記錄數(shù)據(jù)。想要得到每個用戶總共的瀏覽時長,請用Stream優(yōu)雅的實現(xiàn)該功能?
package com.weige.javaskillpoint.controller;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
public class JAVA8 {
@Data
static class History {
// 用戶姓名
private String userName;
// 用戶瀏覽類型 (1->娛樂 2->軍事 3->教育)
private Integer type;
// 用戶瀏覽時間(單位秒)
private Long seconds;
public History(String userName, Integer type, Long seconds) {
this.userName = userName;
this.type = type;
this.seconds = seconds;
}
}
public static void main(String[] args) {
List<History> historyList = new ArrayList<History>() {
{
add(new History("小明", 1, 360L));
add(new History("小明", 1, 720L));
add(new History("小明", 2, 1360L));
add(new History("小明", 2, 2360L));
add(new History("小紅", 2, 2360L));
add(new History("小白", 3, 360L));
add(new History("小紅", 3, 360L));
add(new History("小白", 3, 1060L));
}
};
// 串行流中reduce的第三個參數(shù)combiner無作用 返回值可以寫為null
HashMap<String, Long> reduce = historyList.stream().reduce(new HashMap<>(), (m, e) -> {
m.put(e.getUserName(), m.getOrDefault(e.getUserName(), 0L) + e.getSeconds());
return m;
}, (m1,m2) -> null);
// 返回結(jié)果 - {小明=4800, 小白=1420, 小紅=2720}
log.info("數(shù)據(jù)為: " + reduce);
// 并行流中reduce的第三個參數(shù)combiner有作用 如果返回結(jié)果為map 則應用putAll()來解決并發(fā)情況下數(shù)據(jù)不一致問題 同時返回值應用ConcurrentHashMap接收
ConcurrentHashMap<String, Long> parallelReduce = historyList.stream().parallel().reduce(new ConcurrentHashMap<>(), (m, e) -> {
m.put(e.getUserName(), m.getOrDefault(e.getUserName(), 0L) + e.getSeconds());
return m;
}, (m1,m2) -> {
m1.putAll(m2);
return m1;
});
// 返回結(jié)果 - {小明=4800, 小白=1420, 小紅=2720}
log.info("數(shù)據(jù)為: " + parallelReduce);
// 這里舉個例子:如果reduce第一個參數(shù)為1,則stream執(zhí)行時,分兩個階段;
// 第一個階段分3步:1 + 1 = 2,1 + 2 = 3,1 + 3 = 4;
// 第二個階段 2 * 3 * 4 = 24
List<Integer> intList = new ArrayList<Integer>(){{
add(1);
add(2);
add(3);
}};
Integer sum = intList.stream().parallel().reduce(1, new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) {
return integer + integer2;
}
}, (integer, integer2) -> integer * integer2);
// 返回結(jié)果 - 并行流中用第三個參數(shù)(類似于函數(shù)表達式對參數(shù)進行乘法操作): 24
log.info("并行流中用第三個參數(shù)(類似于函數(shù)表達式對參數(shù)進行乘法操作): " + sum);
Integer multipliers = intList.stream().parallel().reduce(1, new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) {
return integer + integer2;
}
});
// 返回結(jié)果 - 并行流中第三個參數(shù)返回自己本身,不進行任何操作: 9
log.info("并行流中第三個參數(shù)返回自己本身,不進行任何操作: " + multipliers);
Integer num = intList.stream().reduce(1,Integer::sum);
// 返回結(jié)果 - 串行流不使用第三個參數(shù) 7
log.info("串行流不使用第三個參數(shù) " + num);
}
}
二. LocalDate,LocalDateTime
2.1 基礎
一般前端傳給后端的時間參數(shù),都是字符串拼接,比如"2023-07-19","2023 -07-19 20:00:00",這都是字符串;而查詢數(shù)據(jù)庫時,是需要根據(jù)Date時間類型來查詢,所以這里需要將字符串轉(zhuǎn)成Date,如果中間需要操作時間(年,月,日,時,分加減)
LocalDate
public static void main(String[] args) {
// 模擬前端傳過來的時間參數(shù)
String dateString = "2023-07-19";
// 將字符串轉(zhuǎn)成LocalDateTime 這里看前端傳的時間格式 ofPattern里面對應時間格式 不然會報錯
// 2023-07-19 -> yyyy-MM-dd
// LocalDate只能操作年 月 日
LocalDate localDate = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
// 減1年
LocalDate minusYears = localDate.minusYears(1);
// 加1年
LocalDate plusYears = localDate.plusYears(1);
// 減1月
LocalDate minusMonths = localDate.minusMonths(1);
// 加1月
LocalDate plusMonths = localDate.plusMonths(1);
// 減1日
LocalDate minusDays = localDate.minusDays(1);
// 加1日
LocalDate plusDays = localDate.plusDays(1);
// 通過LocalDate操作時間參數(shù)得到自己想要的結(jié)果時 轉(zhuǎn)換成Date類型查詢數(shù)據(jù)庫
// LocalDate轉(zhuǎn)Date
Date date = localDateTurnDate(minusYears);
getListByDate(date);
System.out.println(date);
}
public static Date localDateTurnDate(LocalDate localDate) {
ZoneId zone = ZoneId.systemDefault();
Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
return Date.from(instant);
}
public static void getListByDate(Date date) {
// 模擬查詢結(jié)果
ArrayList<String> arrayList = new ArrayList<String>() {{
add("一輩子");
add("下輩子");
}};
System.out.println("根據(jù)時間" + date + "查詢結(jié)果為 : " + arrayList);
}
LocalDateTime
public static void main(String[] args) {
// 模擬前端傳過來的時間參數(shù)
String dateString = "2023-07-19 20:20:20";
// 將字符串轉(zhuǎn)成LocalDateTime 這里看前端傳的時間格式 ofPattern里面對應時間格式 不然會報錯
// 2023-07-19 20:20:20 -> yyyy-MM-dd HH:mm:ss
// 2023-07-19 20:20 -> yyyy-MM-dd HH:mm
// 2023-07-19 -> yyyy-MM-dd
LocalDateTime localDateTime = LocalDateTime.parse(dateString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
// 減1年
LocalDateTime minusYears = localDateTime.minusYears(1);
// 加1年
LocalDateTime plusYears = localDateTime.plusYears(1);
// 減1月
LocalDateTime minusMonths = localDateTime.minusMonths(1);
// 加1月
LocalDateTime plusMonths = localDateTime.plusMonths(1);
// 減1日
LocalDateTime minusDays = localDateTime.minusDays(1);
// 加1日
LocalDateTime plusDays = localDateTime.plusDays(1);
// 減1小時
LocalDateTime minusHours = localDateTime.minusHours(1);
// 加1小時
LocalDateTime plusHours = localDateTime.plusHours(1);
// 通過LocalDateTime操作時間參數(shù)得到自己想要的結(jié)果時 轉(zhuǎn)換成Date類型查詢數(shù)據(jù)庫
// LocalDateTime轉(zhuǎn)Date
Date date = localDateTimeTurnDate(minusYears);
getListByDate(date);
System.out.println(date);
}
public static Date localDateTimeTurnDate(LocalDateTime localDateTime) {
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
return Date.from(instant);
}
public static void getListByDate(Date date) {
// 模擬查詢結(jié)果
ArrayList<String> arrayList = new ArrayList<String>() {{
add("一輩子");
add("下輩子");
}};
System.out.println("根據(jù)時間" + date + "查詢結(jié)果為 : " + arrayList);
}
2.2?進階
對時間參數(shù)進行比較
通過當前時間,查詢前6個小時數(shù)據(jù)庫的數(shù)據(jù)
public static void main(String[] args) {
// 近6個小時
String format = DateUtils.format(new Date(), "yyyy-MM-dd HH");
LocalDateTime now = LocalDateTime.parse(format, DateTimeFormatter.ofPattern("yyyy-MM-dd HH"));
for (LocalDateTime currentdate = now.minusHours(5); currentdate.isBefore(now) || currentdate.isEqual(now); currentdate = currentdate.plusHours(1)) {
Date date = localDateTimeTurnDate(currentdate);
getListByDate(date);
}
}
public static Date localDateTimeTurnDate(LocalDateTime localDateTime) {
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
return Date.from(instant);
}
public static void getListByDate(Date date) {
// 模擬查詢結(jié)果
ArrayList<String> arrayList = new ArrayList<String>() {{
add("一輩子");
add("下輩子");
}};
System.out.println("根據(jù)時間" + date + "查詢結(jié)果為 : " + arrayList);
}
通過當前時間,查詢近7天數(shù)據(jù)庫的數(shù)據(jù)
public static void main(String[] args) {
// 近7天
String format = DateUtils.format(new Date(), "yyyy-MM-dd");
LocalDateTime now = LocalDate.parse(format, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();
for (LocalDateTime currentdate = now.minusDays(6); currentdate.isBefore(now) || currentdate.isEqual(now); currentdate = currentdate.plusDays(1)) {
Date date = localDateTimeTurnDate(currentdate);
getListByDate(date);
}
}
public static Date localDateTimeTurnDate(LocalDateTime localDateTime) {
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
return Date.from(instant);
}
public static void getListByDate(Date date) {
// 模擬查詢結(jié)果
ArrayList<String> arrayList = new ArrayList<String>() {{
add("一輩子");
add("下輩子");
}};
System.out.println("根據(jù)時間" + date + "查詢結(jié)果為 : " + arrayList);
}
文章來源地址http://www.zghlxwxcb.cn/news/detail-585942.html
文章來源:http://www.zghlxwxcb.cn/news/detail-585942.html
到了這里,關于JAVA8新特性(Stream API,LocalDate,LocalDateTime)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!