1.遍歷/匹配(foreach/find/match)
Stream也是支持類似集合的遍歷和匹配元素的,只是Stream中的元素是以Optional型別存在的,Stream的遍歷、匹配非常簡單,
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 7, 8, 9, 0, 100);
// find使用,查找第一個元素
Optional<Integer> first = list.stream().findFirst();
log.info(first.get().toString());
// match使用,判斷是否存在某個值
boolean b1 = list.stream().anyMatch(value -> value >= 100);
boolean b2 = list.stream().anyMatch(value -> value > 10);
log.info(String.valueOf(b1));
log.info(String.valueOf(b2));
// foreach使用,遍歷輸出元素
list.stream().filter(value -> value > 4).forEach(System.out::print);
System.out.println();
list.forEach(System.out::print);
2.篩選(filter)
篩選,是按照一定的規則校驗流中的元素,將符合條件的元素提取到新的流中的操作,
// 數字篩選
List<Integer> list = Arrays.asList(1, 3, 4, 5, 6, 7, 8, 9, 10, 20);
ArrayList<Integer> arrayList1 = new ArrayList<>();
list.stream().filter(value -> value > 4).forEach(value -> arrayList1.add(value));
log.info(arrayList1.toString());
ArrayList<Integer> arrayList2 = new ArrayList<>();
list.stream().filter(value -> value <= 4).forEach(arrayList2::add);
log.info(arrayList2.toString());
// 物件篩選
List<User> userList1 = Arrays.asList(
new User(1, "xw", "男"),
new User(2, "zgx", "男"),
new User(3, "gg", "男"),
new User(4, "whb", "男"),
new User(5, "yda", "男"),
new User(6, "bhm", "女")
);
List<User> userList2 = new ArrayList<>();
userList1.stream().filter(user -> user.getId() > 2).forEach(userList2::add);
log.info(userList2.toString());
userList1.stream().filter(user -> user.getName().equals("xw")).forEach(System.out::println);
HashMap<String, Optional<User>> userHashMap = new HashMap<>();
Optional<User> man = userList1.stream().filter(user -> user.getSex().equals("男")).findFirst();
userHashMap.put("man", man);
log.info(userHashMap.toString());
3.聚合(max/min/count)
max、min、count這些字眼你一定不陌生,沒錯,在mysql中我們常用它們進行資料統計,Java stream中也引入了這些概念和用法,極大地方便了我們對集合、陣列的資料統計作業,
max、min、count
// max & min & count
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 89, 9, 0, 10, 20, 30);
Optional<Integer> max = list.stream()
.max(Comparator.comparing(Integer::intValue));
log.info(String.format("最大值是:%d", max.get()));
Optional<Integer> min = list.stream()
.min(Comparator.comparing(value -> value.intValue()));
log.info(String.format("最小值是:%d", min.get()));
Integer count1 = Math.toIntExact(list.stream().count());
log.info(String.format("list總元素量1為:%d", count1));
Integer count2 = Math.toIntExact(list.stream().filter(value -> value > 5).count());
log.info(String.format("list元素值大于5的個數:%d", count2));
List<User> userList = Arrays.asList(
new User(1, "xw", "男", 22),
new User(2, "zgx", "男", 22),
new User(3, "whb", "男", 23),
new User(4, "gg", "男", 30),
new User(5, "yda", "男", 22),
new User(6, "bhm", "女", 22),
new User(7, "lwn", "女", 22)
);
Optional<User> ageMax = userList.stream().max(Comparator.comparing(value -> value.getAge()));
log.info(String.format("年齡最大的是:%s", ageMax.get()));
Optional<User> ageMin = userList.stream().filter(user -> user.getSex().equals("男")).min(Comparator.comparing(User::getAge));
log.info(String.format("性別為男且年齡最小的:%s", ageMin.get()));
Integer count3 = Math.toIntExact(userList.stream().filter(user -> user.getAge() > 22).count());
log.info(String.format("年齡大于22的用戶數量為:%d", count3));
4.映射(map/flatMap)
映射,可以將一個流的元素按照一定的映射規則映射到另一個流中,分為map和flatMap:
map:接收一個函式作為引數,該函式會被應用到每個元素上,并將其映射成一個新的元素,flatMap:接收一個函式作為引數,將流中的每個值都換成另一個流,然后把所有流連接成一個流,
map
// map
List<Integer> list1 = Arrays.asList(1, 3, 5, 6, 7, 8, 0, 10, 20, 22, 39);
List<Integer> collect1 = list1.stream().filter(value -> value > 7).collect(Collectors.toList());
log.info(String.format("list1元素值大于7的有: %s", collect1));
List<String> list2 = Arrays.asList("xw", "sjdk", "sf", "jk", "hoksh", "shdfj", "jhgkj");
List<String> collect2 = list2.stream().map(String::toUpperCase).collect(Collectors.toList());
log.info(String.format("list2元素值全轉大寫,結果:%s", collect2));
List<User> userList1 = Arrays.asList(
new User(1, "xw", "男", 22),
new User(2, "zgx", "男", 22),
new User(3, "whb", "男", 23),
new User(4, "gg", "男", 30),
new User(5, "yda", "男", 22),
new User(6, "bhm", "女", 22),
new User(7, "lwn", "女", 22),
new User(8, "ksj", "女", 22)
);
List<User> userList2 = userList1.stream()
.map(user -> {
if (user.getSex().equals("女")) {
user.setAge(user.getAge() - 2);
}
user.setName(user.getName().toUpperCase());
return user;
})
.filter(user -> user.getAge() > 19 && user.getSex().equals("女"))
.collect(Collectors.toList());
log.info(String.format("修改結果為:%s", userList2));
flatMap
// flatMap
List<String> stringList = userList1.stream()
.flatMap(user -> {
Stream<String> stream = Arrays.stream(user.toString().split("="));
return stream;
})
.collect(Collectors.toList());
log.info(String.format("flatMap處理前:%s", userList1));
log.info(String.format("flatMap轉換結果:%s", stringList));
5.歸約(reduce)
歸約,也稱縮減,顧名思義,是把一個流縮減成一個值,能實作對集合求和、求乘積和求最值操作,
// 求和
List<Integer> list1 = Arrays.asList(1, 3, 5, 2, 1, 5, 89, 23, 89, 23, 34);
Integer sum = list1.stream().reduce(0, Integer::sum);
log.info(String.format("list1中各元素之和:%d", sum));
// 求積
List<Integer> list2 = Arrays.asList(1, 2, 4);
Optional<Integer> product = list2.stream().reduce((x, y) -> x * y);
log.info(String.format("list中2各元素之積:%d", product.get()));
// 求最大值1
Optional<Integer> max1 = list1.stream().reduce(Integer::max);
log.info(String.format("list1中的最大值是:%d", max1.get()));
// 求最大/小值2
Optional<Integer> min1 = list1.stream().reduce((x, y) -> x < y ? x : y);
log.info(String.format("list1中的最小值:%d", min1.get()));
List<User> userList1 = Arrays.asList(
new User(1, "xw", "男", 22),
new User(2, "zgx", "男", 22),
new User(3, "whb", "男", 23),
new User(4, "gg", "男", 30),
new User(5, "yda", "男", 22),
new User(6, "bhm", "女", 23),
new User(7, "lsn", "女", 22),
new User(8, "ksj", "女", 22)
);
Integer maxAge1 = userList1.stream().reduce(0, (maxAge, user) -> maxAge > user.getAge() ? maxAge : user.getAge(), Integer::max);
log.info(String.format("年齡最大是:%d", maxAge1));
Optional<Integer> max2 = userList1.stream().map(User::getAge).reduce(Integer::max);
Optional<Integer> max3 = userList1.stream().map(User::getAge).reduce((x, y) -> x > y ? x : y);
log.info(String.format("年齡最大是:%d", max2.get()));
log.info(String.format("年齡最大是:%d", max3.get()));
Integer stringMaxLength = userList1.stream()
.filter(user -> user.getAge() > 22 && user.getAge() < 25)
.flatMap(user -> {
Stream<String> newStream = Arrays.stream(user.toString().split("="));
return newStream;
})
.collect(Collectors.toList())
.stream().map(String::toUpperCase)
.reduce(0, (maxLength, string) -> maxLength > string.length() ? maxLength : string.length(), Integer::max);
log.info(String.format("最大字串長度為:%s", stringMaxLength));
6.收集(collect)
collect,收集,可以說是內容最繁多、功能最豐富的部分了,從字面上去理解,就是把一個流收集起來,最終可以是收集成一個值也可以收集成一個新的集合,
collect主要依賴java.util.stream.Collectors類內置的靜態方法,
6.1歸集(toList/toSet/toMap)
因為流不存盤資料,那么在流中的資料完成處理后,需要將流中的資料重新歸集到新的集合里,toList、toSet和toMap比較常用,另外還有toCollection、toConcurrentMap等復雜一些的用法,
toList
List<Integer> list1 = Arrays.asList(1, 2, 8, 0, 9, 0, 1, 23, 32, 37, 49, 48);
List<Integer> collect1 = list1.stream().filter(value -> value > 5).collect(Collectors.toList());
log.info(String.format("list1中收集>5的結果為:%s", collect1));
toSet
Set<Integer> collect2 = list1.stream().filter(value -> value < 5).collect(Collectors.toSet());
log.info(String.format("list1中收集<5的結果為:%s", collect2));
collect2.forEach(value -> {System.out.print(value + " ");
toMap
List<User> userList1 = Arrays.asList(
new User(1, "xww", "男", 22),
new User(2, "zgx", "男", 22),
new User(3, "whb", "男", 23),
new User(4, "gg", "男", 30),
new User(5, "yda", "男", 22),
new User(6, "bhm", "女", 23),
new User(7, "lsn", "女", 22),
new User(8, "ksj", "女", 22)
);
Map<String, User> userMap = userList1.stream()
.filter(user -> user.getSex().equals("女"))
.collect(Collectors.toMap(User::getName, user -> user));
log.info(String.format("性別為女的用戶轉map:%s", userMap));
6.2 統計(count/averaging)
Collectors提供了一系列用于資料統計的靜態方法:
- 計數:
count - 平均值:
averagingInt、averagingLong、averagingDouble - 最值:
maxBy、minBy - 求和:
summingInt、summingLong、summingDouble - 統計以上所有:
summarizingInt、summarizingLong、summarizingDouble
List<Integer> list = Arrays.asList(1, 2, 3, 2, 5, 3, 9, 8, 7, 6, 29, 10, 22);
// count
long count = list.stream().filter(value -> value > 10).count();
log.info(String.format("list中元素>10的個數為:%d", count));
// average
Double average = list.stream().filter(value -> value > 1).collect(Collectors.averagingInt(Integer::intValue));
log.info(String.format("list中元素>1的元素平均值為:%.2f", average));
List<User> userList1 = Arrays.asList(
new User(1, "xww", "女", 22),
new User(2, "zgx", "男", 22),
new User(3, "whb", "男", 23),
new User(4, "gg", "男", 30),
new User(5, "yda", "男", 22),
new User(6, "bhm", "女", 23),
new User(7, "lsn", "女", 22),
new User(8, "ksj", "女", 22)
);
Double averageAge = userList1.stream()
.filter(user -> user.getSex().equals("男"))
.map(User::getAge)
.collect(Collectors.averagingInt(Integer::intValue));
log.info(String.format("男用戶的平均年齡為:%d 歲", averageAge.intValue()));
// mapToInt
int ageSum = userList1.stream()
.filter(user -> user.getSex().equals("女"))
.mapToInt(User::getAge)
.sum();
log.info(String.format("女用戶的年齡之和為:%d", ageSum));
// summarizingInt 統計 計數、總和、最小值、平均值、最大值
IntSummaryStatistics recording = userList1.stream()
.filter(user -> user.getSex().equals("男"))
.collect(Collectors.summarizingInt(User::getAge));
log.info(String.format("記錄所有男用戶的年齡各項值,結果為:%s", recording));
6.3 分組(partitioningBy/groupingBy)
- 磁區:將
stream按條件分為兩個Map,比如員工按薪資是否高于8000分為兩部分, - 分組:將集合分為多個Map,比如員工按性別分組,有單級分組和多級分組,
partitioningBy
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 20, 37, 49, 243, 30);
// partitioningBy
Map<Boolean, List<Integer>> collect1 = list.stream()
.collect(Collectors.partitioningBy(value -> value > 20));
log.info(String.format("元素值是否大于20進行分組,結果為:%s", collect1));
collect1.forEach((key, value) -> {
log.info(String.format("元素值是否大于20進行分組,結果為:%s:%s", key, value));
});
groupingBy
List<User> userList = Arrays.asList(
new User(1, "xww", "女", 22),
new User(2, "zgx", "男", 21),
new User(3, "whb", "男", 23),
new User(4, "gg", "男", 30),
new User(5, "yda", "男", 22),
new User(6, "bhm", "女", 23),
new User(7, "lsn", "女", 22),
new User(8, "ksj", "女", 22)
);
// groupingBy
Map<String, List<User>> collect2 = userList.stream()
.collect(Collectors.groupingBy(User::getSex));
log.info(String.format("根據性別對用戶進行分組,結果為:%s", collect2));
collect2.forEach((key, user) -> {
log.info(String.format("根據性別對用戶進行分組,結果為:%s:%s", key, user));
});
6.4 接合(joining)
joining可以將stream中的元素用特定的連接符(沒有的話,則直接連接)連接成一個字串,
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 20, 37, 49, 243, 30);
String collect = list.stream()
.map(Object::toString)
.collect(Collectors.joining("——"));
log.info(String.format("joining測驗結果為:%s", collect));
7.排序(sorted)
sorted,中間操作,有兩種排序:
- sorted():自然排序,流中元素需實作Comparable介面
- sorted(Comparator com):Comparator排序器自定義排序
List<User> userList1 = Arrays.asList(
new User(1, "xw", "女", 22),
new User(2, "zgx", "男", 21),
new User(3, "whb", "男", 23),
new User(4, "gg", "男", 30),
new User(5, "yda", "男", 22),
new User(6, "bhm", "女", 23),
new User(7, "lsn", "女", 22),
new User(8, "ksj", "女", 22)
);
// sorted
List<User> userList2 = userList1.stream()
.sorted(Comparator.comparing(User::getAge))
.collect(Collectors.toList());
log.info(String.format("按照年齡排序,結果為:%s", userList2));
// 從小到大,正序
List<String> userName1 = userList1.stream()
.sorted(Comparator.comparing(User::getAge))
.map(User::getName)
.collect(Collectors.toList());
log.info(String.format("根據年齡從小到大排序:%s", userName1));
// 從大到小,倒序
List<String> userName2 = userList1.stream()
.filter(user -> user.getSex().equals("男"))
.sorted(Comparator.comparing(User::getAge).reversed())
.map(User::getName)
.collect(Collectors.toList());
log.info(String.format("男用戶根據年齡從大到小排序:%s", userName2));
8.提取/組合
流也可以進行合并、去重、限制、跳過等操作,
1.去重排序
List<Integer> list = Arrays.asList(1, 2, 4, 4, 10, 9, 6, 8, 6, 2, 3, 7, 5);
List<Integer> collect = list
.stream()
.distinct()
.sorted(Comparator.comparing(Integer::intValue))
.collect(Collectors.toList());
collect.forEach(x -> System.out.print(x+" ")); // 1 2 3 4 5 6 7 8 9 10
存在重復資料的問題,這里使用stream流的衍生功能,去除一個物件中的部分元素的重復如下:
List<User> userList = Arrays.asList(
new User(1, "xw", "女", 21),
new User(2, "zgx", "男", 21),
new User(3, "whb", "男", 23),
new User(4, "gag", "男", 30),
new User(4, "gbg", "男", 30),
new User(4, "gcg", "女", 30),
new User(5, "yda", "男", 22),
new User(6, "bhm", "女", 23),
new User(7, "lsn", "女", 22),
new User(8, "ksj", "女", 22)
);
ArrayList<User> collect1 = userList.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(
Comparator.comparing(
User::getId))), ArrayList::new));
多個欄位或者多個條件去重
ArrayList<User> collect2 = userList.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(
Comparator.comparing(user->user.getName() + ";" + user.getId()))), ArrayList::new)
以上使用到了collectingAndThen()根據屬性進行去重的操作,進行結果集的收集,收集到結果集之后再進行下一步的處理,在這個去重操作中還用到了toCollection、TreeSet兩個操作,
public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,Function<R,RR> finisher)看原始碼中需要傳的引數有兩個,第一個引數是Collector的子類,所以Collectors類中的大多數方法都能使用,比如:toList(),toSet(),toMap()等,當然也包括collectingAndThen(),第二個引數是一個Function函式,也是去重的關鍵,用到的ArrayList::new呼叫到了ArrayList的有參構造,Function函式是R apply(T t),在第一個引數downstream放在第二個引數Function函式的引數里面,將結果設定為t,對于toCollection是一個通用的方法,滿足treeSet收集集合,再傳入需要根據某個屬性進行比較的比較器,就能達到去重的效果,
2.限制長度(limit)
List<Integer> list = Arrays.asList(1, 2, 7, 3, 2, 2, 3, 4, 5, 2, 5, 6, 7, 8, 9, 0, 12);
List<Integer> collect1 = list
.stream()
.distinct()
.sorted(Comparator.comparing(Integer::intValue))
.limit(6)
.collect(Collectors.toList());
collect1.forEach(x -> System.out.print(x + " "));
3.跳過(skip)
// 跳過前幾項
List<Integer> list = Arrays.asList(1, 2, 7, 3, 2, 2, 3, 4, 5, 2, 5, 6, 7, 8, 9, 0, 12);
List<Integer> collect2 = list
.stream()
.distinct()
.sorted(Comparator.comparing(Integer::intValue))
.skip(3)
.limit(6)
.collect(Collectors.toList());
collect2.forEach(x -> System.out.print(x + " "));
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/524911.html
標籤:其他
