網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
文章目錄
- 1、關(guān)于Lambda表達(dá)式
- 1.1 概述
- 1.2 基本格式
- 1.3 省略規(guī)則
- 1.4 小細(xì)節(jié)
- 2、Stream流
- 2.1 數(shù)據(jù)準(zhǔn)備
- 2.2 創(chuàng)建流的方式
- 2.3 中間操作
- filter
- map
- distinct
- sorted
- limit
- skip
- flatMap
- 2.4 終結(jié)操作
- forEach
- count
- max&min
- collect
- 查找與匹配
- anyMatch
- allMatch
- noneMatch
- findAny
- findFirst
- reduce歸并
- 2.5 注意事項(xiàng)
提到lambda表達(dá)式,就不得不得不說(shuō)到一個(gè)叫做
函數(shù)式編程思想
的東西,這樣說(shuō)肯定是懵懵的。我們可以把他理解為一個(gè)數(shù)學(xué)函數(shù),只關(guān)心入?yún)⒑统鰠ⅲ蝗リP(guān)注方法名,這樣就可以淺略的理解函數(shù)式編程。
函數(shù)式編程思想就類(lèi)似于我們數(shù)學(xué)中的函數(shù)。它主要關(guān)注的是對(duì)數(shù)據(jù)進(jìn)行了什么操作。
1、關(guān)于Lambda表達(dá)式
1.1 概述
? Lambda是JDK8中一個(gè)語(yǔ)法糖。他可以對(duì)某些匿名內(nèi)部類(lèi)的寫(xiě)法進(jìn)行簡(jiǎn)化。它是函數(shù)式編程思想的一個(gè)重要體現(xiàn)。讓我們不用關(guān)注是什么對(duì)象。而是更關(guān)注我們對(duì)數(shù)據(jù)進(jìn)行了什么操作。
1.2 基本格式
(參數(shù)列表)->{代碼}
例一:
在創(chuàng)建線(xiàn)程并啟動(dòng)時(shí)可以使用匿名內(nèi)部類(lèi)的寫(xiě)法:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("1001001");
}
}).start();
可以將其轉(zhuǎn)換為L(zhǎng)ambda格式
new Thread(()->{
System.out.println("1001001");
}).start();
// 沒(méi)有參數(shù),所以參數(shù)列表可以省略
// Runnable接口的匿名方法只有一個(gè)run方法,所以也可以省略
例二:
現(xiàn)有方法定義如下,其中IntPredicate是一個(gè)接口。先使用匿名內(nèi)部類(lèi)的寫(xiě)法調(diào)用該方法。
public static void printNum(IntPredicate predicate){
int[] arr = {1,2,3,4,5,6,7,8,9,10};
for (int i : arr) {
if(predicate.test(i)){
System.out.println(i);
}
}
}
public static void main(String[] args) {
printNum(new IntPredicate() {
@Override
public boolean test(int value) {
return value%2==0;
}
});
}
lambda寫(xiě)法:
public static void main(String[] args) {
printNum((int value)-> {
return value%2==0;
});
}
public static void printNum(IntPredicate predicate){
int[] arr = {1,2,3,4,5,6,7,8,9,10};
for (int i : arr) {
if(predicate.test(i)){
System.out.println(i);
}
}
}
1.3 省略規(guī)則
- 參數(shù)類(lèi)型可以省略
- 方法體只有一句代碼時(shí)大括號(hào)return和唯一一句代碼的分號(hào)可以省略
- 方法只有一個(gè)參數(shù)時(shí)小括號(hào)可以省略
- 以上這些規(guī)則都記不住也可以省略不記
1.4 小細(xì)節(jié)
我們?cè)趯?xiě)匿名內(nèi)部類(lèi)時(shí),不熟悉的化,沒(méi)必要直接寫(xiě)為lambda表達(dá)式。而是可以直接寫(xiě)成匿名內(nèi)部類(lèi),然后在IDEA中 ALT + Enter
自動(dòng)補(bǔ)全為匿名內(nèi)部類(lèi)。
2、Stream流
Java8的Stream使用的是函數(shù)式編程模式,如同它的名字一樣,它可以被用來(lái)對(duì)集合或數(shù)組進(jìn)行鏈狀流式的操作。可以更方便的讓我們對(duì)集合或數(shù)組操作。
2.1 數(shù)據(jù)準(zhǔn)備
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode//用于后期的去重使用
public class Author {
//id
private Long id;
//姓名
private String name;
//年齡
private Integer age;
//簡(jiǎn)介
private String intro;
//作品
private List<Book> books;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode//用于后期的去重使用
public class Book {
//id
private Long id;
//書(shū)名
private String name;
//分類(lèi)
private String category;
//評(píng)分
private Integer score;
//簡(jiǎn)介
private String intro;
}
private static List<Author> getAuthors() {
//數(shù)據(jù)初始化
Author author = new Author(1L,"蒙多",33,"一個(gè)從菜刀中明悟哲理的祖安人",null);
Author author2 = new Author(2L,"亞拉索",15,"狂風(fēng)也追逐不上他的思考速度",null);
Author author3 = new Author(3L,"易",14,"是這個(gè)世界在限制他的思維",null);
Author author4 = new Author(3L,"易",14,"是這個(gè)世界在限制他的思維",null);
//書(shū)籍列表
List<Book> books1 = new ArrayList<>();
List<Book> books2 = new ArrayList<>();
List<Book> books3 = new ArrayList<>();
books1.add(new Book(1L,"刀的兩側(cè)是光明與黑暗","哲學(xué),愛(ài)情",88,"用一把刀劃分了愛(ài)恨"));
books1.add(new Book(2L,"一個(gè)人不能死在同一把刀下","個(gè)人成長(zhǎng),愛(ài)情",99,"講述如何從失敗中明悟真理"));
books2.add(new Book(3L,"那風(fēng)吹不到的地方","哲學(xué)",85,"帶你用思維去領(lǐng)略世界的盡頭"));
books2.add(new Book(3L,"那風(fēng)吹不到的地方","哲學(xué)",85,"帶你用思維去領(lǐng)略世界的盡頭"));
books2.add(new Book(4L,"吹或不吹","愛(ài)情,個(gè)人傳記",56,"一個(gè)哲學(xué)家的戀愛(ài)觀注定很難把他所在的時(shí)代理解"));
books3.add(new Book(5L,"你的劍就是我的劍","愛(ài)情",56,"無(wú)法想象一個(gè)武者能對(duì)他的伴侶這么的寬容"));
books3.add(new Book(6L,"風(fēng)與劍","個(gè)人傳記",100,"兩個(gè)哲學(xué)家靈魂和肉體的碰撞會(huì)激起怎么樣的火花呢?"));
books3.add(new Book(6L,"風(fēng)與劍","個(gè)人傳記",100,"兩個(gè)哲學(xué)家靈魂和肉體的碰撞會(huì)激起怎么樣的火花呢?"));
author.setBooks(books1);
author2.setBooks(books2);
author3.setBooks(books3);
author4.setBooks(books3);
List<Author> authorList = new ArrayList<>(Arrays.asList(author,author2,author3,author4));
return authorList;
}
2.2 創(chuàng)建流的方式
-
單列集合:
集合對(duì)象.stream()
List<Author> authors = getAuthors(); Stream<Author> stream = authors.stream();
-
數(shù)組:
Arrays.stream(數(shù)組)
或者使用Stream.of
來(lái)創(chuàng)建Integer[] arr = {1,2,3,4,5}; Stream<Integer> stream = Arrays.stream(arr); Stream<Integer> stream2 = Stream.of(arr);
-
雙列集合:轉(zhuǎn)換成單列集合后再創(chuàng)建
Map<String,Integer> map = new HashMap<>(); map.put("蠟筆小新",19); map.put("黑子",17); map.put("日向翔陽(yáng)",16); Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();
2.3 中間操作
所謂中間操作,就是在流輸出最終結(jié)果前,進(jìn)行的一系列操作。
filter
可以對(duì)流中的元素進(jìn)行條件過(guò)濾,類(lèi)似于SQL中的where
符合過(guò)濾條件的才能繼續(xù)留在流中。
例如:打印所有姓名長(zhǎng)度大于1的作家的姓名
List<Author> authors = getAuthors();
authors.stream()
.filter(author -> author.getName().length()>1)
.forEach(author -> System.out.println(author.getName()));
map
map
操作可以做轉(zhuǎn)換(或者說(shuō)投影),類(lèi)似 SQL 中的 select。可以把對(duì)流中的元素進(jìn)行計(jì)算或轉(zhuǎn)換。
例如:打印所有作家的姓名
List<Author> authors = getAuthors();
authors
.stream()
.map(author -> author.getName())
.forEach(name->System.out.println(name));
例如:將所有作者的年齡+10
authors.stream()
.map(author -> author.getAge())
.map(age->age+10)
.forEach(age-> System.out.println(age));
distinct
對(duì)流中重復(fù)的元素進(jìn)行過(guò)濾,類(lèi)似于SQL中的distinct
例如:打印所有作家的姓名,并且要求其中不能有重復(fù)元素。
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.forEach(author -> System.out.println(author.getName()));
注意:distinct方法是依賴(lài)Object的equals方法來(lái)判斷是否是相同對(duì)象的。所以需要注意重寫(xiě)equals方法。
sorted
可以對(duì)流中的元素進(jìn)行排序。
例如:對(duì)流中的元素按照年齡進(jìn)行降序排序,并且要求不能有重復(fù)的元素。
List<Author> authors = getAuthors();
// 對(duì)流中的元素按照年齡進(jìn)行降序排序,并且要求不能有重復(fù)的元素。
authors.stream()
.distinct()
.sorted() // Author類(lèi)需要實(shí)現(xiàn)Comparable接口
.forEach(author -> System.out.println(author.getAge()));
authors.stream()
.distinct()
.sorted((o1, o2) -> o2.getAge()-o1.getAge())
.forEach(author -> System.out.println(author.getAge()));
注意:如果調(diào)用空參的sorted()方法,需要流中的元素是實(shí)現(xiàn)了Comparable。
limit
可以設(shè)置流的最大長(zhǎng)度,超出的部分將被拋棄。
例如:對(duì)流中的元素按照年齡進(jìn)行降序排序,并且要求不能有重復(fù)的元素,然后打印其中年齡最大的兩個(gè)作家的姓名。
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.sorted()
.limit(2)
.forEach(author -> System.out.println(author.getName()));
skip
跳過(guò)流中的前n個(gè)元素,返回剩下的元素
例如:打印除了年齡最大的作家外的其他作家,要求不能有重復(fù)元素,并且按照年齡降序排序。
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.sorted()
.skip(1)
.forEach(author -> System.out.println(author.getName()));
flatMap
map只能把一個(gè)對(duì)象轉(zhuǎn)換成另一個(gè)對(duì)象來(lái)作為流中的元素。而flatMap可以把一個(gè)對(duì)象轉(zhuǎn)換成多個(gè)對(duì)象作為流中的元素。
例一:打印所有書(shū)籍的名字。要求對(duì)重復(fù)的元素進(jìn)行去重。
List<Author> authors = getAuthors();
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.forEach(book -> System.out.println(book.getName()));
例二:打印現(xiàn)有數(shù)據(jù)的所有分類(lèi)。要求對(duì)分類(lèi)進(jìn)行去重。不能出現(xiàn)這種格式:哲學(xué),愛(ài)情
List<Author> authors = getAuthors();
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.flatMap(book -> Arrays.stream(book.getCategory().split(",")))
.distinct()
.forEach(category-> System.out.println(category));
2.4 終結(jié)操作
forEach
對(duì)流中的元素進(jìn)行遍歷操作,我們通過(guò)傳入的參數(shù)去指定對(duì)遍歷到的元素進(jìn)行什么具體操作。
例如:輸出所有作家的名字
List<Author> authors = getAuthors();
authors.stream()
.map(author -> author.getName())
.distinct()
.forEach(name-> System.out.println(name));
count
可以用來(lái)獲取當(dāng)前流中元素的個(gè)數(shù)。
例如:打印這些作家的所出書(shū)籍的數(shù)目,注意刪除重復(fù)元素。
List<Author> authors = getAuthors();
long count = authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.count();
System.out.println(count);
max&min
可以用來(lái)或者流中的最值。
例子:分別獲取這些作家的所出書(shū)籍的最高分和最低分并打印。
List<Author> authors = getAuthors();
Optional<Integer> max = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.max((score1, score2) -> score1 - score2);
Optional<Integer> min = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.min((score1, score2) -> score1 - score2);
System.out.println(max.get());
System.out.println(min.get());
collect
把當(dāng)前流轉(zhuǎn)換成一個(gè)集合。
例如:獲取一個(gè)存放所有作者名字的List集合。
List<Author> authors = getAuthors();
// 獲取一個(gè)存放所有作者名字的List集合。
List<String> nameList = authors.stream()
.map(author -> author.getName())
.collect(Collectors.toList());
System.out.println(nameList);
// 獲取一個(gè)所有書(shū)名的Set集合。
Set<Book> books = authors.stream()
.flatMap(author -> author.getBooks().stream())
.collect(Collectors.toSet());
System.out.println(books);
// 獲取一個(gè)Map集合,map的key為作者名,value為L(zhǎng)ist<Book>
Map<String, List<Book>> map = authors.stream()
.distinct()
.collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
System.out.println(map);
查找與匹配
anyMatch
? 可以用來(lái)判斷是否有任意符合匹配條件的元素,結(jié)果為boolean類(lèi)型。
例子:
? 判斷是否有年齡在29以上的作家
// 判斷是否有年齡在29以上的作家
List<Author> authors = getAuthors();
boolean flag = authors.stream()
.anyMatch(author -> author.getAge() > 29);
System.out.println(flag);
allMatch
? 可以用來(lái)判斷是否都符合匹配條件,結(jié)果為boolean類(lèi)型。如果都符合結(jié)果為true,否則結(jié)果為false。
例子:
? 判斷是否所有的作家都是成年人
// 判斷是否所有的作家都是成年人
List<Author> authors = getAuthors();
boolean flag = authors.stream()
.allMatch(author -> author.getAge() >= 18);
System.out.println(flag);
noneMatch
? 可以判斷流中的元素是否都不符合匹配條件。如果都不符合結(jié)果為true,否則結(jié)果為false
例子:
? 判斷作家是否都沒(méi)有超過(guò)100歲的。
// 判斷作家是否都沒(méi)有超過(guò)100歲的。
List<Author> authors = getAuthors();
boolean b = authors.stream()
.noneMatch(author -> author.getAge() > 100);
System.out.println(b);
findAny
? 獲取流中的任意一個(gè)元素。該方法沒(méi)有辦法保證獲取的一定是流中的第一個(gè)元素。
例子:
? 獲取任意一個(gè)年齡大于18的作家,如果存在就輸出他的名字
// 獲取任意一個(gè)年齡大于18的作家,如果存在就輸出他的名字
List<Author> authors = getAuthors();
Optional<Author> optionalAuthor = authors.stream()
.filter(author -> author.getAge()>18)
.findAny();
optionalAuthor.ifPresent(author -> System.out.println(author.getName()));
findFirst
? 獲取流中的第一個(gè)元素。
例子:
? 獲取一個(gè)年齡最小的作家,并輸出他的姓名。
// 獲取一個(gè)年齡最小的作家,并輸出他的姓名。
List<Author> authors = getAuthors();
Optional<Author> first = authors.stream()
.sorted((o1, o2) -> o1.getAge() - o2.getAge())
.findFirst();
first.ifPresent(author -> System.out.println(author.getName()));
reduce歸并
? 對(duì)流中的數(shù)據(jù)按照你指定的計(jì)算方式計(jì)算出一個(gè)結(jié)果。(縮減操作)
? reduce的作用是把stream中的元素給組合起來(lái),我們可以傳入一個(gè)初始值,它會(huì)按照我們的計(jì)算方式依次拿流中的元素和初始化值進(jìn)行計(jì)算,計(jì)算結(jié)果再和后面的元素計(jì)算。
? reduce兩個(gè)參數(shù)的重載形式內(nèi)部的計(jì)算方式如下:
T result = identity;
for (T element : this stream)
result = accumulator.apply(result, element)
return result;
? 其中identity就是我們可以通過(guò)方法參數(shù)傳入的初始值,accumulator的apply具體進(jìn)行什么計(jì)算也是我們通過(guò)方法參數(shù)來(lái)確定的。
例子:
? 使用reduce求所有作者年齡的和
// 使用reduce求所有作者年齡的和
List<Author> authors = getAuthors();
Integer sum = authors.stream()
.distinct()
.map(author -> author.getAge())
.reduce(0, (result, element) -> result + element);
System.out.println(sum);
? 使用reduce求所有作者中年齡的最大值
// 使用reduce求所有作者中年齡的最大值
List<Author> authors = getAuthors();
Integer max = authors.stream()
.map(author -> author.getAge())
.reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);
System.out.println(max);
? 使用reduce求所有作者中年齡的最小值
// 使用reduce求所有作者中年齡的最小值
List<Author> authors = getAuthors();
Integer min = authors.stream()
.map(author -> author.getAge())
.reduce(Integer.MAX_VALUE, (result, element) -> result > element ? element : result);
System.out.println(min);
? reduce一個(gè)參數(shù)的重載形式內(nèi)部的計(jì)算
boolean foundAny = false;
T result = null;
for (T element : this stream) {
if (!foundAny) {
foundAny = true;
result = element;
}
else
result = accumulator.apply(result, element);
}
return foundAny ? Optional.of(result) : Optional.empty();
? 如果用一個(gè)參數(shù)的重載方法去求最小值代碼如下:
// 使用reduce求所有作者中年齡的最小值
List<Author> authors = getAuthors();
Optional<Integer> minOptional = authors.stream()
.map(author -> author.getAge())
.reduce((result, element) -> result > element ? element : result);
minOptional.ifPresent(age-> System.out.println(age));
2.5 注意事項(xiàng)
- 惰性求值(如果沒(méi)有終結(jié)操作,沒(méi)有中間操作是不會(huì)得到執(zhí)行的)
- 流是一次性的(一旦一個(gè)流對(duì)象經(jīng)過(guò)一個(gè)終結(jié)操作后。這個(gè)流就不能再被使用)
- 不會(huì)影響原數(shù)據(jù)(我們?cè)诹髦锌梢远鄶?shù)據(jù)做很多處理。但是正常情況下是不會(huì)影響原來(lái)集合中的元素的。這往往也是我們期望的)
原文鏈接:https://blog.csdn.net/weixin_45483328/article/details/125687830
相關(guān)推薦
- 2022-11-08 Go中init()執(zhí)行順序詳解_Golang
- 2022-04-01 用C語(yǔ)言實(shí)現(xiàn)推箱子游戲?qū)嵗齙C 語(yǔ)言
- 2023-01-26 redis慢查詢(xún)?nèi)罩镜脑L(fǎng)問(wèn)和管理方式_Redis
- 2022-07-29 cypress測(cè)試本地web應(yīng)用_web2.0
- 2024-07-15 SpringBoot使用EasyExcel導(dǎo)出Excel(含設(shè)置下拉框、表頭凍結(jié))
- 2022-09-03 列表頁(yè)常見(jiàn)hook封裝實(shí)例_React
- 2022-02-24 JDBC中在結(jié)果集中以列順序獲取值時(shí)注意類(lèi)型匹配
- 2023-04-11 pandas中實(shí)現(xiàn)將相同ID的字符串進(jìn)行合并_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支