JavaSE 7 新特性介绍
一、概述
2010-12-06,JCP投票通過了J2SE 7(JSR336)和J2SE 8(JSR337)兩個版本的規范,之前大家比較關注的Lambda表達式和模塊化系統則被推遲到了8中。按照Oracle的進度("Plan B"),計劃在2011年中推出Oracle JDK7,在2012年晚些時候推出JDK8。截至12月16日,JDK7的所有特性已經完成,也就是說最新的JDK7中已經包括7中所有的特性。
額外提一下此次投票情況,如下。由于Apache與Sun/Oracle關于Java授權的爭端最終導致Apache宣布退出JCP。
二、特性列表
下面列出的是J2SE 7規范的參考實現Oracle JDK7的特性列表:
b)、添加URLClassLoader的關閉方法
c)、并發和集合的一些更新
b)、Locale enhancement
c)、user locale和 user-interface locale分離
b)、針對zip/jar的NIO.2文件系統提供者
c)、SCTP on Solaris
d)、SDP on Solaris or Linux
e)、使用windows vista IPv6協議棧
f)、支持TLS 1.2
b)、針對jdk 6u10中提供的新功能(半透明和不規則窗體,輕重量級組件的混合使用,改進的AWT警告)創建新的平臺接口
c)、Nimbus L2F
d)、JXLayer 組件
三、部分特性詳述
1、動態類型語言支持(Invokedynamic)
在JDK中增加了一個invokeDynamic 字節碼指令和相關的APIs (JSR 292),用于在缺少靜態類型信息的情況下,提高動態語言在Java虛擬機上執行方法調用的性能。
之前,在JVM中存在四種用于方法調用的字節碼指令:
Invokevirtual:調用實例方法,基于類的分派。
invokeinterface:調用接口方法?
invokestatic:調用一個類的靜態方法
invokespecial:調用實例方法。用于特別處理超類方法,私有方法和實例初始化方法的調用。
新的invokedynamic指令在很多方面與invokevirtual類似,但是它更少由字節碼的校驗規則來約束,而是通過動態類型的檢查來保持VM的完整性。
Invokedynamic語法:
invokedynamic <method-specification> <n> ?
對于<method-specification>只需指定方法名稱,對描述符的唯一要求是它應引用非空對象。
由于VM只知道方法名稱,對于返回類型和參數類型則是未知的,而VM需要鏈接并調用真實的方法,所以在JDK7中,提供了一套新的動態類型語言的鏈接機制——方法句柄(Method Handles),VM通過鏈接機制獲取所需真實的方法。鏈接機制的相關類主要在java.dyn中。
詳細內容參見:Da Vinci Machine Project
?
2、語法上改進
a)、自動化的資源管理-ARM
語法規則:
try ( *ResourceDeclarations* ) *Block Catchesopt Finallyopt*?
其中*ResourceDeclarations*必須實現Closeable接口,可以為:
*LocalVariableDeclaration* *LocalVariableDeclaration* ; *ResourceDeclarations示例如下圖所示,后一個方法為采用ARM的實現。
public void copy(String src, String dest) throws IOException {InputStream in = new FileInputStream(src);try {OutputStream out = new FileOutputStream(dest);try {byte[] buf = new byte[8 * 1024];int n;while ((n = in.read(buf)) >= 0) {out.write(buf, 0, n);}} finally {out.close();}} finally {in.close();}}public void autoResMngCopy(String src, String dest) throws IOException { try (InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dest)) { byte[] buf = new byte[8192]; int n; while ((n = in.read(buf)) >= 0) { out.write(buf, 0, n); } } } ?
一些說明:
- JDK7中所有的Closeable對象都實現了AutoCloseable (public interface Closeable extends AutoCloseable)
- 資源實例必須實現AutoCloseable中的public void close()方法才可以
- JDK7中JDBC 4.1相關接口也會更新為AutoCloseable
- 編譯器會在代碼塊中嵌入變量跟蹤異常狀態,同時通過一種新的機制來記錄隱藏異常
- 可以通過注解處理器來查找適合更新的已有代碼 [鏈接]
b)、泛型示例創建時類型接口的改進—Diamond(<>)
為了使java代碼清晰簡短,用一個空的類型參數<>,替換之前明確列出的類型參數。例如
Map<String, List<String>> mapList = new HashMap<String, List<String>>();?
替換為:
Map<String, List<String>> mapList=new HashMap<>(); ?
使用場景:構造對象,委派給變量,傳遞參數
c)、簡化可變參數的方法調用
減少類型安全性的警告信息,把在調用出現時的警告信息放到了方法的聲明處
變化前
方法聲明:
static <T> List<T> asList(T... elements) { ... } ?
?方法調用:
static List<Callable<String>> stringFactories() {Callable<String> a, b, c;...*// Warning: **"uses unchecked or unsafe operations"*return asList(a, b, c);} ??
變化后:
方法聲明:
*// Warning: **"enables unsafe generic array creation"*static List asList(T... elements) { ... }?
方法調用:
static List> stringFactories() {Callable a, b, c;...return asList(a, b, c);}?
d)、Switch支持字符串
private void caseStr(String s) {switch (s) {case "a":System.out.println("case:" + s);break;case "b":System.out.println("case:" + s);break;case "c":System.out.println("case:" + s);break;default:System.out.println("unknown string:" + s);}}?
e)、異常的多重捕捉和更加精確的重新拋出
void test(boolean b1, boolean b2) throws BException { try { if (b1) { throw new AException(); } else if (b2) { throw new BException(); } else { throw new CException(); } } catch (final AException|CException e){ } }?
f)、改進的整數值符
public void testUnderscore() { int a = 12345, b = 1_2_3_4_5, c = 1_23_4_5; int a1 = 0x12345, b1 = 0x1_2_3_4_5, c1 = 0x1_23_4_5; int a2 = 0b10101, b2 = 0b1_0_1_0_1, c2 = 0b1_01_0_1; assertTrue(a == b); assertTrue(c == b); assertTrue(a1 == b1); assertTrue(c1 == b1); assertTrue(a2 == b2); assertTrue(c2 == b2); } ?
3、Fork/Join框架
隨著多核技術的發展,為了充分利用硬件資源,需要應用程序在更細的粒度上實現并發控制,為此,Java 7中引入了fork/join并發框架。其采用了分而治之(divide-and-conquer)的思想:
對問題進行評估,確定其大小是否更適合使用順序解決方案;通常,可通過將問題大小與某個閾值進行比較完成。如果問題大到需要并行分解,算法會遞歸地將它分成多個子問題,直到每個子問題都足夠小,以至于可以高效地串行化解決它們;然后把這些問題放入隊列中等待處理(fork步驟),接下來等待所有子問題的結果(join步驟),把多個結果合并到一起。用于選擇順序和并行執行方法的理想閾值是協調并行任務的成本。
偽代碼描述如下:
Result solve(Problem problem) { if (problem is small) directly solve problem else { split problem into independent parts fork new subtasks to solve each part join all subtasks compose result from subresults } }?
Fork/Join主要類的結構圖如下,其中ForkJoinTask的幾個子類分別為:
RecursiveAction:無返回結果,不需要進行合并
RecursiveTask:帶有返回值
AsyncAction/LinkedAsyncAction: 使用?finish()?方法顯式中止
CyclicAction:可使用 TaskBarrier 為每個任務設置不同中止條件
一些說明:
- Fork/Join框架使用與可用核數相匹配的適當大小的線程池,以減少頻繁交換的開銷。
- 為避免線程空閑,框架中采用了一種叫工作竊取(work stealing)的技術,可以使空閑線程從一個執行較慢的線程中竊取等待其處理的工作,其主要是通過雙端隊列(Deque)來實現。
- Fork/Join框架是針對大的,多核系統采取的并發框架,如果少于4個核心的話,效率并不會有太多的提升。
- 一些額外的新特性,如ThreadLocal偽隨機數產生器—ThreadLocalRandom;靈活可復用的同步barrier—Phaser等。
4、新的I/O APIs(NIO.2):
已有I/O接口的問題:
- 需要一個文件系統的接口而不是File類
- 文件名稱的處理方式不是跨平臺的
- 不支持有效的文件屬性訪問
- 不支持文件系統的高級特性,如符號鏈接
- 許多方法只返回true/false或者error而不是有效的異常信息
- 非阻塞I/O機制應用到Socket中,但沒有用到文件系統操作中;另外,下一代網絡控制器和操作系統會對異步I/O提供更好的支持
NIO.2中的主要功能:
- 支持大量訪問文件屬性,避免暴露專有API的文件系統接口以及一個實現可拔插的文件系統服務提供者接口
- 在Socket和文件的操作上,支持異步的非阻塞的I/O操作。
- 完成Socket-channel功能(JSR-51),包括附件的對綁定,配置,多播的支持。
基本對象:
FileSystem:文件系統訪問接口,是訪問文件的對象(Path,WatchService)生成工廠
FileRef:文件(文件或目錄)引用
Path:提供獨立路徑
FileStore:文件存儲對象,可能是存儲池,設備,分區等
FileSystemProvider:文件系統的服務提供者,是FileSystem,FileRef和FileChanel的創建工廠。
WatchService:監聽Watchable對象(Path)的變化和相關事件。
FileVisitor:文件訪問者,實現類通過調用Files. walkFileTree來對文件樹遍歷
PathMatcher:判斷給定路徑是否符合matcher的模式
UserPrincipalLookupService:提供通過名稱來查找用戶和組的主體(UserPrincipal),用來判斷對文件的訪問權限。
主要關系結構圖如下:
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
新舊APIs的對應關系:
| java.io.File | java.nio.file |
| java.io.File? | java.nio.file.Path? |
| java.io.RandomAccessFile? | SeekableByteChannel? |
| File.canRead,?canWrite,?canExecute? | Path.checkAccess?.?on Unix,?Attributes? is used to check the permissions.? |
| The?File?methods:?isDirectory,isFile,?setExecutable,?setReadable,setReadOnly,?lastModified,setLastModified,?length,?setWritable? | replaced by java.nio.file.attributes?package, which reads the attributes in a more efficient bulk operation. |
| new File(parent, "newfile")? | parent.resolve("newfile")? |
| File.renameTo? | Path.moveTo? |
| File.delete? | Path.delete?or?Path.delete(boolean)? |
| File.createNewFile? | Path.createFile? |
| File.deleteOnExit? | Specified in the?createFile?method. |
| File.createTempFile? | Using the?DELETE_ON_CLOSE?option with the createFile?method. An easy way:? Path tmpFile = File.createTempFile("blah",null).toPath(); |
| File.exists? | Path.exists?and?Path.notExists? |
| File.compareTo?and?equals? | Path.compareTo?and?equals |
| File.getAbsolutePath?andgetAbsoluteFile? | Path.toAbsolutePath? |
| File.getCanonicalPath?andgetCanonicalFile? | Path.toRealPath?or?normalize? |
| File.toURI? | Path.toURI? |
| File.isHidden? | Path.isHidden? |
| File.list?and?listFiles? | Path.newDirectoryStream? |
| File.mkdir?and?mkdirs | Path.createDirectory? |
| File.listRoots? | FileSystem.getRootDirectories? |
| File.getTotalSpace,?File.getFreeSpace,File.getUsableSpace? | Attributes.readFileStoreSpaceAttributes? |
異步I/O:
異步IO實現的目的主要基于兩點:統一Socket和文件系統的異步IO APIs;充分利用操作系統提供的IO機制。
基礎類:
- AsynchronousChannel – 標識一個支持異步I/O的通道。
- AsynchronousByteChannel – 標識一個支持讀寫字節的異步通道,這個接口擴展了AsynchronousChannel。
- AsynchronousDatagramChannel – 標識一個面向數據報套接字異步通道,這個類實現了AsynchronousByteChannel。
- AsynchronousFileChannel – 標識一個可讀,寫和操作文件的異步通道,這個類實現了AsynchronousChannel。
- AsynchronousServerSocketChannel – 標識一個面向流監聽套接字的異步通道,這個類實現了AsynchronousChannel。
- AsynchronousSocketChannel – 標識一個面向流連接套接字的異步通道,這個類實現了AsynchronousByteChannel。
- AsynchronousChannelGroup – 標識一個用于資源共享的異步通道組。
兩種異步操作方式:
Future方式:初始化IO操作,返回java.util.concurrent.Future;在Future接口中定義檢測任務是否完成的方法。示例如下:
AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();// initiate connection// wait for connection to be established or failure //Future result = ch.connect(remote);result.get();ByteBuffer buf = ...// initiate readFuture result = ch.read(buf);// do something// wait for read to completetry {int bytesRead = result.get();} catch (ExecutionExecption x) {// failed}?
CallBack方式:調用IO操作時指定CompletionHandler,其在IO操作完成或者失敗時調用。
示例如下:
ByteBuffer buf = ...// CompletionHandler invoked when read completesch.read(buffer, ..., new CompletionHandler() {public void completed(IoFuture result) {try {int bytesRead = result.getNow();} catch (IOException x) {// error handling}}}??
關于異步IO中線程調度及其管理,網上有很多詳細的討論,在此不表。
四、參考資料
1、JaveSE 7 JSR:http://jcp.org/en/jsr/detail?id=336
2、OpenJDK-JDK7:http://openjdk.java.net/projects/jdk7/
3、Mark Reinhold`s Blog:http://blogs.sun.com/mr/
4、Da Vinci Machine Project:http://openjdk.java.net/projects/mlvm/
5、Project Coin: http://openjdk.java.net/projects/coin/
6、Doug Lea:http://gee.cs.oswego.edu/dl/
7、Doug Lea:《A Java Fork/Join Framework》
8、IBM DW: http://www.ibm.com/developerworks/cn/java/j-lo-forkjoin/index.html
9、NIO2 Project: http://openjdk.java.net/projects/nio/
10、Tutorials: http://download.oracle.com/javase/tutorial/essential/io/fileio.html
總結
以上是生活随笔為你收集整理的JavaSE 7 新特性介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 夺命追击(Murderous Pursu
- 下一篇: Java 17 新特性尝鲜