java5、java6、java7、java8、java9新特性
1. 介紹
JAVA作為使用的主力語言,掌握下其歷史發展也是有必要的。看看從JAVA5開始到現在的JAVA9有哪些變化。藉此機會,也可以看看哪些特性我們是已經用到的,哪些是還沒有用到的。
我們在IDEA裡面也可以看到language level裡面的資訊,這裡也大致寫了下各個版本JDK的新特性。
簡單概括下就是:
- JAVA1.3:普通的原始的JAVA,基本語法相信大家都見過了
- JAVA1.4:assert關鍵字
- JAVA5:列舉型別、泛型、自動拆裝箱
- JAVA6: @Override註解
- JAVA7: <>符號、ARM支援、支援多catch
- JAVA8:Lamda表示式,型別註解等
- JAVA9: 模組化、介面中的私有方法等
下面我們更加詳細的分析下各個版本有哪些新特性。
2. JAVA5新特性
2.1 泛型 Generics
引用泛型之後,允許指定集合裡元素的型別,免去了強制型別轉換,並且能在編譯時刻進行型別檢查的好處。Parameterized Type作為引數和返回值,Generic是vararg、annotation、enumeration、collection的基石。
泛型可以帶來如下的好處總結如下:
- 型別安全:拋棄List、Map,使用List、Map給它們新增元素或者使用Iterator遍歷時,編譯期就可以給你檢查出型別錯誤
- 方法引數和返回值加上了Type: 拋棄List、Map,使用List、Map
- 不需要型別轉換:List list=new ArrayList();
- 型別萬用字元“?”: 假設一個列印List中元素的方法printList,我們希望任何型別T的List都可以被列印
2.2 列舉型別
引入了列舉型別
2.3 自動裝箱拆箱(自動型別包裝和解包)autoboxing & unboxing
簡單的說是型別自動轉換。自動裝包:基本型別自動轉為包裝類(int ——Integer)自動拆包:包裝類自動轉為基本型別(Integer——int)
2.4 可變引數varargs(varargs number of arguments)
引數型別相同時,把過載函式合併到一起了。如:
-
public void test(object... objs){
-
for(Object obj:objs){
-
System.out.println(obj);
-
}
-
}
2.5 Annotations(重要) 它是java中的metadata(註釋)
註解在JAVA5中就引入了。這是非常重要的特性。現在註解的應用已經隨處可見。不過JAVA5的註解還不成熟,沒法自定義註解。
2.6 新的迭代語句
-
for(int n:numbers){
-
//process
-
}
2.7 靜態匯入(import static )
匯入靜態物件,可以省略些程式碼。不過這個也不常用。
-
import static java.lang.System.out;//匯入java.lang包下的System類的靜態方法out;
-
public class HelloWorld{
-
public static void main(String[] args){
-
out.print("Hello World!");//既是在這裡不用再寫成System.out.println("Hello World!")了,因為已經匯入了這個靜態方法out。
-
}
-
}
2.8 新的格式化方法(java.util.Formatter)
formatter.format("Remaining account balance: $%.2f", balance);
2.9 新的執行緒模型和併發庫Thread Framework(重要)
最主要的就是引入了java.util.concurrent包,這個都是需要重點掌握的。
HashMap的替代者ConcurrentHashMap和ArrayList的替代者CopyOnWriteArrayList在大併發量讀取時採用java.util.concurrent包裡的一些類會讓大家滿意BlockingQueue、Callable、Executor、Semaphore
3. JAVA6
JAVA6當中
3.1 Web Services
優先支援編寫 XML web service 客戶端程式。你可以用過簡單的annotaion將你的API釋出成.NET互動的web services. Mustang 添加了新的解析和 XML 在 Java object-mapping APIs中, 之前只在Java EE平臺實現或者Java Web Services Pack中提供.
3.2 Scripting
現在你可以在Java原始碼中混入JavaScript了,這對開發原型很有有用,你也可以插入自己的指令碼引擎。
3.3 JDBC4.0
JAVA6將聯合繫結 Java DB (Apache Derby). JDBC 4.0 增加了許多特性例如支援XML作為SQL資料型別,更好的整合Binary Large OBjects (BLOBs) 和 Character Large OBjects (CLOBs) .
3.4 UI優化
- GUI 開發者可以有更多的技巧來使用 SwingWorker utility ,以幫助GUI應用中的多執行緒。, JTable 分類和過濾,以及新增splash閃屏。
- Swing擁有更好的 look-and-feel , LCD 文字呈現, 整體GUI效能的提升。Java應用程式可以和本地平臺更好的整合,例如訪問平臺的系統托盤和開始選單。Mustang將Java外掛技術和Java Web Start引擎統一了起來。
3.5 監控管理增強
新增更多的診斷資訊,綁定了不是很知名的 memory-heap 分析工具Jhat 來檢視核心匯出。
3.6 編譯API
compiler API提供程式設計訪問javac,可以實現程序內編譯,動態產生Java程式碼
3.7 自定義註解
Java tool和framework 提供商可以定義自己的 annotations ,並且核心支援自定義annotation的外掛和執行處理器
3.8 安全性
XML-數字簽名(XML-DSIG) APIs 用於建立和操縱數字簽名); 新的方法來訪問本地平臺的安全服務,例如本地Microsoft Windows for secure authentication and communicationnative 的Public Key Infrastructure (PKI) 和 cryptographic services, Java Generic Security Services (Java GSS) 和 Kerberos services for authentication, 以及訪問 LDAP servers 來認證使用者.
4. JAVA7
4.1 集合類的語法支援
原來的樣子
-
List<String> list = new ArrayList<String>();
-
list.add("item");
-
String item = list.get(0);
-
Set<String> set = new HashSet<String>();
-
set.add("item");
-
Map<String, Integer> map = new HashMap<String, Integer>();
-
map.put("key", 1);
-
int value = map.get("key");
現在的樣子:(這些集合是不可變的...)
-
List<String> list = ["item"];
-
String item = list[0];
-
Set<String> set = {"item"};
-
Map<String, Integer> map = {"key" : 1};
-
int value = map["key"];
4.2 自動資源管理
Java中某些資源是需要手動關閉的,如InputStream,Writes,Sockets,Sql classes等。這個新的語言特性允許try語句本身申請更多的資源,這些資源作用於try程式碼塊,並自動關閉。
以前的寫法:
-
BufferedReader br = new BufferedReader(new FileReader(path));
-
try {
-
return br.readLine();
-
} finally {
-
br.close();
-
}
現在的寫法(不需要finally來釋放資源了)
-
try (BufferedReader br = new BufferedReader(new FileReader(path)) {
-
return br.readLine();
-
}
4.3 型別推斷
以前的寫法:
Map<String, List<String>> anagrams = new HashMap<String, List<String>>();
現在的寫法
Map<String, List<String>> anagrams = new HashMap<>();
4.4 數字字面量下劃線支援
很長的數字可讀性不好,在Java 7中可以使用下劃線分隔長int以及long了。如:
int one_million = 1_000_000;
這樣子還真看不慣。。。不過的確是可讀性好了。
4.5 switch中使用string
-
String s = "test";
-
switch (s) {
-
case "test" :
-
System.out.println("test");
-
case "test1" :
-
System.out.println("test1");
-
break ;
-
default :
-
System.out.println("break");
-
break ;
-
}
4.6 新增一些取環境資訊的工具方法
-
File System.getJavaIoTempDir() // IO臨時資料夾
-
File System.getJavaHomeDir() // JRE的安裝目錄
-
File System.getUserHomeDir() // 當前使用者目錄
-
File System.getUserDir() // 啟動java程序時所在的目錄5
5. java8
5.1 lambda表示式
提供了lambda表示式,增加了很多內建函式式介面。尤其是其中的stream介面提供了
5.2 註解改進
例如支援多重註解,還有新的target等
5.3 更加詳細資料
JAVA8的新內容非常多,都有相關的書來說明。需要更多瞭解可以看下我的另外一篇文章:java8的新特性以及用法簡介
6. java9
根據JAVA 9 new features這篇幻燈片部落格來總結。
6.1 REPL: jshell
類似效果:
6.2 javadoc改進
使用了H5的javadoc,優化了搜尋功能:
6.3 編譯改進
改變了Javac和Java用法,以便使用模組:
-
javac -mp modulepath ...
-
java -mp modulepath -m modulename/moduleclass
javac -release選項支援交叉編譯
6.4 語言級別上的優化
主要涉及:
- 程序控制
- 集合改進
- 改進@Deprecated註解
- 流處理
- StacjWalker
- Package name
6.4.1 程序控制
能夠檢查和檢測以及殺死Process。
-
import java.io.IOException;
-
import static java.lang.System.out;
-
public class ControlProcess {
-
/**
-
* 啟動一個程序process, 監聽程序中斷,檢查程序細節,殺死程序
-
*/
-
public static void main(String[] args) throws IOException, InterruptedException {
-
Process sleeper = Runtime.getRuntime().exec("sleep 1h");
-
// 獲得 自己的或啟動的進行的PIDs
-
out.println("Your pid is " + ProcessHandle.current().getPid());
-
out.println("Started process is " + sleeper.getPid());
-
ProcessHandle sleeperHandle = ProcessHandle.of(sleeper.getPid()) // Optional
-
.orElseThrow(IllegalStateException::new);
-
// 在退出程序做些善後
-
sleeperHandle.onExit().thenRun( // CompletableFuture
-
() -> out.println("Sleeper exited")
-
);
-
// Get info on process
-
out.printf("[%d] %s - %s\n",
-
sleeperHandle.getPid(),
-
sleeperHandle.info().user().orElse("unknown"),
-
sleeperHandle.info().commandLine().orElse("none"));
-
// Kill a process
-
sleeperHandle.destroy();
-
// Give exit handler a chance to see the sleeper onExit()
-
Thread.sleep(99);
-
}
-
}
6.4.2 新的Colection——不可變集合
-
public class ImmutableCollections {
-
/**
-
* 快速建立一個不可變集合
-
* <b>Note:</b> They do not accept {@code null} or duplicate entries (Set/Map)
-
*/
-
public static void main(String args[]) {
-
List<Integer> listOfNumbers = List.of(1, 2, 3, 4, 5/*, null*/);
-
out.println(listOfNumbers);
-
Set<Integer> setOfNumbers = Set.of(1, 2, 3, 4, 5/*, 1*/);
-
out.println(setOfNumbers);
-
Map<String, String> mapOfString = Map.of("key1", "value1", "key2", "value2");
-
out.println(mapOfString);
-
Map<String, String> moreMapOfString = Map.ofEntries(
-
Map.entry("key1", "value1"),
-
Map.entry("key2", "value2")/*,
-
Map.entry("key1", "value3")*/
-
);
-
out.println(moreMapOfString);
-
}
-
}
6.4.3 增強的Deprecated
@Deprecated(since ="1.5", forRemoval = true)
6.4.4 Stream
提供了新的inputStream方法,可以直接重定向輸入流到一個輸出流上
-
// All bytes from an InputStream at once
-
byte[] result = new ByteArrayInputStream(buf)
-
.readAllBytes();
-
// 直接重定向InputStream 到 OutputStream
-
new ByteArrayInputStream(buf)
-
.transferTo(System.out);
6.4.5 StackWalekr類
更加詳細可以參考JAVA9 API
這個類,主要是方便對例項本身做一些類似filter、collect的操作。
-
public class StackWalkerExample {
-
/**
-
* Easily traverse stackframes.
-
*/
-
public static void main(String[] args) {
-
walkAndFilterStackframe().forEach(out::println);
-
}
-
// return class/method only for our classes.
-
private static List<String> walkAndFilterStackframe() {
-
return StackWalker.getInstance().walk(s ->
-
s.map( frame -> frame.getClassName()+"/"+frame.getMethodName() )
-
.filter(name -> name.startsWith("de.excellent"))
-
.limit(10)
-
.collect(Collectors.toList())
-
);
-
}
-
}
7. http/2的支援
關於HTTP2的優點,可以參考我的文章:HTTP2的優點
-
/**
-
* HTTP API 提供非同步和同步功能,在非同步模型
-
* 任務會線上程threads (ExecutorService)執行
-
*/
-
public static void main(String[] args) throws Exception {
-
HttpClient.getDefault()
-
.request(URI.create("https://www.exxcellent.de"))
-
.GET()
-
.responseAsync() // CompletableFuture :D
-
.thenAccept(httpResponse ->
-
out.println(httpResponse.body(HttpResponse.asString()))
-
);
-
Thread.sleep(999); // Give worker thread some time.
-
}
8. JIGSAW
要在JDK裡面內建模組化。這個就要提起OSGI了。這個不是三言兩語能詳細說清楚,為啥這個模組化這麼重要的。簡單來說,無論是JIGSAW還是OSGI都是為了對各模組、包的依賴之間做好隔離。這樣還可以解決“JAR/Classpath地獄”的問題,Jigsaw專案的一個關鍵特性就是依賴管理。這個專案一旦大氣來,自然而然有這樣的模組、包隔離需求。雖然語言層面有了private這樣的關鍵字,但是還是太弱了。
不過我好奇的是JIGSAW是否趕得上OSGI,畢竟人家這麼多年了。還有和MAVEN的關係。按照網友的解釋:osgi更偏重執行時多版本隔離,maven只到jar,jigsaw編譯管理的到程式碼級別,執行時沒有多版本隔離
關於maven和jigsaw在管理依賴上的區別,我覺得應該是maven層次更高點,jigsaw管理程式碼級別較低層次的依賴。未來應該是兩者共存吧。
還有一點就是OSGI太複雜。。用過的大佬最後都放棄了。不過其思路值得學習。
關於這個問題,可以看下以下文章瞭解下:
下面來簡單看下JIGSAW如何生效的:可以看到這裡定義了module,module當中引入了其他類的依賴。更像是替換了原來的import
連編譯時候的方法都變了:
然後使用ServiceLoader來讀取modules
-
public abstract class BillingService {
-
public static BillingService getInstance() {
-
// Java SPI to find the instance
-
ServiceLoader<BillingServiceProvider> sl =
-
ServiceLoader.load(BillingServiceProvider.class);
-
// Fetch first provider implementation
-
Iterator<BillingServiceProvider> it = sl.iterator();
-
return it.next().buildBillingService();
-
}
-
public abstract String takeMoney();
-
}
再看另外個例子:
- 先定義module
-
module anothermodule {
-
exports de.exxcellent.anothermodule;
-
requires de.exxcellent.java9;
-
// Provide Service instance (SPI with Jigsaw modules)
-
provides de.exxcellent.java9.jigsaw.spi.BillingServiceProvider
-
with de.exxcellent.anothermodule.spi.MastercardBillingServiceProvider;
-
}
- 使用module
-
$ mkdir -p target/module/de.exxcellent.java9
-
$ mkdir -p target/module/anothermodule
-
$ javac $(find playground/src/main/java -name "*.java") \
-
-d target/module/de.exxcellent.java9
-
$ javac $(find playground-dependent/src/main/java -name "*.java")\
-
-d target/module/anothermodule \
-
-modulepath target/module
-
$ java -modulepath target/module \
-
-m anothermodule/de.exxcellent.anothermodule.TestJigsawSPI
-
Mastercard billed the money!
9. 工具
-
#1.列出內建的module
-
java –listmods
-
#2. 找到對應jar的所有依賴
-
jdeps –jdkinternals app.jar
10. 其他改進
10.1 效能上
提高了競爭鎖的效能隔離程式碼快取更智慧的Java編譯
10.2 http2 client
implements HTTP/2 and WebSocket