JDK1.8 新特性(全)
https://blog.csdn.net/qq_29411737/article/details/80835658
JDK1.8 新特性(全)
2018年06月27日 22:01:54 qq_29411737 閱讀數:6952
版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/qq_29411737/article/details/80835658
JDK1.8 新特性
本文主要介紹了JDK1.8版本中的一些新特性,乃作者視訊觀後筆記,僅供參考。
jdk1.8新特性知識點:
- Lambda表示式
- 函式式介面
- *方法引用和構造器呼叫
- Stream API
- 介面中的預設方法和靜態方法
- 新時間日期API
在jdk1.8中對hashMap等map集合的資料結構優化。hashMap資料結構的優化
原來的hashMap採用的資料結構是雜湊表(陣列+連結串列),hashMap預設大小是16,一個0-15索引的陣列,如何往裡面儲存元素,首先呼叫元素的hashcode
方法,計算出雜湊碼值,經過雜湊演算法算成陣列的索引值,如果對應的索引處沒有元素,直接存放,如果有物件在,那麼比較它們的equals方法比較內容
如果內容一樣,後一個value會將前一個value的值覆蓋,如果不一樣,在1.7的時候,後加的放在前面,形成一個連結串列,形成了碰撞,在某些情況下如果連結串列
無限下去,那麼效率極低,碰撞是避免不了的
載入因子:0.75,陣列擴容,達到總容量的75%,就進行擴容,但是無法避免碰撞的情況發生
在1.8之後,在陣列+連結串列+紅黑樹來實現hashmap,當碰撞的元素個數大於8時 & 總容量大於64,會有紅黑樹的引入
除了新增之後,效率都比連結串列高,1.8之後連結串列新進元素加到末尾
ConcurrentHashMap (鎖分段機制),concurrentLevel,jdk1.8採用CAS演算法(無鎖演算法,不再使用鎖分段),陣列+連結串列中也引入了紅黑樹的使用
Lambda表示式
lambda表示式本質上是一段匿名內部類,也可以是一段可以傳遞的程式碼
先來體驗一下lambda最直觀的優點:簡潔程式碼
<span style="color:#000000"><code> <span style="color:#880000 !important"><em>//匿名內部類</em></span> Comparator<span style="color:#4f4f4f !important"><</span><span style="color:#4f4f4f !important">Integer</span><span style="color:#4f4f4f !important">></span> cpt <span style="color:#4f4f4f !important">=</span> <span style="color:#006666 !important">new</span> Comparator<span style="color:#4f4f4f !important"><</span><span style="color:#4f4f4f !important">Integer</span><span style="color:#4f4f4f !important">></span>() { @Override <span style="color:#000088 !important">public</span> int compare(<span style="color:#4f4f4f !important">Integer</span> o1, <span style="color:#4f4f4f !important">Integer</span> o2) { <span style="color:#000088 !important">return</span> <span style="color:#4f4f4f !important">Integer</span><span style="color:#4f4f4f !important">.</span>compare(o1,o2); } }; TreeSet<span style="color:#4f4f4f !important"><</span><span style="color:#4f4f4f !important">Integer</span><span style="color:#4f4f4f !important">></span> <span style="color:#4f4f4f !important">set</span> <span style="color:#4f4f4f !important">=</span> <span style="color:#006666 !important">new</span> TreeSet<span style="color:#4f4f4f !important"><></span>(cpt); System<span style="color:#4f4f4f !important">.</span>out<span style="color:#4f4f4f !important">.</span>println(<span style="color:#009900 !important">"========================="</span>); <span style="color:#880000 !important"><em>//使用lambda表示式</em></span> Comparator<span style="color:#4f4f4f !important"><</span><span style="color:#4f4f4f !important">Integer</span><span style="color:#4f4f4f !important">></span> cpt2 <span style="color:#4f4f4f !important">=</span> (x,y) <span style="color:#4f4f4f !important">-> </span><span style="color:#4f4f4f !important">Integer</span><span style="color:#4f4f4f !important">.</span>compare(x,y); TreeSet<span style="color:#4f4f4f !important"><</span><span style="color:#4f4f4f !important">Integer</span><span style="color:#4f4f4f !important">></span> set2 <span style="color:#4f4f4f !important">=</span> <span style="color:#006666 !important">new</span> TreeSet<span style="color:#4f4f4f !important"><></span>(cpt2);</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
只需要一行程式碼,極大減少程式碼量!!
這樣一個場景,在商城瀏覽商品資訊時,經常會有條件的進行篩選瀏覽,例如要選顏色為紅色的、價格小於8000千的….
<span style="color:#000000"><code><span style="color:#880000 !important"><em>// 篩選顏色為紅色</em></span>
<span style="color:#000088 !important">public</span> <span style="color:#000088 !important">List</span><Product> filterProductByColor(<span style="color:#000088 !important">List</span><Product> <span style="color:#000088 !important">list</span>){
<span style="color:#000088 !important">List</span><Product> prods = <span style="color:#000088 !important">new</span> ArrayList<>();
<span style="color:#000088 !important">for</span> (Product product : <span style="color:#000088 !important">list</span>){
<span style="color:#000088 !important">if</span> (<span style="color:#009900 !important">"紅色"</span>.equals(product.getColor())){
prods.add(product);
}
}
<span style="color:#000088 !important">return</span> prods;
}
<span style="color:#880000 !important"><em>// 篩選價格小於8千的</em></span>
<span style="color:#000088 !important">public</span> <span style="color:#000088 !important">List</span><Product> filterProductByPrice(<span style="color:#000088 !important">List</span><Product> <span style="color:#000088 !important">list</span>){
<span style="color:#000088 !important">List</span><Product> prods = <span style="color:#000088 !important">new</span> ArrayList<>();
<span style="color:#000088 !important">for</span> (Product product : <span style="color:#000088 !important">list</span>){
<span style="color:#000088 !important">if</span> (product.getPrice() < <span style="color:#006666 !important">8000</span>){
prods.add(product);
}
}
<span style="color:#000088 !important">return</span> prods;
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
我們發現實際上這些過濾方法的核心就只有if語句中的條件判斷,其他均為模版程式碼,每次變更一下需求,都需要新增一個方法,然後複製黏貼,假設這個過濾方法有幾百行,那麼這樣的做法難免笨拙了一點。如何進行優化呢?
優化一:使用設計模式
定義一個MyPredicate介面
<span style="color:#000000"><code><span style="color:#000088 !important">public</span> <span style="color:#000088 !important">interface</span> MyPredicate <T> {
boolean test(T t);
}</code></span>
- 1
- 2
- 3
如果想要篩選顏色為紅色的商品,定義一個顏色過濾類
<span style="color:#000000"><code><span style="color:#000088 !important">public</span> <span style="color:#000088 !important">class</span> <span style="color:#4f4f4f !important">ColorPredicate</span> <span style="color:#000088 !important">implements</span> <span style="color:#4f4f4f !important">MyPredicate</span> <<span style="color:#4f4f4f !important">Product</span>> {
<span style="color:#000088 !important">private</span> <span style="color:#000088 !important">static</span> <span style="color:#000088 !important">final</span> String RED = <span style="color:#009900 !important">"紅色"</span>;
@Override
<span style="color:#000088 !important">public</span> <span style="color:#000088 !important">boolean</span> test(Product product) {
<span style="color:#000088 !important">return</span> RED.equals(product.getColor());
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
定義過濾方法,將過濾介面當做引數傳入,這樣這個過濾方法就不用修改,在實際呼叫的時候將具體的實現類傳入即可。
<span style="color:#000000"><code><span style="color:#000088 !important">public</span> <span style="color:#000088 !important">List</span><Product> filterProductByPredicate(<span style="color:#000088 !important">List</span><Product> <span style="color:#000088 !important">list</span>,MyPredicate<Product> mp){
<span style="color:#000088 !important">List</span><Product> prods = <span style="color:#000088 !important">new</span> ArrayList<>();
<span style="color:#000088 !important">for</span> (Product prod : <span style="color:#000088 !important">list</span>){
<span style="color:#000088 !important">if</span> (mp.test(prod)){
prods.add(prod);
}
}
<span style="color:#000088 !important">return</span> prods;
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
例如,如果想要篩選價格小於8000的商品,那麼新建一個價格過濾類既可
<span style="color:#000000"><code><span style="color:#000088 !important">public</span> <span style="color:#000088 !important">class</span> <span style="color:#4f4f4f !important">PricePredicate</span> <span style="color:#000088 !important">implements</span> <span style="color:#4f4f4f !important">MyPredicate</span><<span style="color:#4f4f4f !important">Product</span>> {
@Override
<span style="color:#000088 !important">public</span> <span style="color:#000088 !important">boolean</span> test(Product product) {
<span style="color:#000088 !important">return</span> product.getPrice() < <span style="color:#006666 !important">8000</span>;
}
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
這樣實現的話可能有人會說,每次變更需求都需要新建一個實現類,感覺還是有點繁瑣呀,那麼再來優化一下
優化二:使用匿名內部類
定義過濾方法:
<span style="color:#000000"><code><span style="color:#000088 !important">public</span> <span style="color:#000088 !important">List</span><Product> filterProductByPredicate(<span style="color:#000088 !important">List</span><Product> <span style="color:#000088 !important">list</span>,MyPredicate<Product> mp){
<span style="color:#000088 !important">List</span><Product> prods = <span style="color:#000088 !important">new</span> ArrayList<>();
<span style="color:#000088 !important">for</span> (Product prod : <span style="color:#000088 !important">list</span>){
<span style="color:#000088 !important">if</span> (mp.test(prod)){
prods.add(prod);
}
}
<span style="color:#000088 !important">return</span> prods;
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
呼叫過濾方法的時候:
<span style="color:#000000"><code><span style="color:#880000 !important"><em>// 按價格過濾</em></span>
<span style="color:#000088 !important">public</span> <span style="color:#000088 !important">void</span> <span style="color:#009900 !important">test2</span>(){
filterProductByPredicate(proList, <span style="color:#000088 !important">new</span> MyPredicate<Product>() {
<span style="color:#9b859d !important">@Override</span>
<span style="color:#000088 !important">public</span> <span style="color:#000088 !important">boolean</span> <span style="color:#009900 !important">test</span>(Product product) {
<span style="color:#000088 !important">return</span> product.getPrice() < <span style="color:#006666 !important">8000</span>;
}
});
}
<span style="color:#880000 !important"><em>// 按顏色過濾</em></span>
<span style="color:#000088 !important">public</span> <span style="color:#000088 !important">void</span> <span style="color:#009900 !important">test3</span>(){
filterProductByPredicate(proList, <span style="color:#000088 !important">new</span> MyPredicate<Product>() {
<span style="color:#9b859d !important">@Override</span>
<span style="color:#000088 !important">public</span> <span style="color:#000088 !important">boolean</span> <span style="color:#009900 !important">test</span>(Product product) {
<span style="color:#000088 !important">return</span> <span style="color:#009900 !important">"紅色"</span>.equals(product.getColor());
}
});
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
使用匿名內部類,就不需要每次都新建一個實現類,直接在方法內部實現。看到匿名內部類,不禁想起了Lambda表示式。
優化三:使用lambda表示式
定義過濾方法:
<span style="color:#000000"><code><span style="color:#000088 !important">public</span> <span style="color:#000088 !important">List</span><Product> filterProductByPredicate(<span style="color:#000088 !important">List</span><Product> <span style="color:#000088 !important">list</span>,MyPredicate<Product> mp){
<span style="color:#000088 !important">List</span><Product> prods = <span style="color:#000088 !important">new</span> ArrayList<>();
<span style="color:#000088 !important">for</span> (Product prod : <span style="color:#000088 !important">list</span>){
<span style="color:#000088 !important">if</span> (mp.test(prod)){
prods.add(prod);
}
}
<span style="color:#000088 !important">return</span> prods;
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
使用lambda表示式進行過濾
<span style="color:#000000"><code>@Test
public void test4(){
List<Product> products = filterProductByPredicate<span style="color:#4f4f4f !important">(proList, (p) -> p.getPrice() < <span style="color:#006666 !important">8000</span>)</span>;
<span style="color:#009900 !important">for</span> <span style="color:#4f4f4f !important">(Product pro : products)</span>{
<span style="color:#009900 !important">System</span>.<span style="color:#009900 !important">out</span>.<span style="color:#009900 !important">println</span><span style="color:#4f4f4f !important">(pro)</span>;
}
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
在jdk1.8中還有更加簡便的操作 Stream API
優化四:使用Stream API
甚至不用定義過濾方法,直接在集合上進行操作
<span style="color:#000000"><code><span style="color:#008800 !important">//</span> 使用jdk1<span style="color:#006666 !important">.8</span>中的Stream API進行集合的操作
@Test
public void test(){
<span style="color:#008800 !important">//</span> 根據價格過濾
proList.stream()
.fliter<span style="color:#4f4f4f !important">((p) -> p.getPrice() <<span style="color:#006666 !important">8000</span>)</span>
.<span style="color:#009900 !important">limit</span><span style="color:#4f4f4f !important">(<span style="color:#006666 !important">2</span>)</span>
.<span style="color:#009900 !important">forEach</span><span style="color:#4f4f4f !important">(System.out::println)</span>;
// 根據顏色過濾
<span style="color:#009900 !important">proList</span>.<span style="color:#009900 !important">stream</span><span style="color:#4f4f4f !important">()</span>
.<span style="color:#009900 !important">fliter</span><span style="color:#4f4f4f !important">((p) -> <span style="color:#009900 !important">"紅色"</span>.equals(p.getColor()))</span>
.<span style="color:#009900 !important">forEach</span><span style="color:#4f4f4f !important">(System.out::println)</span>;
// 遍歷輸出商品名稱
<span style="color:#009900 !important">proList</span>.<span style="color:#009900 !important">stream</span><span style="color:#4f4f4f !important">()</span>
.<span style="color:#009900 !important">map</span><span style="color:#4f4f4f !important">(Product::getName)</span>
.<span style="color:#009900 !important">forEach</span><span style="color:#4f4f4f !important">(System.out::println)</span>;
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
Lmabda表示式的語法總結: () -> ();
前置 | 語法 |
---|---|
無引數無返回值 | () -> System.out.println(“Hello WOrld”) |
有一個引數無返回值 | (x) -> System.out.println(x) |
有且只有一個引數無返回值 | x -> System.out.println(x) |
有多個引數,有返回值,有多條lambda體語句 | (x,y) -> {System.out.println(“xxx”);return xxxx;}; |
有多個引數,有返回值,只有一條lambda體語句 | (x,y) -> xxxx |
口訣:左右遇一省括號,左側推斷型別省
注:當一個介面中存在多個抽象方法時,如果使用lambda表示式,並不能智慧匹配對應的抽象方法,因此引入了函式式介面的概念
函式式介面
函式式介面的提出是為了給Lambda表示式的使用提供更好的支援。
什麼是函式式介面?
簡單來說就是隻定義了一個抽象方法的介面(Object類的public方法除外),就是函式式介面,並且還提供了註解:@FunctionalInterface
常見的四大函式式介面
- Consumer 《T》:消費型介面,有參無返回值
<span style="color:#000000"><code> <span style="color:#9b859d !important">@Test</span>
<span style="color:#000088 !important">public</span> <span style="color:#000088 !important">void</span> <span style="color:#009900 !important">test</span>(){
changeStr(<span style="color:#009900 !important">"hello"</span>,(str) -> System.out.println(str));
}
<span style="color:#880000 !important">/**
* Consumer<T> 消費型介面
*<span style="color:#4f4f4f !important"> @param</span> str
*<span style="color:#4f4f4f !important"> @param</span> con
*/</span>
<span style="color:#000088 !important">public</span> <span style="color:#000088 !important">void</span> <span style="color:#009900 !important">changeStr</span>(String str, Consumer<String> con){
con.accept(str);
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- Supplier 《T》:供給型介面,無參有返回值
<span style="color:#000000"><code> <span style="color:#9b859d !important">@Test</span>
<span style="color:#000088 !important">public</span> <span style="color:#000088 !important">void</span> <span style="color:#009900 !important">test2</span>(){
String value = getValue(() -> <span style="color:#009900 !important">"hello"</span>);
System.out.println(value);
}
<span style="color:#880000 !important">/**
* Supplier<T> 供給型介面
*<span style="color:#4f4f4f !important"> @param</span> sup
*<span style="color:#4f4f4f !important"> @return</span>
*/</span>
<span style="color:#000088 !important">public</span> String <span style="color:#009900 !important">getValue</span>(Supplier<String> sup){
<span style="color:#000088 !important">return</span> sup.get();
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- Function 《T,R》::函式式介面,有參有返回值
<span style="color:#000000"><code> <span style="color:#9b859d !important">@Test</span>
<span style="color:#000088 !important">public</span> <span style="color:#000088 !important">void</span> <span style="color:#009900 !important">test3</span>(){
Long result = changeNum(<span style="color:#006666 !important">100</span>L, (x) -> x + <span style="color:#006666 !important">200</span>L);
System.out.println(result);
}
<span style="color:#880000 !important">/**
* Function<T,R> 函式式介面
*<span style="color:#4f4f4f !important"> @param</span> num
*<span style="color:#4f4f4f !important"> @param</span> fun
*<span style="color:#4f4f4f !important"> @return</span>
*/</span>
<span style="color:#000088 !important">public</span> Long <span style="color:#009900 !important">changeNum</span>(Long num, Function<Long, Long> fun){
<span style="color:#000088 !important">return</span> fun.apply(num);
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- Predicate《T》: 斷言型介面,有參有返回值,返回值是boolean型別
<span style="color:#000000"><code><span style="color:#000088 !important">public</span> <span style="color:#000088 !important">void</span> <span style="color:#009900 !important">test4</span>(){
<span style="color:#000088 !important">boolean</span> result = changeBoolean(<span style="color:#009900 !important">"hello"</span>, (str) -> str.length() > <span style="color:#006666 !important">5</span>);
System.out.println(result);
}
<span style="color:#880000 !important">/**
* Predicate<T> 斷言型介面
*<span style="color:#4f4f4f !important"> @param</span> str
*<span style="color:#4f4f4f !important"> @param</span> pre
*<span style="color:#4f4f4f !important"> @return</span>
*/</span>
<span style="color:#000088 !important">public</span> <span style="color:#000088 !important">boolean</span> <span style="color:#009900 !important">changeBoolean</span>(String str, Predicate<String> pre){
<span style="color:#000088 !important">return</span> pre.test(str);
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
在四大核心函式式介面基礎上,還提供了諸如BiFunction、BinaryOperation、toIntFunction等擴充套件的函式式介面,都是在這四種函式式介面上擴充套件而來的,不做贅述。
總結:函式式介面的提出是為了讓我們更加方便的使用lambda表示式,不需要自己再手動建立一個函式式介面,直接拿來用就好了,貼
方法引用
若lambda體中的內容有方法已經實現了,那麼可以使用“方法引用”
也可以理解為方法引用是lambda表示式的另外一種表現形式並且其語法比lambda表示式更加簡單
(a) 方法引用
三種表現形式:
1. 物件::例項方法名
2. 類::靜態方法名
3. 類::例項方法名 (lambda引數列表中第一個引數是例項方法的呼叫 者,第二個引數是例項方法的引數時可用)
<span style="color:#000000"><code> <span style="color:#000088 !important">public</span> <span style="color:#006666 !important">void</span> test() {
<span style="color:#880000 !important"><em>/**
*注意:
* 1.lambda體中呼叫方法的引數列表與返回值型別,要與函式式介面中抽象方法的函式列表和返回值型別保持一致!
* 2.若lambda引數列表中的第一個引數是例項方法的呼叫者,而第二個引數是例項方法的引數時,可以使用ClassName::method
*
*/</em></span>
Consumer<span style="color:#4f4f4f !important"><</span><span style="color:#4f4f4f !important">Integer</span><span style="color:#4f4f4f !important">></span> con <span style="color:#4f4f4f !important">=</span> (x) <span style="color:#4f4f4f !important">-> </span>System<span style="color:#4f4f4f !important">.</span>out<span style="color:#4f4f4f !important">.</span>println(x);
con<span style="color:#4f4f4f !important">.</span>accept(<span style="color:#006666 !important">100</span>);
<span style="color:#880000 !important"><em>// 方法引用-物件::例項方法</em></span>
Consumer<span style="color:#4f4f4f !important"><</span><span style="color:#4f4f4f !important">Integer</span><span style="color:#4f4f4f !important">></span> con2 <span style="color:#4f4f4f !important">=</span> System<span style="color:#4f4f4f !important">.</span>out<span style="color:#006666 !important">::println</span>;
con2<span style="color:#4f4f4f !important">.</span>accept(<span style="color:#006666 !important">200</span>);
<span style="color:#880000 !important"><em>// 方法引用-類名::靜態方法名</em></span>
BiFunction<span style="color:#4f4f4f !important"><</span><span style="color:#4f4f4f !important">Integer</span>, <span style="color:#4f4f4f !important">Integer</span>, <span style="color:#4f4f4f !important">Integer</span><span style="color:#4f4f4f !important">></span> biFun <span style="color:#4f4f4f !important">=</span> (x, y) <span style="color:#4f4f4f !important">-> </span><span style="color:#4f4f4f !important">Integer</span><span style="color:#4f4f4f !important">.</span>compare(x, y);
BiFunction<span style="color:#4f4f4f !important"><</span><span style="color:#4f4f4f !important">Integer</span>, <span style="color:#4f4f4f !important">Integer</span>, <span style="color:#4f4f4f !important">Integer</span><span style="color:#4f4f4f !important">></span> biFun2 <span style="color:#4f4f4f !important">=</span> <span style="color:#4f4f4f !important">Integer</span><span style="color:#006666 !important">::compare</span>;
<span style="color:#4f4f4f !important">Integer</span> result <span style="color:#4f4f4f !important">=</span> biFun2<span style="color:#4f4f4f !important">.</span>apply(<span style="color:#006666 !important">100</span>, <span style="color:#006666 !important">200</span>);
<span style="color:#880000 !important"><em>// 方法引用-類名::例項方法名</em></span>
BiFunction<span style="color:#4f4f4f !important"><</span><span style="color:#4f4f4f !important">String</span>, <span style="color:#4f4f4f !important">String</span>, Boolean<span style="color:#4f4f4f !important">></span> fun1 <span style="color:#4f4f4f !important">=</span> (str1, str2) <span style="color:#4f4f4f !important">-> </span>str1<span style="color:#4f4f4f !important">.</span><span style="color:#000088 !important">equals</span>(str2);
BiFunction<span style="color:#4f4f4f !important"><</span><span style="color:#4f4f4f !important">String</span>, <span style="color:#4f4f4f !important">String</span>, Boolean<span style="color:#4f4f4f !important">></span> fun2 <span style="color:#4f4f4f !important">=</span> <span style="color:#4f4f4f !important">String</span><span style="color:#006666 !important">::equals</span>;
Boolean result2 <span style="color:#4f4f4f !important">=</span> fun2<span style="color:#4f4f4f !important">.</span>apply(<span style="color:#009900 !important">"hello"</span>, <span style="color:#009900 !important">"world"</span>);
System<span style="color:#4f4f4f !important">.</span>out<span style="color:#4f4f4f !important">.</span>println(result2);
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
(b)構造器引用
格式:ClassName::new
<span style="color:#000000"><code><span style="color:#000088 !important">public</span> <span style="color:#000088 !important">void</span> <span style="color:#009900 !important">test2</span>() {
<span style="color:#880000 !important"><em>// 構造方法引用 類名::new</em></span>
Supplier<Employee> sup = () -> <span style="color:#000088 !important">new</span> Employee();
System.<span style="color:#000088 !important">out</span>.println(sup.<span style="color:#000088 !important">get</span>());
Supplier<Employee> sup2 = Employee::<span style="color:#000088 !important">new</span>;
System.<span style="color:#000088 !important">out</span>.println(sup2.<span style="color:#000088 !important">get</span>());
<span style="color:#880000 !important"><em>// 構造方法引用 類名::new (帶一個引數)</em></span>
Function<Integer, Employee> fun = (x) -> <span style="color:#000088 !important">new</span> Employee(x);
Function<Integer, Employee> fun2 = Employee::<span style="color:#000088 !important">new</span>;
System.<span style="color:#000088 !important">out</span>.println(fun2.apply(<span style="color:#006666 !important">100</span>));
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
(c)陣列引用
格式:Type[]::new
<span style="color:#000000"><code>public <span style="color:#000088 !important">void</span> test(){
<span style="color:#880000 !important"><em>// 陣列引用</em></span>
<span style="color:#4f4f4f !important">Function</span><Integer, <span style="color:#4f4f4f !important">String</span>[]> fun = (x) -> <span style="color:#000088 !important">new</span> <span style="color:#4f4f4f !important">String</span>[x];
<span style="color:#4f4f4f !important">Function</span><Integer, <span style="color:#4f4f4f !important">String</span>[]> fun2 = <span style="color:#4f4f4f !important">String</span>[]::<span style="color:#000088 !important">new</span>;
<span style="color:#4f4f4f !important">String</span>[] strArray = fun2.apply(<span style="color:#006666 !important">10</span>);
Arrays.stream(strArray).forEach(System.out::println);
}</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
Stream API
Stream操作的三個步驟
- 建立stream
- 中間操作(過濾、map)
- 終止操作
stream的建立:
<span style="color:#000000"><code> <span style="color:#880000 !important"><em>// 1,校驗通過Collection 系列集合提供的stream()或者paralleStream()</em></span>
List<<span style="color:#4f4f4f !important">String</span>> list = <span style="color:#000088 !important">new</span> ArrayList<>();
Strean<<span style="color:#4f4f4f !important">String</span>> stream1 = list.stream();
<span style="color:#880000 !important"><em>// 2.通過Arrays的靜態方法stream()獲取陣列流</em></span>
<span style="color:#4f4f4f !important">String</span>[] str = <span style="color:#000088 !important">new</span> <span style="color:#4f4f4f !important">String</span>[<span style="color:#006666 !important">10</span>];
Stream<<span style="color:#4f4f4f !important">String</span>> stream2 = Arrays.stream(str);
<span style="color:#880000 !important"><em>// 3.通過Stream類中的靜態方法of</em></span>
Stream<<span style="color:#4f4f4f !important">String</span>> stream3 = Stream.of(<span style="color:#009900 !important">"aa"</span>,<span style="color:#009900 !important">"bb"</span>,<span style="color:#009900 !important">"cc"</span>);
<span style="color:#880000 !important"><em>// 4.建立無限流</em></span>
<span style="color:#880000 !important"><em>// 迭代</em></span>
Stream<Integer> stream4 = Stream.iterate(<span style="color:#006666 !important">0</span>,(x) -> x+<span style="color:#006666 !important">2</span>);
<span style="color:#880000 !important"><em>//生成</em></span>
Stream.generate(() -><span style="color:#4f4f4f !important">Math</span>.random());</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
Stream的中間操作:
<span style="color:#000000"><code><span style="color:#880000 !important">/**
* 篩選 過濾 去重
*/</span>
emps.stream()
.filter(e -> e.getAge() > <span style="color:#006666 !important">10</span>)
.limit(<span style="color:#006666 !important">4</span>)
.skip(<span style="color:#006666 !important">4</span>)
<span style="color:#880000 !important"><em>// 需要流中的元素重寫hashCode和equals方法</em></span>
.distinct()
.forEach(System.out::println);
<span style="color:#880000 !important">/**
* 生成新的流 通過map對映
*/</span>
emps.stream()
.map((e) -> e.getAge())
.forEach(System.out::println);
<span style="color:#880000 !important">/**
* 自然排序 定製排序
*/</span>
emps.stream()
.sorted((e1 ,e2) -> {
<span style="color:#000088 !important">if</span> (e1.getAge().equals(e2.getAge())){
<span style="color:#000088 !important">return</span> e1.getName().compareTo(e2.getName());
} <span style="color:#000088 !important">else</span>{
<span style="color:#000088 !important">return</span> e1.getAge().compareTo(e2.getAge());
}
})
.forEach(System.out::println);
</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
Stream的終止操作:
<span style="color:#000000"><code> /**
* 查詢和匹配
* allMatch-檢查是否匹配所有元素
* anyMatch-檢查是否至少匹配一個元素
* noneMatch-檢查是否沒有匹配所有元素
* findFirst-返回第一個元素
* findAny-返回當前流中的任意元素
* count-返回流中元素的總個數
* max-返回流中最大值
* min-返回流中最小值
*/
/**
* 檢查是否匹配元素
*/
boolean b1 = emps.stream()
.allMatch<span style="color:#4f4f4f !important">((e) -> e.getStatus().equals(Employee.Status.BUSY))</span>;
<span style="color:#009900 !important">System</span>.<span style="color:#009900 !important">out</span>.<span style="color:#009900 !important">println</span><span style="color:#4f4f4f !important">(b1)</span>;
<span style="color:#009900 !important">boolean</span> <span style="color:#009900 !important">b2</span> = <span style="color:#009900 !important">emps</span>.<span style="color:#009900 !important">stream</span><span style="color:#4f4f4f !important">()</span>
.<span style="color:#009900 !important">anyMatch</span><span style="color:#4f4f4f !important">((e) -> e.getStatus().equals(Employee.Status.BUSY))</span>;
<span style="color:#009900 !important">System</span>.<span style="color:#009900 !important">out</span>.<span style="color:#009900 !important">println</span><span style="color:#4f4f4f !important">(b2)</span>;
<span style="color:#009900 !important">boolean</span> <span style="color:#009900 !important">b3</span> = <span style="color:#009900 !important">emps</span>.<span style="color:#009900 !important">stream</span><span style="color:#4f4f4f !important">()</span>
.<span style="color:#009900 !important">noneMatch</span><span style="color:#4f4f4f !important">((e) -> e.getStatus().equals(Employee.Status.BUSY))</span>;
<span style="color:#009900 !important">System</span>.<span style="color:#009900 !important">out</span>.<span style="color:#009900 !important">println</span><span style="color:#4f4f4f !important">(b3)</span>;
<span style="color:#009900 !important">Optional</span><<span style="color:#009900 !important">Employee</span>> <span style="color:#009900 !important">opt</span> = <span style="color:#009900 !important">emps</span>.<span style="color:#009900 !important">stream</span><span style="color:#4f4f4f !important">()</span>
.<span style="color:#009900 !important">findFirst</span><span style="color:#4f4f4f !important">()</span>;
<span style="color:#009900 !important">System</span>.<span style="color:#009900 !important">out</span>.<span style="color:#009900 !important">println</span><span style="color:#4f4f4f !important">(opt.get())</span>;
// 並行流
<span style="color:#009900 !important">Optional</span><<span style="color:#009900 !important">Employee</span>> <span style="color:#009900 !important">opt2</span> = <span style="color:#009900 !important">emps</span>.<span style="color:#009900 !important">parallelStream</span><span style="color:#4f4f4f !important">()</span>
.<span style="color:#009900 !important">findAny</span><span style="color:#4f4f4f !important">()</span>;
<span style="color:#009900 !important">System</span>.<span style="color:#009900 !important">out</span>.<span style="color:#009900 !important">println</span><span style="color:#4f4f4f !important">(opt2.get())</span>;
<span style="color:#009900 !important">long</span> <span style="color:#009900 !important">count</span> = <span style="color:#009900 !important">emps</span>.<span style="color:#009900 !important">stream</span><span style="color:#4f4f4f !important">()</span>
.<span style="color:#009900 !important">count</span><span style="color:#4f4f4f !important">()</span>;
<span style="color:#009900 !important">System</span>.<span style="color:#009900 !important">out</span>.<span style="color:#009900 !important">println</span><span style="color:#4f4f4f !important">(count)</span>;
<span style="color:#009900 !important">Optional</span><<span style="color:#009900 !important">Employee</span>> <span style="color:#009900 !important">max</span> = <span style="color:#009900 !important">emps</span>.<span style="color:#009900 !important">stream</span><span style="color:#4f4f4f !important">()</span>
.<span style="color:#009900 !important">max</span><span style="color:#4f4f4f !important">((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))</span>;
<span style="color:#009900 !important">System</span>.<span style="color:#009900 !important">out</span>.<span style="color:#009900 !important">println</span><span style="color:#4f4f4f !important">(max.get())</span>;
<span style="color:#009900 !important">Optional</span><<span style="color:#009900 !important">Employee</span>> <span style="color:#009900 !important">min</span> = <span style="color:#009900 !important">emps</span>.<span style="color:#009900 !important">stream</span><span style="color:#4f4f4f !important">()</span>
.<span style="color:#009900 !important">min</span><span style="color:#4f4f4f !important">((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))</span>;
<span style="color:#009900 !important">System</span>.<span style="color:#009900 !important">out</span>.<span style="color:#009900 !important">println</span><span style="color:#4f4f4f !important">(min.get())</span>;</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
還有功能比較強大的兩個終止操作 reduce和collect
reduce操作: reduce:(T identity,BinaryOperator)/reduce(BinaryOperator)-可以將流中元素反覆結合起來,得到一個值
<span style="color:#000000"><code> /**
* reduce :規約操作
*/
List<Integer> list = Arrays.asList(<span style="color:#006666 !important">1</span>,<span style="color:#006666 !important">2</span>,<span style="color:#006666 !important">3</span>,<span style="color:#006666 !important">4</span>,<span style="color:#006666 !important">5</span>,<span style="color:#006666 !important">6</span>,<span style="color:#006666 !important">7</span>,<span style="color:#006666 !important">8</span>,<span style="color:#006666 !important">9</span>,<span style="color:#006666 !important">10</span>);
Integer count2 = list.stream()
.reduce<span style="color:#4f4f4f !important">(<span style="color:#006666 !important">0</span>, (x, y) -> x + y)</span>;
<span style="color:#009900 !important">System</span>.<span style="color:#009900 !important">out</span>.<span style="color:#009900 !important">println</span><span style="color:#4f4f4f !important">(count2)</span>;
<span style="color:#009900 !important">Optional</span><<span style="color:#009900 !important">Double</span>> <span style="color:#009900 !important">sum</span> = <span style="color:#009900 !important">emps</span>.<span style="color:#009900 !important">stream</span><span style="color:#4f4f4f !important">()</span>
.<span style="color:#009900 !important">map</span><span style="color:#4f4f4f !important">(Employee::getSalary)</span>
.<span style="color:#009900 !important">reduce</span><span style="color:#4f4f4f !important">(Double::sum)</span>;
<span style="color:#009900 !important">System</span>.<span style="color:#009900 !important">out</span>.<span style="color:#009900 !important">println</span><span style="color:#4f4f4f !important">(sum)</span>;
</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
collect操作:Collect-將流轉換為其他形式,接收一個Collection介面的實現,用於給Stream中元素做彙總的方法
<span style="color:#000000"><code> <span style="color:#880000 !important">/**
* collect:收集操作
*/</span>
List<Integer> ageList = emps.stream()
.map(Employee::getAge)
.collect(Collectors.toList());
ageList.stream().forEach(System.out::println);</code></span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
並行流和序列流
在jdk1.8新的stream包中針對集合的操作也提供了並行操作流和序列操作流。並行流就是把內容切割成多個數據塊,並且使用多個執行緒分別處理每個資料塊的內容。Stream api中宣告可以通過parallel()與sequential()方法在並行流和序列流之間進行切換。
jdk1.8並行流使用的是fork/join框架進行並行操作
ForkJoin框架
Fork/Join 框架:就是在必要的情況下,將一個大任務,進行拆分(fork)成若干個小任務(拆到不可再拆時),再將一個個的小任務運算的結果進行 join 彙總。
關鍵字:遞迴分合、分而治之。
採用 “工作竊取”模式(work-stealing):
當執行新的任務時它可以將其拆分分成更小的任務執行,並將小任務加到線
程佇列中,然後再從一個隨機執行緒的佇列中偷一個並把它放在自己的佇列中
相對於一般的執行緒池實現,fork/join框架的優勢體現在對其中包含的任務的
處理方式上.在一般的執行緒池中,如果一個執行緒正在執行的任務由於某些原因
無法繼續執行,那麼該執行緒會處於等待狀態.而在fork/join框架實現中,如果
某個子問題由於等待另外一個子問題的完成而無法繼續執行.那麼處理該子
問題的執行緒會主動尋找其他尚未執行的子問題來執行.這種方式減少了執行緒
的等待時間,提高了效能.。
<span style="color:#000000"><code><span style="color:#880000 !important">/**
* 要想使用Fark—Join,類必須繼承
* RecursiveAction(無返回值)
* Or
* RecursiveTask(有返回值)
*
*/</span>
public <span style="color:#000088 !important">class</span> <span style="color:#4f4f4f !important">ForkJoin</span> <span style="color:#000088 !important">extends</span> <span style="color:#4f4f4f !important">RecursiveTask</span><<span style="color:#4f4f4f !important">Long</span>> {
<span style="color:#880000 !important">/**
* 要想使用Fark—Join,類必須繼承RecursiveAction(無返回值) 或者
* RecursiveTask(有返回值)
*
* <span style="color:#4f4f4f !important">@author</span> Wuyouxin
*/</span>
<span style="color:#000088 !important">private</span> static <span style="color:#000088 !important">final</span> long serialVersionUID = <span style="color:#006666 !important">23423422</span>L;
<span style="color:#000088 !important">private</span> long start;
<span style="color:#000088 !important">private</span> long end;
public ForkJoin() {
}
public ForkJoin(long start, long end) {
<span style="color:#000088 !important">this</span>.start = start;
<span style="color:#000088 !important">this</span>.end = end;
}
<span style="color:#880000 !important"><em>// 定義闕值</em></span>
<span style="color:#000088 !important">private</span> static <span style="color:#000088 !important">final</span> long THRESHOLD = <span style="color:#006666 !important">10000</span>L;
<span style="color:#9b859d !important">@Override</span>
<span style="color:#000088 !important">protected</span> Long compute() {
<span style="color:#000088 !important">if</span> (end - start <= THRESHOLD) {
long sum = <span style="color:#006666 !important">0</span>;
<span style="color:#000088 !important">for</span> (long i = start; i < end; i++) {
sum += i;
}
<span style="color:#000088 !important">return</span> sum;
} <span style="color:#000088 !important">else</span> {
long middle = (end - start) / <span style="color:#006666 !important">2</span>;
ForkJoin left = <span style="color:#000088 !important">new</span> ForkJoin(start, middle);
<span style="color:#880000 !important"><em>//拆分子任務,壓入執行緒佇列</em></span>
left.fork();
ForkJoin right = <span style="color:#000088 !important">new</span> ForkJoin(middle + <span style="color:#006666 !important">1</span>, end);
right.fork();
<span style="color:#880000 !important"><em>//合併並返回</em></span>
<span style="color:#000088 !important">return</span> left.join() + right.join();
}
}
<span style="color:#880000 !important">/**
* 實現數的累加
*/</span>
<span style="color:#9b859d !important">@Test</span>
public void test1() {
<span style="color:#880000 !important"><em>//開始時間</em></span>
Instant start = Instant.now();
<span style="color:#880000 !important"><em>//這裡需要一個執行緒池的支援</em></span>
ForkJoinPool pool = <span style="color:#000088 !important">new</span> ForkJoinPool();
ForkJoinTask<Long> task = <span style="color:#000088 !important">new</span> ForkJoin(<span style="color:#006666 !important">0</span>L, <span style="color:#006666 !important">10000000000</span>L);
<span style="color:#880000 !important"><em>// 沒有返回值 pool.execute();</em></span>
<span style="color:#880000 !important"><em>// 有返回值</em></span>
long sum = pool.invoke(task);
<span style="color:#880000 !important"><em>//結束時間</em></span>
Instant end = Instant.now();
System.out.println(Duration.between