JAVA8新特性

一蜂挪、重要數(shù)據(jù)結(jié)構(gòu)和JVM的改動

1.HashMap的改動

HashMap維護了一個Entry數(shù)組,put(K key,V value)元素到HashMap中時通過key的hash碼計算其在數(shù)組中的索引位置,若索引位置上已有元素形成哈希碰撞.

jdk1.8之前的HashMap

jdk1.8以前:哈希碰撞之后,在碰撞位置將會形成一個鏈表,新加入的元素將放置于表頭位置(明顯缺點:當碰撞元素過多,鏈表過長,遍歷鏈表查找元素的速度就較慢)

jdk1.7關鍵代碼:

public V put(K key, V value) {

? ? if (table == EMPTY_TABLE) {

? ? ? ? inflateTable(threshold);

? ? }

? ? //若key為null,則特殊處理一下(放到數(shù)組索引為0的位置)

? ? if (key == null)

? ? ? ? return putForNullKey(value);

? ? //計算key在數(shù)組中對應的索引值

? ? int hash = hash(key);

? ? int i = indexFor(hash, table.length);

? ? //遍歷索引位置上的鏈表,若找到匹配key,則將新值賦給該節(jié)點,并返回舊值

? ? for (Entry e = table[i]; e != null; e = e.next) {

? ? ? ? Object k;

? ? ? ? if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

? ? ? ? ? ? ? ?V oldValue = e.value;

? ? ? ? ? ? ? ?e.value = value;

? ? ? ? ? ? ? ?e.recordAccess(this);

? ? ? ? ? ? ? ?return oldValue;

? ? ? ? }

? ? }

? ? //若沒有匹配的已存在的key,則在索引位置對應的鏈表上新增節(jié)點,next指向原鏈表的表頭元素

? ? modCount++;

? ? addEntry(hash, key, value, i);

? ? return null;

}

void addEntry(int hash, K key, V value, int bucketIndex) {

? ? if ((size >= threshold) && (null != table[bucketIndex])) {

? ? ? ? resize(2 * table.length);

? ? ? ? hash = (null != key) ? hash(key) : 0;

????????bucketIndex = indexFor(hash, table.length);

????}

????createEntry(hash, key, value, bucketIndex);

}

void createEntry(int hash, K key, V value, int bucketIndex) {

????Entry e = table[bucketIndex];

????table[bucketIndex] = new Entry<>(hash, key, value, e);

????size++;

}

jdk1.8:(a)新加入的元素將置于鏈表的尾部;(b)當鏈表元素達到8個時,此鏈表將轉(zhuǎn)換為紅黑樹 ,優(yōu)點:HashMap的查詢效率在jdk1.8中得到了大大的提升

jdk1.8關鍵代碼:

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {

????Node[] tab; Node p; int n, i;

????//若map中的tab數(shù)組為空,則先初始化數(shù)組

????if ((tab = table) == null || (n = tab.length) == 0)

????????n = (tab = resize()).length;

????//若tab數(shù)組中,當前元素hash值對應的索引位置上為null,則直接將元素置于該位置

????if ((p = tab[i = (n - 1) & hash]) == null)

????????tab[i] = newNode(hash, key, value, null);

????else {

????????Node e; K k;

????????//若元素與鏈表第一個元素的hash值和key值均相等,則直接將value賦給該元素

????????if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))

????????????e = p;

????????????//若當前位置是一個樹節(jié)點(說明已經(jīng)轉(zhuǎn)為紅黑樹了),則挨個與樹節(jié)點比較,若hash和key與某個節(jié)點相等則,則將value賦給該節(jié)點,否則新增一個樹節(jié)點

? ? ? ? else if (p instanceof TreeNode)

????????????e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);

