JDK1.8新特性總結

duoduo18up發表於2018-08-07

背景:

因為面試被問到了,而且一直以來想去深入瞭解一下JDK 1.8的新特性 。才發現其實好多已經用在了專案中,自己沒能察覺,所以總結一下,方便後期使用,以及加深理解。

 

主要有幾點:

一. JCF 集合中   :

+紅黑樹 (詳細見 hashmap原始碼分析)-----------更快速

 

在jdk1.8中對hashMap等map集合的資料結構優化。
原來的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表示式,Java8新增了java.util.funcion包,裡面包含常用的函式介面,這是Lambda表示式的基礎,Java集合框架也新增部分介面,以便與Lambda表示式對接。lambda表示式本質上是一段匿名內部類,也可以是一段可以傳遞的程式碼

 

首先回顧一下Java集合框架的介面繼承結構:

JCF_Collection_Interfaces

 

下表詳細列舉了這些方法。

介面名 Java8新加入的方法
Collection removeIf() spliterator() stream() parallelStream() forEach()
List replaceAll() sort()
Map getOrDefault() forEach() replaceAll() putIfAbsent() remove() replace() computeIfAbsent() computeIfPresent() compute() merge()

這些新加入的方法大部分要用到java.util.function包下的介面

 

 

Collection中的新方法:

JDK1.8 集合新特性

舉例:

Java 7 中 ArrayList底層原始碼解析

原  增強的for迴圈 

需求:假設有一個字串列表,需要列印出其中所有長度大於3的字串.


ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
for(String str : list){
    if(str.length()>3)
        System.out.println(str);

新   forEach()  +匿名內部類

// 使用forEach()結合匿名內部類迭代
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
list.forEach(new Consumer<String>(){
    @Override
    public void accept(String str){
        if(str.length()>3)
            System.out.println(str);
    }
});

                       +Lambda表示式

// 使用forEach()結合Lambda表示式迭代
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
list.forEach( str -> {
        if(str.length()>3)
            System.out.println(str);
    });

forEach()方法傳入一個Lambda表示式,我們不需要知道accept()方法,也不需要知道Consumer介面,型別推導幫我們做了一切。

 

 

Map中的新方法

相比CollectionMap中加入了更多的方法,我們以HashMap為例來逐一探祕。瞭解Java7HashMap實現原理,將有助於理解下文。

 

需求:假設有一個數字到對應英文單詞的Map,請輸出Map中的所有對映關係.

Java7以及之前經典的程式碼如下:

// Java7以及之前迭代Map
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
for(Map.Entry<Integer, String> entry : map.entrySet()){
    System.out.println(entry.getKey() + "=" + entry.getValue());
}

之後:

HashMap<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
map.forEach((k, v) -> System.out.println(k + "=" + v));
}

更多方法細節請參照 JDK1.8 集合新特性

lambda表示式規範及Java8中的四大核心函式式介面  請看lambda表示式

 

總結

  1. Java8為容器新增一些有用的方法,這些方法有些是為完善原有功能,有些是為引入函數語言程式設計,學習和使用這些方法有助於我們寫出更加簡潔有效的程式碼.
  2. 函式介面雖然很多,但絕大多數時候我們根本不需要知道它們的名字,書寫Lambda表示式時型別推斷幫我們做了一切

 

 

二.介面

介面中可以定義預設實現方法和靜態方法

在介面中可以使用default和static關鍵字來修飾介面中定義的普通方法

public interface Interface {
    default  String getName(){
        return "zhangsan";
    }

    static String getName2(){
        return "zhangsan";
    }
}

在JDK1.8中很多介面會新增方法。

為了保證1.8向下相容,1.7版本中的介面實現類不用每個都重新實現新新增的介面方法,引入了default預設實現。

static的用法是直接用介面名去調方法即可。

當一個類繼承父類又實現介面時,若後兩者方法名相同,則優先繼承父類中的同名方法,即“類優先”,如果實現兩個同名方法的介面,則要求實現類必須手動宣告預設實現哪個介面中的方法。

 

 

三.並行流和序列流

在jdk1.8新的stream包中針對集合的操作也提供了並行操作流和序列操作流。並行流就是把內容切割成多個資料塊,並且使用多個執行緒分別處理每個資料塊的內容。Stream api中宣告可以通過parallel()與sequential()方法在並行流和序列流之間進行切換。 
jdk1.8並行流使用的是fork/join框架進行並行操作

ForkJoin框架

Fork/Join 框架:就是在必要的情況下,將一個大任務,進行拆分(fork)成若干個小任務(拆到不可再拆時),再將一個個的小任務運算的結果進行 join 彙總。 
關鍵字:遞迴分合、分而治之。 
採用 “工作竊取”模式(work-stealing): 
當執行新的任務時它可以將其拆分分成更小的任務執行,並將小任務加到線 程佇列中,然後再從一個隨機執行緒的佇列中偷一個並把它放在自己的佇列中 。


相對於一般的執行緒池實現,fork/join框架的優勢體現在對其中包含的任務的 處理方式上.在一般的執行緒池中,如果一個執行緒正在執行的任務由於某些原因 無法繼續執行,那麼該執行緒會處於等待狀態.而在fork/join框架實現中,如果 
某個子問題由於等待另外一個子問題的完成而無法繼續執行.那麼處理該子 問題的執行緒會主動尋找其他尚未執行的子問題來執行.這種方式減少了執行緒 的等待時間,提高了效能.。

 

相關文章