序言
面試官經常會問到新版JDK新的特性, 尤其是JDK8的特性。
下面將首先講解JDK版本發佈情況,概括性介紹JDK8的主要新的特徵。
主要包括:
- 新的語言特性
- 集合對象的修改
- JVM新特性
- HashMap的修改
關注“”非典型理科男“”公衆號, 回覆 jdk文檔 獲取JDK官方文檔合集。
爲什麼面試經常問JDK8新的特性
JDK8是2014年3月發行版本, 面試官會在面試中問JDK8的一些新的特性。
Java從已經從JDK1.0版本發展到了最新的JDK13, 爲什麼目前Jdk8經常被問到呢?
大概有一些原因:
第一、JDK8仍然是最受歡迎的JDK版本。
從skyn網站的《2018年JVM生態報告》中可以看到截止到2018年, JDK8仍然是生成環境使用最多的JDK版本。
第二、新的發版週期,讓很多公司無所適從。JDK9非LTS版本。
JDK8之後Oracle使用了新的發佈週期。
從JDK版本歷史發行看, Oracle從Java9開始實行了新的版本發佈規則,縮短了新版本發佈週期。
JDK1.6到JDK1.7經過了5年的時間
JDK1.7到JDK1.8經過了3年
JDK1.8到JDK1.9經過了3年
之後的版本 每6個月發佈一個版本
每3年發佈一個LTS版本(最新的LTS版本是JDK11)
幾乎 三分之一 的開發人員還不知道他們將如何應對新的發佈週期。
第三、JDK8 引入了很多非常實用和長期的影響
- JDK8引入新的語法特性,比如Lambda表達式,默認方法,方法引用,新增新的日期處理類
- JDK8爲Collection新增Stream流式接口, 修改HashMap和ConcurrentHashMap實現
- JDK8修改了JVM內存模型, 實用metaSpace代替永久代
- JDK新增併發接口和實現, 包括新增CompletableFuture、爲ConcurrentHashMap新增支持Stream方法、新增StampedLock
下面介紹幾個面試過程經常被問到的幾個新特性
Lambda表達式、方法引用和默認方法
1. Lambda表達式
Lambda表達式允許把函數作爲一個方法的參數。
有幾種常見的Lambda表達式:
// 1. 不需要參數,返回值爲 5
() -> 5
// 2. 接收一個參數(數字類型),返回其2倍的值
x -> 2 * x
// 3. 接受2個參數(數字),並返回他們的差值
(x, y) -> x – y
// 4. 接收2個int型整數,返回他們的和
(int x, int y) -> x + y
// 5. 接受一個 string 對象,並在控制檯打印,不返回任何值(看起來像是返回void)
(String s) -> System.out.print(s)
2. 方法引用
JDK8支持了四種方式方法引用
類型 | 方法引用 |
---|---|
引用靜態方法 | ContainingClass::staticMethodName |
引用特定對象的實例方法 | containingObject::instanceMethodName |
引用特定類型的任意對象的實例方法 | String::compareToIngoreCase |
引用構造函數 | ClassName::new |
3. 默認方法和靜態方法
JDK1.8支持在接口中定義默認方法和靜態方法, 默認方法可以被接口實現引用。
package defaultmethods;
import java.time.*;
public interface TimeClient {
void setTime(int hour, int minute, int second);
void setDate(int day, int month, int year);
void setDateAndTime(int day, int month, int year,
int hour, int minute, int second);
LocalDateTime getLocalDateTime();
// 靜態方法
static ZoneId getZoneId (String zoneString) {
try {
return ZoneId.of(zoneString);
} catch (DateTimeException e) {
System.err.println("Invalid time zone: " + zoneString +
"; using default time zone instead.");
return ZoneId.systemDefault();
}
}
// 默認方法
default ZonedDateTime getZonedDateTime(String zoneString) {
return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
}
}
Colletion的修改
JDK1.8增強了Collection FrameWork, 支持了lambda, 流和聚合操作。
改動有兩個方面:
- 支持了lambda, 流和聚合操作
- 改進的類型推斷
改進的類型推斷
Java編譯器利用目標類型來推斷通用方法調用的類型參數。
考慮以下示例:
List <String> stringList = new ArrayList <>();
stringList.add("A");
stringList.addAll(Arrays.asList());
Java管理擴展(JMX)提供了對診斷命令的遠程訪問。
目前,不考慮泛型,該方法addAll將Collection實例作爲其參數,然後該方法Arrays.asList返回一個List實例。這是有效的,因爲List是的子類型Collection。
現在考慮泛型,的目標類型addAll爲Collection<? extends String>,並Arrays.asList返回一個List實例。在此示例中,Java SE 8編譯器可以推斷類型變量的T值爲String。編譯器從目標類型推斷出這一點Collection<? extends String>。
Java SE 7和更早版本的編譯器不接受此代碼,因爲它們不使用目標類型來推斷方法調用參數的類型。例如,Java SE 7編譯器生成類似於以下內容的錯誤消息:
error: no suitable method found for addAll(List<Object>) ...
method List.addAll(Collection<? extends String>) is not applicable (actual argument List<Object> cannot be converted to Collection<? extends String> by method invocation conversion)
因此,在Java編譯器無法推斷類型的情況下,必須使用顯式指定類型變量的值。例如,以下在Java SE 7中有效:
List <String> stringList = new ArrayList <>();
stringList.add(“ A”);
stringList.addAll(Arrays.<String> asList());
JVM新特性
JDK8在JVM中修改重要有:
- 新增JVM工具:jdeps提供了用於分析類文件的命令行工具。
- 使用metaSpace代替永久區
- 新增NMT(Native Memeory Trace)本地內存跟蹤器,參見NMT
HashMap變化
JDK8優化了HashMap的實現, 主要優化點包括:
- 將鏈表方式修改成鏈表或者紅黑樹的形式
- 修改resize的過程,解決JDK7在resize在併發場景下死鎖的隱患
- JDK1.7存儲使用Entry數組, JDK8使用Node或者TreeNode數組存儲
當鏈表長度大於8是鏈表的存儲結構會被修改成紅黑樹的形式。
查詢效率從O(N)提升到O(logN)。鏈表長度小於6時,紅黑樹的方式退化成鏈表。
JDK7鏈表插入是從鏈表頭部插入, 在resize的時候會將原來的鏈表逆序。
JDK8插入從鏈表尾部插入, 因此在resize的時候仍然保持原來的順序。
👁 關注微信公衆號:非典型理科男 回覆:JDK文檔 獲取JDK官方文檔。