????????else {

????????????//挨個遍歷鏈表中元素,若hash和key匹配,則找到匹配的元素

????????????for (int binCount = 0; ; ++binCount) {

????????????????if ((e = p.next) == null) {

????????????????????//若遍歷到表尾仍然沒有找到,則在尾部新增一個元素

????????????????????p.next = newNode(hash, key, value, null);

????????????????????//若元素個數(shù)達到8個,則將鏈表轉(zhuǎn)成紅黑樹

? ? ? ? ? ? ? ? ? ? if (binCount >= TREEIFY_THRESHOLD - 1)?

? ? ? ? ? ? ? ? ? ? ? ? treeifyBin(tab, hash);

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))

? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? ? ? p = e;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? if (e != null) {?

? ? ? ? ? ? ? ? V oldValue = e.value;

? ? ? ? ? ? ? ? if (!onlyIfAbsent || oldValue == null)

? ? ? ? ? ? ? ? ? ? e.value = value;

? ? ? ? ? ? ? ? ? ? afterNodeAccess(e);

? ? ? ? ? ? ? ? ? ? return oldValue;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

????????++modCount;

????????if (++size > threshold)

????????????resize();

????????afterNodeInsertion(evict);

????????return null;

}

2.JVM運行時數(shù)據(jù)區(qū)

JVM運行時數(shù)據(jù)區(qū)去掉永久代(Permanent Generation ),改為元空間(MetaSpace)。

jdk1.8之前的JVM運行時數(shù)據(jù)區(qū):

jdk1.8之前的運行時數(shù)據(jù)區(qū)

方法區(qū)即永久代(Method Area): 所有線程共享讼呢,用于存儲JVM加載的類信息、常量谦炬、靜態(tài)變量悦屏、JIT編譯器編譯后的代碼等數(shù)據(jù)。它只是JVM規(guī)范中定義的一個概念,是堆的一個邏輯部分础爬,為了與普通堆區(qū)分開來散劫,有一個別名叫做Non-Heap(非堆)。

jdk1.8及以后幕帆,永久代被移除,取而代之的是元空間赖条,它直接從操作系統(tǒng)分配內(nèi)存失乾,獨立且可以自由擴展,最大可分配空間就是系統(tǒng)可用空間纬乍,因此不會遇到PermGen的內(nèi)存溢出錯誤(java.lang.OutOfMemoryError: PermGen space)碱茁。在JVM參數(shù)方面,使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize代替原來的-XX:PermSize和-XX:MaxPermSize仿贬。

二纽竣、關于接口的變動

1、default關鍵字

Jdk1.8新增了一個關鍵字default,用于修飾接口中的非抽象方法,只能通過接口實現(xiàn)類的對象進行調(diào)用

2茧泪、static方法

Jdk1.8允許在接口中定義static方法,調(diào)用方式必須為:接口名.方法名()

3蜓氨、函數(shù)式接口

Jdk1.8提出了一個”函數(shù)式接口”的概念:只有一個抽象方法的接口稱為函數(shù)式接口,可使用@FunctionalInterface注解進行檢查(此注解只是用來檢查是否是函數(shù)式接口,并不是說,加了此注解的接口是函數(shù)式接口,如果加了此注解,接口中有多個抽象方法將會編譯報錯)。常見的函數(shù)式接口:Runnable队伟,Comparator等

三穴吹、Optional容器類

Optional 類(java.util.Optional) 是一個容器類,代表一個值存在或不存在嗜侮,原來用 null 表示一個值不存在港令,現(xiàn)在 Optional 可以更好的表達這個概念。并且可以避免空指針異常锈颗。

常用方法:

Optional.of(T t) : 創(chuàng)建一個 Optional 實例

Optional.empty() : 創(chuàng)建一個空的 Optional 實例

Optional.ofNullable(T t):若 t 不為 null,創(chuàng)建 Optional 實例,否則創(chuàng)建空實例

isPresent() : 判斷是否包含值

orElse(T t) : 如果調(diào)用對象包含值顷霹,返回該值,否則返回t

orElseGet(Supplier s) :如果調(diào)用對象包含值击吱,返回該值淋淀,否則返回 s 獲取的值

map(Function f): 如果有值對其處理,并返回處理后的Optional姨拥,否則返回 Optional.empty()

flatMap(Function mapper):與 map 類似绅喉,要求返回值必須是Optional

四、Lambda表達式

Lambda表達式是對函數(shù)式接口中抽象方法的實現(xiàn)的簡寫方式.

1.? ? 分析Lambda表達式的結(jié)構(gòu)及常規(guī)寫法

格式:? ()->? {}

操作符“->”被稱為 Lambda 操作符或箭頭操作符叫乌。它將 Lambda 分為兩個部分:

左側(cè): 指定了 Lambda 表達式需要的所有參數(shù)

右側(cè): 指定了 Lambda 體柴罐,即 Lambda 表達式要執(zhí)行的功能。

語法格式一:無參數(shù)憨奸,無返回值

() -> System.out.println("Hello Lambda!");

語法格式二:有一個參數(shù)革屠,并且無返回值

(x) -> System.out.println(x)

語法格式三:有兩個以上的參數(shù),有返回值,并且 Lambda 體中有多條語句

Comparator com = (x, y) -> {

System.out.println("函數(shù)式接口");

return Integer.compare(x, y);

};

語法格式四:

(1).Lambda 表達式的參數(shù)列表的數(shù)據(jù)類型可以省略不寫似芝,jdk1.7引入的“類型推斷”機制在jdk1.8得到了強化(注意:若不寫,都不寫)

(2).若只有一個參數(shù)那婉,小括號可以省略不寫

(3).若 Lambda 體中只有一條語句, return 和 大括號都可以省略不寫

2.? ? jdk1.8內(nèi)置的一些函數(shù)式接口

Lambda是基于函數(shù)式接口的,難道使用lambda表達式還必須要寫一個函數(shù)式接口?當然不是! jdk開發(fā)人員想到了這個問題.

Jdk提供了一些函數(shù)式接口:四大核心接口,N個擴展接口位于java.util.function包下.

四大核心函數(shù)式接口:

(1)? ? 消費型接口Comsumer:有一個參數(shù)無返回值的抽象方法,參數(shù)類型T

(2)? ? 供給型接口Supplier:無參數(shù)有返回值的抽象方法,返回值類型T

(3)? ? 函數(shù)型接口Function:一個參數(shù)有返回值的抽象方法,參數(shù)類型T,返回值類型R

(4)? ? 斷言型接口Predicate:一個參數(shù)有返回值的抽象方法,參數(shù)類型T,返回值類型boolean

五党瓮、方法引用和構(gòu)造器引用

1.方法引用

當要傳遞給Lambda體的操作详炬,已經(jīng)有實現(xiàn)的方法了,可以使用方法引用D椤(實現(xiàn)抽象方法的參數(shù)列表呛谜,必須與方法引用方法的參數(shù)列表保持一致!)

方法引用:使用操作符 “::” 將方法名和對象或類的名字分隔開來

例如:

Lambda表達式:? x->System.out.println(x);

等同于:

方法引用(實例名::實例方法名):? ? System.out::println;

Lambda表達式:? t -> Integer.parseInt(t);

等同于

方法引用(類名::類方法名):? Integer::parseInt;

Lambda表達式:? (x, y) -> x.equals(y);

等同于

方法引用(類名::類方法名):? String::equals;

方法引用的判斷規(guī)則:

(1)方法引用所引用的方法的參數(shù)列表與返回值類型枪萄,需要與函數(shù)式接口中抽象方法的參數(shù)列表和返回值類型保持一致隐岛!

(2)若Lambda 的參數(shù)列表的第一個參數(shù),是實例方法的調(diào)用者瓷翻,第二個參數(shù)(或無參)是實例方法的參數(shù)時聚凹,格式: ClassName::MethodName

2.構(gòu)造器引用(例子: MyTestMethodRef.java)

構(gòu)造器的參數(shù)列表,需要與函數(shù)式接口中參數(shù)列表保持一致齐帚!

格式: 類名::new

六妒牙、Stream API

1、Stream簡介

Stream 是 Java8 中處理集合的關鍵抽象概念童谒,它可以指定你希望對集合進行的操作单旁,可以執(zhí)行非常復雜的查找、過濾和映射數(shù)據(jù)等操作饥伊。使用Stream API 對集合數(shù)據(jù)進行操作象浑,就類似于使用 SQL 執(zhí)行數(shù)據(jù)庫查詢。也可以使用 Stream API 來并行執(zhí)行操作琅豆。簡而言之愉豺,Stream API 提供了一種高效且易于使用的處理數(shù)據(jù)的方式。

注意:

(1)Stream 自己不會存儲元素茫因。

(2)Stream 不會改變源對象蚪拦。相反,他們會返回一個持有結(jié)果的新Stream冻押。

(3)Stream 操作是延遲執(zhí)行的驰贷。這意味著他們會等到需要結(jié)果的時候才執(zhí)行。

2洛巢、創(chuàng)建stream: 通過一個數(shù)據(jù)源(如: 集合括袒、數(shù)組), 獲取一個流

(1)? ? Java8 中的 Collection 接口被擴展稿茉,提供了兩個獲取流的方法:

default? Stream? stream() : 返回一個順序流

default? Stream? parallelStream() : 返回一個并行流

(2)? ? Java8 中的 Arrays 的靜態(tài)方法 stream() 可以獲取數(shù)組流:

public? static? ? Stream? stream(T[] array): 返回一個流

public? static? IntStream? stream(int[] array)

public? static? LongStream? stream(long[] array)

public? static? DoubleStream? stream(double[] array)

(3)? ? 可以使用靜態(tài)方法 Stream.of(), 通過顯示值創(chuàng)建一個流锹锰。它可以接收任意數(shù)量的參數(shù)芥炭。

public? static? Stream? of(T... values) : 返回一個流

3、中間操作: 一個中間操作鏈恃慧,對數(shù)據(jù)源的數(shù)據(jù)進行處理

多個中間操作可以連接起來形成一個流水線园蝠,除非流水線上觸發(fā)終止操作,否則中間操作不會執(zhí)行任何的處理痢士!而在終止操作時一次性全部處理彪薛,稱為“惰性求值” 。(例子: MyTestStream3.test1()).

(1)? ? 篩選與切片

filter(Predicate? p): 過濾,從流中過濾出符合條件的元素,接收一個斷言型Lambda

distinct(): 去重復,根據(jù)流中元素的hashCode()和equals()方法去除流中的重復元素

limit(long? maxSize): 截斷流,使其元素不超過給定數(shù)量

skip(long? n): 跳過元素怠蹂,返回一個扔掉了前 n 個元素的流陪汽。若流中元素不足 n 個,則返回一個空流褥蚯。與 limit(n) 互補

(2)? ? 映射

map(Function f): 接收一個函數(shù)作為參數(shù),該函數(shù)會被應用到每個元素上况增,并將其映射成一個新的元素赞庶。

(3)? ? 排序

sorted(): 產(chǎn)生一個新流,其中按自然順序排序

sorted(Comparator? comp): 產(chǎn)生一個新流澳骤,其中按比較器順序排序

4歧强、終止操作: 一個終止操作,執(zhí)行中間操作鏈为肮,并產(chǎn)生結(jié)果

(1)查找與匹配

allMatch(Predicate p): 檢查是否匹配所有元素

anyMatch(Predicate p): 檢查是否至少匹配一個元素

noneMatch(Predicate p): 檢查是否沒有匹配所有元素

findFirst(): 返回第一個元素

findAny(): 返回流中的任意元素

count(): 返回流中的元素總數(shù)

max(Comparator? c): 返回流中最大值

min(Comparator? c): 返回流中最小值

forEach(Consumer? c): 內(nèi)部迭代

(2)規(guī)約

reduce(T? iden,BinaryOperator? b): 可以將流中元素反復結(jié)合起來摊册,得到一個值。返回 T

reduce(BinaryOperator? b): 可以將流中元素反復結(jié)合起來颊艳,得到一個值茅特。返回 Optional

(3)收集

collect(Collector? c): 將流轉(zhuǎn)換為其他形式。接收一個 Collector接口的實現(xiàn)棋枕,用于給Stream中元素做匯總的方法, Collectors提供了豐富的靜態(tài)方法供我們使用


七白修、新的時間日期API(java.time.*包)?

Jdk1.8之前的時間日期API的缺陷:

1.Java的日期/時間類的定義不一致,在java.util和java.sql的包中都有日期類重斑,此外用于格式化和解析的類在java.text包中定義兵睛。

2.java.util.Date同時包含日期和時間,而java.sql.Date僅包含日期窥浪,將其納入java.sql包并不合理祖很。另外這兩個類都有相同的名字,這本身就是一個非常糟糕的設計漾脂。

3.所有的日期類都是可變的假颇,因此他們都不是線程安全的,這是Java日期類最大的問題之一符相。

4.日期類并不提供國際化拆融,沒有時區(qū)支持蠢琳,因此Java引入了java.util.Calendar和java.util.TimeZone類,但他們同樣存在上述所有的問題镜豹。

5.計算兩個日期時間之間的間隔比較麻煩,因此出現(xiàn)了一個joda-time.jar.

Jdk1.8新的時間日期API解決了上述問題

1. 使用 LocalDate傲须、 LocalTime、 LocalDateTime

LocalDate趟脂、 LocalTime泰讽、 LocalDateTime 類的實例是不可變的對象,分別表示使用ISO-8601日歷系統(tǒng)(ISO-8601日歷系統(tǒng)是國際標準化組織制定的現(xiàn)代公民的日期和時間的表示法)的日期昔期、時間已卸、日期和時間。

2. Duration 和 Period

(1) Duration:用于計算兩個“時間”間隔

(2) Period:用于計算兩個“日期”間隔

3. 解析與格式化

java.time.format.DateTimeFormatter 類

4. 按照指定時區(qū)獲取時間

> PS:JDK1.8的新特性還有很多,這里只是簡要介紹了一些我們平時經(jīng)常接觸到的.還有其他的需要自己去深入學習一下!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末硼一,一起剝皮案震驚了整個濱河市累澡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌般贼,老刑警劉巖愧哟,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異哼蛆,居然都是意外死亡蕊梧,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進店門腮介,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肥矢,“玉大人,你說我怎么就攤上這事叠洗「矢模” “怎么了?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵灭抑,是天一觀的道長楼誓。 經(jīng)常有香客問我,道長名挥,這世上最難降的妖魔是什么疟羹? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮禀倔,結(jié)果婚禮上榄融,老公的妹妹穿的比我還像新娘。我一直安慰自己救湖,他們只是感情好愧杯,可當我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鞋既,像睡著了一般力九。 火紅的嫁衣襯著肌膚如雪耍铜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天跌前,我揣著相機與錄音棕兼,去河邊找鬼。 笑死抵乓,一個胖子當著我的面吹牛伴挚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播灾炭,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼茎芋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蜈出?” 一聲冷哼從身側(cè)響起田弥,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎铡原,沒想到半個月后皱蹦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡眷蜈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了沈自。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酌儒。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖枯途,靈堂內(nèi)的尸體忽然破棺而出忌怎,到底是詐尸還是另有隱情,我是刑警寧澤酪夷,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布榴啸,位于F島的核電站,受9級特大地震影響晚岭,放射性物質(zhì)發(fā)生泄漏鸥印。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一坦报、第九天 我趴在偏房一處隱蔽的房頂上張望库说。 院中可真熱鬧,春花似錦片择、人聲如沸潜的。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽啰挪。三九已至信不,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間亡呵,已是汗流浹背抽活。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留政己,地道東北人酌壕。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像歇由,于是被迫代替她去往敵國和親卵牍。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,876評論 2 361

推薦閱讀更多精彩內(nèi)容

  • Java 8自Java 5(發(fā)行于2004)以來最具革命性的版本沦泌。Java 8 為Java語言糊昙、編譯器、類庫谢谦、開發(fā)...
    誰在烽煙彼岸閱讀 891評論 0 4
  • Java 8自Java 5(發(fā)行于2004)以來最具革命性的版本释牺。Java 8 為Java語言、編譯器回挽、類庫没咙、開發(fā)...
    huoyl0410閱讀 640評論 1 2
  • 原創(chuàng)文章&經(jīng)驗總結(jié)&從校招到A廠一路陽光一路滄桑 詳情請戳www.codercc.com 對于Java開發(fā)者來說,...
    你聽___閱讀 2,342評論 4 38
  • Java8新特性 Lambda表達式 概念 lambda表達式是一段可以傳遞的代碼千劈,它的核心思想是將面向?qū)ο笾械膫?..
    好好秦先生閱讀 842評論 0 1
  • 幼兒園水平……手動哭泣
    抱著蘿卜的小白兔閱讀 302評論 2 3