??我親愛的各位大佬們好??????
??本篇文章記錄的為 JDK8 新特性 Stream API 進(jìn)階 相關(guān)內(nèi)容,適合在學(xué)Java的小白,幫助新手快速上手,也適合復(fù)習(xí)中,面試中的大佬??????。
??如果文章有什么需要改進(jìn)的地方還請大佬不吝賜教??????
????? 個人主頁 : 阿千弟
?? 相關(guān)內(nèi)容?????? : 都2023年了,如果不會Lambda表達(dá)式、函數(shù)式編程?你確定能看懂公司代碼?
前情回顧 :
最近, 我的一些已經(jīng)入職一段時間的朋友和我說, 在公司中做的最多的業(yè)務(wù)就是crud, 他最近做的項目是一個h5的中移動一個外包項目, 雖然業(yè)務(wù)并不復(fù)雜, 但是呢數(shù)據(jù)量非常龐大, 數(shù)據(jù)庫的表很多, 大概四五百張表, 每天的crud寫的我這哥們也是很煩.??????
所以對于這個問題, 建議哥們可以嘗試使用 JDK8 新特性 Stream的方式來處理數(shù)據(jù), 對于集合, 數(shù)組, map的處理很方便, 也很快速, 這時一些朋友會問, stream閱讀性不好, 難以讀懂, 但是呢你想想別管它咋樣, 能有利于咱們開發(fā)提高咱們的開發(fā)效率就行了唄
為此我專門出來一期關(guān)于JDK8 新特性 Stream API 進(jìn)階使用的文章, 來幫助咱們經(jīng)常寫crud的朋友來簡化開發(fā), 可能你剛開始用的時候很抵觸, 但是你用熟練了會覺得它真的爽.??????希望大家多多支持
1、了解 Stream
? Java8中有兩大最為重要的改變。第一個是 Lambda 表達(dá)式;另外一個則是Stream API(java.util.stream.*)。Stream 是 Java8 中處理集合的關(guān)鍵抽象概念,它可以指定你希望對集合進(jìn)行的操作,可以執(zhí)行非常復(fù)雜的查找、過濾和映射數(shù)據(jù)等操作。使用Stream API 對集合數(shù)據(jù)進(jìn)行操作,就類似于使用 SQL 執(zhí)行的數(shù)據(jù)庫查詢。也可以使用 Stream API 來并行執(zhí)行操作。簡而言之,Stream API 提供了一種高效且易于使用的處理數(shù)據(jù)的方式。
2、什么是 Stream
流(Stream) 到底是什么呢?
是數(shù)據(jù)渠道,用于操作數(shù)據(jù)源(集合、數(shù)組等)所生成的元素序列?!凹现v的是數(shù)據(jù),流講的是計算!”
注意:
- Stream 自己不會存儲元素。
- Stream 不會改變源對象。相反,他們會返回一個持有結(jié)果的新Stream。
- Stream 操作是延遲執(zhí)行的。這意味著他們會等到需要結(jié)果的時候才執(zhí)行。
3、Stream 的操作三個步驟
- 創(chuàng)建 Stream
一個數(shù)據(jù)源(如:集合、數(shù)組),獲取一個流
- 中間操作
一個中間操作鏈,對數(shù)據(jù)源的數(shù)據(jù)進(jìn)行處理
- 終止操作(終端操作)
一個終止操作,執(zhí)行中間操作鏈,并產(chǎn)生結(jié)果
Stream 的中間操作
? 多個中間操作可以連接起來形成一個流水線,除非流水線上觸發(fā)終止操作,否則中間操作不會執(zhí)行任何的處理!而在終止操作時一次性全部處理,稱為“惰性求值”。
1、篩選與切片
方 法 | 描 述 |
---|---|
filter (Predicate p)
|
接收 Lambda , 從流中排除某些元素。 |
distinct() |
篩選,通過流所生成元素的 hashCode() 和 equals() 去除重復(fù)元素 |
limit (long maxSize)
|
截斷流,使其元素不超過給定數(shù)量。 |
skip (long n)
|
跳過元素,返回一個扔掉了前 n 個元素的流。若流中元素不足 n 個,則返回一個空流。與 limit(n) 互補 |
2、映射
方 法 | 描 述 |
---|---|
map (Function f)
|
接收一個函數(shù)作為參數(shù),該函數(shù)會被應(yīng)用到每個元素上,并將其映射成一個新的元素。 |
mapToDouble (ToDoubleFunction f)
|
接收一個函數(shù)作為參數(shù),該函數(shù)會被應(yīng)用到每個元素上,產(chǎn)生一個新的 DoubleStream。 |
mapToInt (ToIntFunction f)
|
接收一個函數(shù)作為參數(shù),該函數(shù)會被應(yīng)用到每個元素上,產(chǎn)生一個新的 IntStream。 |
mapToLong (ToLongFunction f)
|
接收一個函數(shù)作為參數(shù),該函數(shù)會被應(yīng)用到每個元素上,產(chǎn)生一個新的 LongStream。 |
flatMap (Function f)
|
接收一個函數(shù)作為參數(shù),將流中的每個值都換成另一個流,然后把所有流連接成一個流 |
3、排序
方 法 | 描 述 |
---|---|
sorted() |
產(chǎn)生一個新流,其中按自然順序排序 |
sorted (Comparator comp)
|
產(chǎn)生一個新流,其中按比較器順序排序 |
Stream 的終止操作
終端操作會從流的流水線生成結(jié)果。其結(jié)果可以是任何不是流的值,例如:List、Integer,甚至是 void。
1、查找與匹配
方 法 | 描 述 |
---|---|
allMatch (Predicate p)
|
檢查是否匹配所有元素 |
anyMatch (Predicate p)
|
檢查是否至少匹配一個元素 |
noneMatch (Predicate p)
|
檢查是否沒有匹配所有元素 |
findFirst() |
返回第一個元素 |
findAny() |
返回當(dāng)前流中的任意元素 |
count() |
返回流中元素總數(shù) |
max (Comparator c)
|
返回流中最大值 |
min (Comparator c)
|
返回流中最小值 |
forEach (Consumer c)
|
內(nèi)部迭代(使用 Collection 接口需要用戶去做迭代,稱為外部迭代。相反,Stream API 使用內(nèi)部迭代——它幫你把迭代做了) |
2、歸約
方 法 | 描 述 |
---|---|
reduce (T iden, BinaryOperator b)
|
可以將流中元素反復(fù)結(jié)合起來,得到一個值。返回 T |
reduce (BinaryOperator b)
|
可以將流中元素反復(fù)結(jié)合起來,得到一個值。返回 Optional |
3、收集
方 法 | 描 述 |
---|---|
collect (Collector c)
|
將流轉(zhuǎn)換為其他形式。接收一個 Collector接口的實現(xiàn),用于給Stream中元素做匯總的方法 |
? Collector 接口中方法的實現(xiàn)決定了如何對流執(zhí)行收集操作(如收集到 List、Set、Map)。但是 Collectors 實用類提供了很多靜態(tài)方法,可以方便地創(chuàng)建常見收集器實例,具體方法與實例如下表:
方法 | 返回類型 | 作用 | 代碼 |
---|---|---|---|
toList |
List | 把流中元素收集到List | List emps= list.stream().collect(Collectors.toList()); |
toSet |
Set | 把流中元素收集到Set | Set emps= list.stream().collect(Collectors.toSet()); |
toCollection |
Collection | 把流中元素收集到創(chuàng)建的集合 | Collectionemps=list.stream().collect(Collectors.toCollection(ArrayList::new)); |
counting |
Long | 計算流中元素的個數(shù) | long count = list.stream().collect(Collectors.counting()); |
summingInt |
Integer | 對流中元素的整數(shù)屬性求和 | int total=list.stream().collect(Collectors.summingInt(Employee::getSalary)); |
averagingInt |
Double | 計算流中元素Integer屬性的平均值 | double avg= list.stream().collect(Collectors.averagingInt(Employee::getSalary)); |
summarizingInt |
IntSummaryStatistics | 收集流中Integer屬性的和。 | IntSummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary)); |
joining |
String | 連接流中每個字符串 | String str= list.stream().map(Employee::getName).collect(Collectors.joining()); |
maxBy |
Optional | 根據(jù)比較器選擇最大值 | Optionalmax= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary))); |
minBy |
Optional | 根據(jù)比較器選擇最小值 | Optional min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary))); |
reducing |
歸約產(chǎn)生的類型 | 從一個作為累加器的初始值開始,利用BinaryOperator與流中元素逐個結(jié)合,從而歸約成單個值 | int total=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum)); |
collectingAndThen |
轉(zhuǎn)換函數(shù)返回的類型 | 包裹另一個收集器,對其結(jié)果轉(zhuǎn)換函數(shù) | int how= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size)); |
groupingBy |
Map<K, List> | 根據(jù)某屬性值對流分組,屬性為K,結(jié)果為V | Map<Emp.Status, List> map= list.stream().collect(Collectors.groupingBy(Employee::getStatus)); |
partitioningBy |
Map<Boolean, List> | 根據(jù)true或false進(jìn)行分區(qū) | Map<Boolean,List>vd= list.stream().collect(Collectors.partitioningBy(Employee::getManage)); |
下面是工作中經(jīng)常被用到的案例, 請仔細(xì)品味
一些使用場景
1、取出自身重復(fù)的數(shù)據(jù)
@Test
public void test01() {
List<String> list = Arrays.asList(
"g", "k", "f", "k", "g", "b"
);
List<String> li = list.stream().
filter(li1 -> list.stream().filter((li2 -> li2.equals(li1))).count() > 1l)
.collect(toList());
System.out.println(li);
}
2、累加數(shù)字
@Test
public void test12() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(sum);
}
3、字符串?dāng)?shù)字集合與整數(shù)集合互轉(zhuǎn)
@Test
public void test14() {
List<Integer> intList = new ArrayList<>();
intList.add(1);
intList.add(3);
intList.add(4);
List<String> intToStrList = intList.stream().map(String::valueOf).collect(toList());
intToStrList.stream().forEach(str -> {
System.out.println(str);
});
List<String> stringList = new ArrayList<>();
stringList.add("10");
stringList.add("20");
stringList.add("30");
List<String> stringToIntList = stringList.stream().map(String::valueOf).collect(toList());
stringToIntList.stream().forEach(num -> {
System.out.println(num);
});
}
4、取list1與list2的交集
List<String> list1 = Arrays.asList(
"張三", "李四", "李剛", "隋通"
);
List<String> list2 = Arrays.asList(
"熊大", "熊二", "張三", "李剛"
);
//15.取list1與list2的交集
@Test
public void test15() {
List<String> intersection = list1.stream().filter(item -> list2.contains(item)).collect(toList());
System.out.println("---得到交集---");
intersection.parallelStream().forEach(System.out::println);
}
5、取list1與list2的差集
@Test
public void test16() {
List<String> reduce1 = list1.stream().filter(item -> !list2.contains(item)).collect(toList());
System.out.println("---得到差集 reduce1 (list1 - list2)---");
reduce1.parallelStream().forEach(System.out::println);
}
6、取list1和list2的并集
@Test
public void test18() {
List<String> listAll = list1.parallelStream().collect(toList());
List<String> listAll2 = list2.parallelStream().collect(toList());
listAll.addAll(listAll2);
System.out.println("---得到并集 listAll---");
listAll.parallelStream().forEach(System.out::println);
// 去重并集
List<String> listAllDistinct = listAll.stream().distinct().collect(toList());
System.out.println("---得到去重并集 listAllDistinct---");
listAllDistinct.parallelStream().forEach(System.out::println);
System.out.println("---原來的List1---");
list1.parallelStream().forEach(System.out::println);
System.out.println("---原來的List2---");
list2.parallelStream().forEach(System.out::println);
}
7、統(tǒng)計集合重復(fù)元素出現(xiàn)次數(shù),并且去重返回hashmap
List<String> list = Arrays.asList(
"b", "g", "d", "d", "t", "j", "d", "a", "c", "f", "a", "b", "s", "w", "w", "b"
);
//19.統(tǒng)計集合重復(fù)元素出現(xiàn)次數(shù),并且去重返回hashmap
@Test
public void test19() {
Map<String, Long> map = list.stream().
collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
System.out.println(map);
//由于hashmap無序,所以在排序放入LinkedHashMap里(key升序)
Map<String, Long> sortMap = new LinkedHashMap<>();
map.entrySet().stream().sorted(Map.Entry.comparingByKey()).
forEachOrdered(e -> sortMap.put(e.getKey(), e.getValue()));
System.out.println(sortMap);
//獲取排序后map的key集合
List<String> keys = new LinkedList<>();
sortMap.entrySet().stream().forEachOrdered(e -> keys.add(e.getKey()));
System.out.println(keys);
//獲取排序后map的value集合
List<Long> values = new LinkedList<>();
sortMap.entrySet().stream().forEachOrdered(e -> values.add(e.getValue()));
System.out.println(values);
}
8、stream循環(huán)拿到下標(biāo)
@Test
public void test21(){
Stream.iterate(0, i -> i + 1).limit(users01.size()).forEach(index -> {
System.out.println(index);
});
}
9、List集合轉(zhuǎn)Map任意一個屬性作為鍵,鍵相同的對象用集合存儲
@Test
public void test22(){
Map<Integer,List<User>> userMap = new HashMap<>();
List<User> userList = null;
for (int i = 0; i < users02.size(); i++) {
User user = users02.get(i);
if(userMap.get(user.getAge())==null){
userList = new ArrayList<>();
}
userList.add(user);
userMap.put(user.getAge(),userList);
}
for(Integer key : userMap.keySet()){
System.out.println("key:"+key+"\n"+"value:"+userMap.get(key));
}
}
10、List集合轉(zhuǎn)Map任意一個屬性作為鍵,鍵相同的對象用集合存儲(Java8新特性實現(xiàn))
@Test
public void test23(){
Map<Integer, List<User>> listMap = users02.stream().collect(Collectors.groupingBy(User::getAge));
listMap.keySet().forEach(key->{
System.out.println(key);
listMap.get(key).forEach((user)->System.out.println(user));
});
for(Integer key : listMap.keySet()){
System.out.println("key:"+key+"\n"+"value:"+listMap.get(key));
}
}
11、取出users01中age一樣的,并算出有幾項
@Test
public void test03() {
List<User> userList = users01.stream().filter(user1 -> users01.stream().filter((user2 -> user2.getAge().equals(user1.getAge()))).count() > 1l)
.collect(toList());
userList.stream().forEach((user) -> {
System.out.println(user.getName() + ":" + user.getAge());
});
Map<Object, Object> str = new HashMap<>();
for (User user : userList) {
List<User> collect = userList.stream().filter(d -> d.getAge().equals(user.getAge())).collect(toList());
str.put(user.getAge(), collect.size());
}
for (Object key : str.keySet()) {
String value = str.get(key).toString();//
System.out.println("key:" + key + " value:" + value);
}
}
12、取出users01中的Id在users02中沒有的user
/**
* allMatch——檢查是否匹配所有元素
* anyMatch——檢查是否至少匹配一個元素
* noneMatch——檢查是否沒有匹配的元素
*/
//4.取出users01中的Id在users02中沒有的user
@Test
public void test04() {
//取出所有users02的id
List<Integer> user02Ids = users02.stream().map(User::getId).collect(toList());
System.out.println(user02Ids);
List<User> userList = users01.stream().filter(user1 -> !user02Ids.stream().anyMatch(user02Id -> user1.getId().equals(user02Id))).collect(toList());
userList.stream().forEach((user) -> {
System.out.println(user.getName() + ":" + user.getAge());
});
List<SkuEsModel.Attrs> attrList = baseAttrs.stream().filter(item -> {
// 過濾掉不包含在 searchAttrIds集合中的元素
return idSet.contains(item.getAttrId());
}).collect(Collectors.toList());
}
13、去掉users01name重復(fù)的只保留一個
@Test
public void test07() {
List<User> userList = users01.stream().collect(
Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getName()))),
ArrayList::new));
userList.stream().forEach((user) -> {
System.out.println(user.getName() + ":" + user.getAge() + ":" + user.getBirthday());
});
}
14、將Student信息注入到相應(yīng)的Grade里面的studentList中
List<Student> stuList = Arrays.asList(
new Student(1, "張三", 1),
new Student(2, "李四", 2),
new Student(3, "李飛", 2)
);
List<Grade> gradeList = Arrays.asList(
new Grade(1, "大一"),
new Grade(2, "大二")
);
//13.將Student信息注入到相應(yīng)的Grade里面的studentList中
@Test
public void test13() {
gradeList.stream().forEach((grade) -> {
List<Student> students = stuList.stream().filter((stu) -> stu.getGradeId().equals(grade.getGradeId())).collect(toList());
grade.setStudentList(students);
});
gradeList.stream().forEach(grade -> {
System.out.println(grade.getGradeName() + "---");
grade.getStudentList().stream().forEach(stu -> {
System.out.println(stu.getStuName());
});
});
}
文章來源:http://www.zghlxwxcb.cn/news/detail-460814.html
如果這篇【文章】有幫助到你??,希望可以給我點個贊??,創(chuàng)作不易,如果有對Java后端或者對
spring
,分布式
,云原生
感興趣的朋友,請多多關(guān)注??????
????? 個人主頁 : 阿千弟文章來源地址http://www.zghlxwxcb.cn/news/detail-460814.html
到了這里,關(guān)于JDK8 新特性 Stream API 進(jìn)階 (結(jié)合案例詳解--通透--講清)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!