java8函数式编程 视频_快速掌握Java8 Stream函数式编程技巧
函數(shù)式編程優(yōu)勢“函數(shù)第一位”,即函數(shù)可以出現(xiàn)在任何地方。
可以把函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù),還可以將函數(shù)作為返回值。
讓代碼的邏輯更清晰更優(yōu)雅。
減少了可變量(Immutable Variable)的聲明,程序更為安全。
支持惰性計(jì)算。
Lambda語法三部分一個(gè)括號內(nèi)用逗號分隔的形式參數(shù),參數(shù)是函數(shù)式接口里面方法的參數(shù)
一個(gè)箭頭符號:->
方法體,可以是表達(dá)式和代碼塊,方法體函數(shù)式接口里面方法的實(shí)現(xiàn),如果是代碼塊,則必須用{}來包裹起來,且需要一個(gè)return 返回值,但有個(gè)例外,若函數(shù)式接口里面方法返回值是void,則無需{}。例如:
(parameters) -> expression 或者 (parameters) -> { statements; }
方法引用是lambda表達(dá)式的一個(gè)簡化寫法,所引用的方法其實(shí)是lambda表達(dá)式的方法體實(shí)現(xiàn),語法也很簡單,左邊是容器(可以是類名,實(shí)例名),中間是“::”,右邊是相應(yīng)的方法名。如下所示:
ObjectReference::methodName
一般方法的引用格式是:如果是靜態(tài)方法,則是ClassName::methodName。如 Object ::equals
如果是實(shí)例方法,則是Instance::methodName。如Object obj=new Object();obj::equals;
構(gòu)造函數(shù).則是ClassName::new
Stream是什么
Stream是Java8中新加入的api,更準(zhǔn)確的說: Java 8 中的 Stream 是對集合(Collection)對象功能的增強(qiáng),它專注于對集合對象進(jìn)行各種非常便利、高效的聚合操作,或者大批量數(shù)據(jù)操作 。Stream API 借助于同樣新出現(xiàn)的 Lambda 表達(dá)式,極大的提高編程效率和程序可讀性。
?
以前我們處理復(fù)雜的數(shù)據(jù)只能通過各種for循環(huán),不僅不美觀,而且時(shí)間長了以后可能自己都看不太明白以前的代碼了,但有Stream以后,通過filter,map,limit等等方法就可以使代碼更加簡潔并且更加語義化。 Stream的效果就像上圖展示的它可以先把數(shù)據(jù)變成符合要求的樣子(map),吃掉不需要的東西(filter)然后得到需要的東西(collect)。
Stream操作分類
Stream上的所有操作分為兩類:中間操作和結(jié)束操作,中間操作只是一種標(biāo)記,只有結(jié)束操作才會(huì)觸發(fā)實(shí)際計(jì)算。中間操作又可以分為無狀態(tài)的(Stateless)和有狀態(tài)的(Stateful),無狀態(tài)中間操作是指元素的處理不受前面元素的影響,而有狀態(tài)的中間操作必須等到所有元素處理之后才知道最終結(jié)果,比如排序是有狀態(tài)操作,在讀取所有元素之前并不能確定排序結(jié)果;結(jié)束操作又可以分為短路操作和非短路操作,短路操作是指不用處理全部元素就可以返回結(jié)果,比如找到第一個(gè)滿足條件的元素。之所以要進(jìn)行如此精細(xì)的劃分,是因?yàn)榈讓訉γ恳环N情況的處理方式不同。
Stream API等價(jià)實(shí)現(xiàn)
求出字符串集合中所有以字母A開頭字符串的最大長度
int longest = 0;
for(String str : strings){
if(str.startsWith("A")){// 1. filter(), 保留以A開頭的字符串
int len = str.length();// 2. mapToInt(), 轉(zhuǎn)換成長度
longest = Math.max(len, longest);// 3. max(), 保留最長的長度
}
}
int longest = strings.stream()
.filter(str -> str.startsWith("A"))
.mapToInt(str -> str.length())
//.mapToInt(String::length)
.max();
Stream串行與并行
Stream可以分為串行與并行兩種,串行流和并行流差別就是單線程和多線程的執(zhí)行。 default Stream stream() : 返回串行流 default Stream parallelStream() : 返回并行流 stream()和parallelStream()方法返回的都是java.util.stream.Stream類型的對象,說明它們在功能的使用上是沒差別的。唯一的差別就是單線程和多線程的執(zhí)行。
Stream性能總結(jié)
1.對于簡單操作,比如最簡單的遍歷,Stream串行API性能明顯差于顯示迭代,但并行的Stream API能夠發(fā)揮多核特性。
2.對于復(fù)雜操作,Stream串行API性能可以和手動(dòng)實(shí)現(xiàn)的效果匹敵,在并行執(zhí)行時(shí)Stream API效果遠(yuǎn)超手動(dòng)實(shí)現(xiàn)。
所以,如果出于性能考慮:對于簡單操作推薦使用外部迭代手動(dòng)實(shí)現(xiàn)。
對于復(fù)雜操作,推薦使用Stream API。
在多核情況下,推薦使用并行Stream API來發(fā)揮多核優(yōu)勢。
單核情況下不建議使用并行Stream API。 如果出于代碼簡潔性考慮,使用Stream API能夠?qū)懗龈痰拇a。即使是從性能方面說,盡可能的使用Stream API也另外一個(gè)優(yōu)勢,那就是只要Java Stream類庫做了升級優(yōu)化,代碼不用做任何修改就能享受到升級帶來的好處。
Stream 來源
所有流計(jì)算都有一種共同的結(jié)構(gòu):它們具有一個(gè)流來源、0 或多個(gè)中間操作,以及一個(gè)終止操作。流的元素可以是對象引用 (Stream),也可以是原始整數(shù) (IntStream)、長整型 (LongStream) 或雙精度 (DoubleStream)。
因?yàn)?Java 程序使用的大部分?jǐn)?shù)據(jù)都已存儲(chǔ)在集合中,所以許多流計(jì)算使用集合作為它們的來源。JDK 中的 Collection 實(shí)現(xiàn)都已增強(qiáng),可充當(dāng)高效的流來源。但是,還存在其他可能的流來源,比如數(shù)組、生成器函數(shù)或內(nèi)置的工廠(比如數(shù)字范圍),而且可以編寫自定義的流適配器,以便可以將任意數(shù)據(jù)源充當(dāng)流來源。如上圖中一些流生成方法。
Stream 操作
中間操作負(fù)責(zé)將一個(gè)流轉(zhuǎn)換為另一個(gè)流,中間操作包括 filter()(選擇與條件匹配的元素)、map()(根據(jù)函數(shù)來轉(zhuǎn)換元素)、distinct()(刪除重復(fù))、limit()(在特定大小處截?cái)嗔?和 sorted()。一些操作(比如 mapToInt())獲取一種類型的流并返回一種不同類型的流。
中間操作始終是惰性的:調(diào)用中間操作只會(huì)設(shè)置流管道的下一個(gè)階段,不會(huì)啟動(dòng)任何操作。重建操作可進(jìn)一步劃分為無狀態(tài) 和有狀態(tài) 操作。無狀態(tài)操作(比如 filter() 或 map())可獨(dú)立處理每個(gè)元素,而有狀態(tài)操作(比如 sorted() 或 distinct())可合并以前看到的影響其他元素處理的元素狀態(tài)。
數(shù)據(jù)集的處理在執(zhí)行終止操作時(shí)開始,比如縮減(sum() 或 max())、應(yīng)用 (forEach()) 或搜索 (findFirst()) 操作。終止操作會(huì)生成一個(gè)結(jié)果或副作用。執(zhí)行終止操作時(shí),會(huì)終止流管道,如果您想再次遍歷同一個(gè)數(shù)據(jù)集,可以設(shè)置一個(gè)新的流管道。如下給出了一些終止流操作。
Stream 流與集合比較
集合是一種數(shù)據(jù)結(jié)構(gòu),它的主要關(guān)注點(diǎn)是在內(nèi)存中組織數(shù)據(jù),而且集合會(huì)在一段時(shí)間內(nèi)持久存在。 流的關(guān)注點(diǎn)是計(jì)算,而不是數(shù)據(jù)。流沒有為它們處理的元素提供存儲(chǔ)空間,而且流的生命周期更像一個(gè)時(shí)間點(diǎn) — 調(diào)用終止操作。 不同于集合,流也可以是無限的(Stream.generate、Stream.iterate);相應(yīng)地,一些操作(limit()、findFirst())是短路,而且可在無限流上運(yùn)行有限的計(jì)算。 程序 = 數(shù)據(jù)結(jié)構(gòu) + 算法,集合即數(shù)據(jù)結(jié)構(gòu),流操作相當(dāng)于算法。
數(shù)據(jù)形式:集合是一個(gè)內(nèi)存中的數(shù)據(jù)結(jié)構(gòu),它包含數(shù)據(jù)結(jié)構(gòu)中目前所有的值——集合中的每個(gè)元素都得先算出來才能添加到集合中。(你可以往集合里加?xùn)|西或者刪東西,但是不管什么時(shí)候,集合中的每個(gè)元素都是放在內(nèi)存里的,元素都得先算出來才能成為集合的一部分。) 相比之下,流則是在概念上固定的數(shù)據(jù)結(jié)構(gòu)(你不能添加或刪除元素),其元素則是按需計(jì)算的。
迭代方式:使用Collection接口需要用戶去做迭代(比如用for-each),這稱為外部迭代。相反,Streams庫使用內(nèi)部迭代——它幫你把迭代做了,還把得到的流值存在了某個(gè)地方,你只要給出一個(gè)函數(shù)說要干什么就可以了。Steams庫的內(nèi)部迭代可以自動(dòng)選擇一種適合你硬件的數(shù)據(jù)表示和并行實(shí)現(xiàn)。
Stream 基本使用
filter篩選(中間操作)
輸出:4,5
List integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream stream = integerList.stream().filter(i -> i > 3);
distinct去重(中間操作)
輸出:1,2,3,4,5
List integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream stream = integerList.stream().distinct();
limit限制(中間操作)
輸出:1,1,2
List integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream stream = integerList.stream().limit(3);
skip跳過(中間操作)
輸出:2,3,4,5
List integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream stream = integerList.stream().skip(2);
map流映射(中間操作)
輸出:6, 7, 2, 6
List stringList = Arrays.asList("Java 8", "Lambdas", "In", "Action");
Stream stream = stringList.stream().map(String::length);
flatMap流轉(zhuǎn)換(中間操作)
輸出:1, 2, 3, 4
將一個(gè)流中的每個(gè)值都轉(zhuǎn)換為另一個(gè)流
List> lists = new ArrayList>() {{
add(Arrays.asList(1, 2));
add(Arrays.asList(3, 4));
}};
Stream stream = lists.stream().flatMap(List::stream);
//Stream stream = lists.stream().flatMap(list -> list.stream());
allMatch匹配所有(中間操作)
輸出:
List integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().allMatch(i -> i > 3)) {
System.out.println("值都大于3");
}
noneMatch全部不匹配(中間操作)
輸出:
List integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().noneMatch(i -> i > 3)) {
System.out.println("值都小于3");
}
anyMatch匹配其中一個(gè)(中間操作)
輸出:存在大于3的值
List integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().anyMatch(i -> i > 3)) {
System.out.println("存在大于3的值");
}
findFirst查找第一個(gè)(終端操作)
輸出:4
List integerList = Arrays.asList(1, 2, 3, 4, 5);
Optional result = integerList.stream().filter(i -> i > 3).findFirst();
findAny隨機(jī)查找一個(gè)(終端操作)
輸出:存在大于3的值
和findFirst操作相比,并行流優(yōu)勢更大
List integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().findAny(i -> i > 3)) {
System.out.println("存在大于3的值");
}
Stream 常用統(tǒng)計(jì)
List ints = Arrays.asList(1, 1, 2, 2, 3);
//統(tǒng)計(jì)流中元素個(gè)數(shù)
ints.stream().count();
ints.stream().collect(Collectors.counting());
//獲取流中最小值
ints.stream().min(Integer::compareTo);
ints.stream().collect(Collectors.minBy(Integer::compareTo));
//獲取流中最大值
ints.stream().max(Integer::compareTo);
ints.stream().collect(Collectors.maxBy(Integer::compareTo));
//求和
ints.stream().mapToInt(Integer::intValue).sum();
ints.stream().collect(Collectors.summingInt(Integer::intValue));
ints.stream().reduce(0, Integer::sum);
//平均值
ints.stream().collect(Collectors.averagingInt(Integer::intValue));
//通過summarizingInt同時(shí)求總和、平均值、最大值、最小值
ints.stream().collect(Collectors.summarizingInt(Integer::intValue));
Stream 終端操作(collect)
List ints = Arrays.asList(1, 1, 2, 2, 3);
//返回List
ints.stream().collect(Collectors.toList());
//返回Set
ints.stream().collect(Collectors.toSet());
//返回Map
ints.stream().collect(Collectors.toMap(k -> k, v -> v, (v1, v2) -> v1));
//group分組
ints.stream().collect(Collectors.groupingBy(k -> k));
//partitioningBy分區(qū)
ints.stream().collect(Collectors.partitioningBy(k -> k % 2 == 0));
Stream參考文獻(xiàn)
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的java8函数式编程 视频_快速掌握Java8 Stream函数式编程技巧的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 优盘损坏且无法读取怎么解决 优盘损坏,如
- 下一篇: java对象序列化作用_Java学习之—