Java5~11新特性


Java5

Java5開發代號為Tiger(老虎),於2004-09-30發行

特性列表

  • 泛型
  • 枚舉
  • 自動裝箱拆箱
  • 可變參數
  • 注解
  • foreach循環(增強for、for/in)
  • 靜態導入
  • 格式化(System.out.println 支持%s %d等格式化輸出)
  • 線程框架/數據結構 JUC
  • Arrays工具類/StringBuilder/instrument

 

1、泛型

所謂類型擦除指的就是Java源碼中的范型信息只允許停留在編譯前期,而編譯后的字節碼文件中將不再保留任何的范型信息。也就是說,范型信息在編譯時將會被全部刪除,其中范型類型的類型參數則會被替換為Object類型,並在實際使用時強制轉換為指定的目標數據類型。而C++中的模板則會在編譯時將模板類型中的類型參數根據所傳遞的指定數據類型生成相對應的目標代碼。

Map<Integer, Integer> squares = new HashMap<Integer, Integer>();

 

通配符類型:避免unchecked警告,問號表示任何類型都可以接受

public void printList(List<?> list, PrintStream out) throws IOException {
for (Iterator<?> i = list.iterator(); i.hasNext(); ) {
out.println(i.next().toString());
}
}

 

限制類型

public static <A extends Number> double sum(Box<A> box1,Box<A> box2){
double total = 0;
for (Iterator<A> i = box1.contents.iterator(); i.hasNext(); ) {
total = total + i.next().doubleValue();
}
for (Iterator<A> i = box2.contents.iterator(); i.hasNext(); ) {
total = total + i.next().doubleValue();
}
return total;
}

2、枚舉

EnumMap

public void testEnumMap(PrintStream out) throws IOException {
// Create a map with the key and a String message
EnumMap<AntStatus, String> antMessages =
new EnumMap<AntStatus, String>(AntStatus.class);
// Initialize the map
antMessages.put(AntStatus.INITIALIZING, "Initializing Ant...");
antMessages.put(AntStatus.COMPILING, "Compiling Java classes...");
antMessages.put(AntStatus.COPYING, "Copying files...");
antMessages.put(AntStatus.JARRING, "JARring up files...");
antMessages.put(AntStatus.ZIPPING, "ZIPping up files...");
antMessages.put(AntStatus.DONE, "Build complete.");
antMessages.put(AntStatus.ERROR, "Error occurred.");
// Iterate and print messages
for (AntStatus status : AntStatus.values() ) {
out.println("For status " + status + ", message is: " +
antMessages.get(status));
}
}

 

switch枚舉

public String getDescription() {
switch(this) {
case ROSEWOOD: return "Rosewood back and sides";
case MAHOGANY: return "Mahogany back and sides";
case ZIRICOTE: return "Ziricote back and sides";
case SPRUCE: return "Sitka Spruce top";
case CEDAR: return "Wester Red Cedar top";
case AB_ROSETTE: return "Abalone rosette";
case AB_TOP_BORDER: return "Abalone top border";
case IL_DIAMONDS:
return "Diamonds and squares fretboard inlay";
case IL_DOTS:
return "Small dots fretboard inlay";
default: return "Unknown feature";
}
}

3、自動拆箱/裝箱

將primitive類型轉換成對應的wrapper類型:Boolean、Byte、Short、Character、Integer、Long、Float、Double

 

4、可變參數

private String print(Object... values) {
StringBuilder sb = new StringBuilder();
for (Object o : values) {
sb.append(o.toString())
.append(" ");
}
return sb.toString();
}

 

5、注解

Inherited表示該注解是否對類的子類繼承的方法等起作用

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface InProgress { }

 

Target類型

Rentation表示annotation是否保留在編譯過的class文件中還是在運行時可讀。

 

6、增強for循環 for/in

for/in循環辦不到的事情:

(1)遍歷同時獲取index

(2)集合逗號拼接時去掉最后一個

(3)遍歷的同時刪除元素

 

7、靜態導入

import static java.lang.System.err;
import static java.lang.System.out;
err.println(msg);

 

8、print輸出格式化

System.out.println("Line %d: %s%n", i++, line);

 

9、並發支持(JUC)

 

線程池

uncaught exception(可以抓住多線程內的異常)

class SimpleThreadExceptionHandler implements
Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
System.err.printf("%s: %s at line %d of %s%n",
t.getName(),
e.toString(),
e.getStackTrace()[0].getLineNumber(),
e.getStackTrace()[0].getFileName());
}

 

blocking queue(BlockingQueue)

JUC類庫

 

10、Arrays、Queue、線程安全StringBuilder

Arrays工具類

Arrays.sort(myArray);
Arrays.toString(myArray)
Arrays.binarySearch(myArray, 98)
Arrays.deepToString(ticTacToe)
Arrays.deepEquals(ticTacToe, ticTacToe3)

 

Queue

避開集合的add/remove操作,使用offer、poll操作(不拋異常)

Queue接口與List、Set同一級別,都是繼承了Collection接口。LinkedList實現了Deque接口。

Queue q = new LinkedList(); //采用它來實現queue

 

Override返回類型

單線程StringBuilder

java.lang.instrument

 

Java 6

Java6開發代號為Mustang(野馬),於2006-12-11發行。評價:雞肋的版本,有JDBC4.0更新、Complier API、WebSevice支持的加強等更新。

1、Web Services

優先支持編寫 XML web service 客戶端程序。你可以用過簡單的annotaion將你的API發布成.NET交互的web services. Mustang 添加了新的解析和 XML 在 Java object-mapping APIs中, 之前只在Java EE平台實現或者Java Web Services Pack中提供.

2、Scripting(開啟JS的支持,算是比較有用的)

現在你可以在Java源代碼中混入JavaScript了,這對開發原型很有有用,你也可以插入自己的腳本引擎。

3、Database

Mustang 將聯合綁定 Java DB (Apache Derby). JDBC 4.0 增加了許多特性例如支持XML作為SQL數據類型,更好的集成Binary Large OBjects (BLOBs) 和 Character Large OBjects (CLOBs) .

4、More Desktop APIs

GUI 開發者可以有更多的技巧來使用 SwingWorker utility ,以幫助GUI應用中的多線程。, JTable 分類和過濾,以及添加splash閃屏。

很顯然,這對於主攻服務器開發的Java來說,並沒有太多吸引力

5、Monitoring and Management.

綁定了不是很知名的 memory-heap 分析工具Jhat 來查看內核導出。

6、Compiler Access(這個很厲害)

compiler API提供編程訪問javac,可以實現進程內編譯,動態產生Java代碼。

7、Pluggable Annotation

8、Desktop Deployment.

Swing擁有更好的 look-and-feel , LCD 文本呈現, 整體GUI性能的提升。Java應用程序可以和本地平台更好的集成,例如訪問平台的系統托盤和開始菜單。Mustang將Java插件技術和Java Web Start引擎統一了起來。

9、Security

XML-數字簽名(XML-DSIG) APIs 用於創建和操縱數字簽名); 新的方法來訪問本地平台的安全服務

10、The -ilities(很好的習慣)

質量,兼容性,穩定性。 80,000 test cases 和數百萬行測試代碼(只是測試活動中的一個方面). Mustang 的快照發布已經被下載15個月了,每一步中的Bug都被修復了,表現比J2SE 5還要好。

 

Java 7

特性列表

  • switch中添加對String類型的支持
  • 數字字面量的改進 / 數值可加下划
  • 異常處理(捕獲多個異常) try-with-resources
  • 增強泛型推斷
  • JSR203 NIO2.0(AIO)新IO的支持
  • JSR292與InvokeDynamic指令
  • Path接口、DirectoryStream、Files、WatchService(重要接口更新)
  • fork/join framework

1、switch中添加對String類型的支持

 String title = ""; 
switch (gender) {
case "男":
title = name + " 先生";
break;
case "女":
title = name + " 女士";
break;
default:
title = name;
}
return title;
}

 

編譯器在編譯時先做處理:

①case僅僅有一種情況。直接轉成if。

②假設僅僅有一個case和default,則直接轉換為if…else…。

③有多個case。先將String轉換為hashCode,然后相應的進行處理,JavaCode在底層兼容Java7曾經版本號。

2、數字字面量的改進

Java7前支持十進制(123)、八進制(0123)、十六進制(0X12AB)

Java7添加二進制表示(0B11110001、0b11110001)

數字中可加入分隔符

Java7中支持在數字量中間添加’_'作為分隔符。更直觀,如(12_123_456)。下划線僅僅能在數字中間。編譯時編譯器自己主動刪除數字中的下划線。

int one_million = 1_000_000;

3、異常處理(捕獲多個異常) try-with-resources

catch子句能夠同一時候捕獲多個異常

public void testSequence() { 
try {
Integer.parseInt("Hello");
}
catch (NumberFormatException | RuntimeException e) { //使用'|'切割,多個類型,一個對象e
}
}

 

try-with-resources語句

Java7之前須要在finally中關閉socket、文件、數據庫連接等資源;

Java7中在try語句中申請資源,實現資源的自己主動釋放(資源類必須實現java.lang.AutoCloseable接口,一般的文件、數據庫連接等均已實現該接口,close方法將被自己主動調用)。

public void read(String filename) throws IOException { 
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
StringBuilder builder = new StringBuilder();
String line = null;
while((line=reader.readLine())!=null){
builder.append(line);
builder.append(String.format("%n"));
}
return builder.toString();
}
}

4、增強泛型推斷

Map<String, List<String>> map = new HashMap<String, List<String>>(); 

 

Java7之后可以簡單的這么寫

Map<String, List<String>> anagrams = new HashMap<>(); 

5、NIO2.0(AIO)新IO的支持

bytebuffer

public class ByteBufferUsage {
public void useByteBuffer() {
ByteBuffer buffer = ByteBuffer.allocate(32);
buffer.put((byte)1);
buffer.put(new byte[3]);
buffer.putChar('A');
buffer.putFloat(0.0f);
buffer.putLong(10, 100L);
System.out.println(buffer.getChar(4));
System.out.println(buffer.remaining());
}
public void byteOrder() {
ByteBuffer buffer = ByteBuffer.allocate(4);
buffer.putInt(1);
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.getInt(0); //值為16777216
}
public void compact() {
ByteBuffer buffer = ByteBuffer.allocate(32);
buffer.put(new byte[16]);
buffer.flip();
buffer.getInt();
buffer.compact();
int pos = buffer.position();
}
public void viewBuffer() {
ByteBuffer buffer = ByteBuffer.allocate(32);
buffer.putInt(1);
IntBuffer intBuffer = buffer.asIntBuffer();
intBuffer.put(2);
int value = buffer.getInt(); //值為2
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
ByteBufferUsage bbu = new ByteBufferUsage();
bbu.useByteBuffer();
bbu.byteOrder();
bbu.compact();
bbu.viewBuffer();
}
}

 

filechannel

public class FileChannelUsage {
public void openAndWrite() throws IOException {
FileChannel channel = FileChannel.open(Paths.get("my.txt"), StandardOpenOption.CREATE, StandardOpenOption.WRITE);
ByteBuffer buffer = ByteBuffer.allocate(64);
buffer.putChar('A').flip();
channel.write(buffer);
}
public void readWriteAbsolute() throws IOException {
FileChannel channel = FileChannel.open(Paths.get("absolute.txt"), StandardOpenOption.READ, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
ByteBuffer writeBuffer = ByteBuffer.allocate(4).putChar('A').putChar('B');
writeBuffer.flip();
channel.write(writeBuffer, 1024);
ByteBuffer readBuffer = ByteBuffer.allocate(2);
channel.read(readBuffer, 1026);
readBuffer.flip();
char result = readBuffer.getChar(); //值為'B'
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException {
FileChannelUsage fcu = new FileChannelUsage();
fcu.openAndWrite();
fcu.readWriteAbsolute();
}
}

6、JSR292與InvokeDynamic

 

JSR 292: Supporting Dynamically Typed Languages on the JavaTM Platform,支持在JVM上運行動態類型語言。在字節碼層面支持了InvokeDynamic。

public class ThreadPoolManager {
private final ScheduledExecutorService stpe = Executors
.newScheduledThreadPool(2);
private final BlockingQueue<WorkUnit<String>> lbq;
public ThreadPoolManager(BlockingQueue<WorkUnit<String>> lbq_) {
lbq = lbq_;
}
public ScheduledFuture<?> run(QueueReaderTask msgReader) {
msgReader.setQueue(lbq);
return stpe.scheduleAtFixedRate(msgReader, 10, 10, TimeUnit.MILLISECONDS);
}
private void cancel(final ScheduledFuture<?> hndl) {
stpe.schedule(new Runnable() {
public void run() {
hndl.cancel(true);
}
}, 10, TimeUnit.MILLISECONDS);
}
/**
* 使用傳統的反射api
*/
public Method makeReflective() {
Method meth = null;
try {
Class<?>[] argTypes = new Class[]{ScheduledFuture.class};
meth = ThreadPoolManager.class.getDeclaredMethod("cancel", argTypes);
meth.setAccessible(true);
} catch (IllegalArgumentException | NoSuchMethodException
| SecurityException e) {
e.printStackTrace();
}
return meth;
}
/**
* 使用代理類
* @return
*/
public CancelProxy makeProxy() {
return new CancelProxy();
}
/**
* 使用Java7的新api,MethodHandle
* invoke virtual 動態綁定后調用 obj.xxx
* invoke special 靜態綁定后調用 super.xxx
* @return
*/
public MethodHandle makeMh() {
MethodHandle mh;
MethodType desc = MethodType.methodType(void.class, ScheduledFuture.class);
try {
mh = MethodHandles.lookup().findVirtual(ThreadPoolManager.class,
"cancel", desc);
} catch (NoSuchMethodException | IllegalAccessException e) {
throw (AssertionError) new AssertionError().initCause(e);
}
return mh;
}
public static class CancelProxy {
private CancelProxy() {
}
public void invoke(ThreadPoolManager mae_, ScheduledFuture<?> hndl_) {
mae_.cancel(hndl_);
}
}
}

 

調用invoke

public class ThreadPoolMain {
/**
* 如果被繼承,還能在靜態上下文尋找正確的class
*/
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private ThreadPoolManager manager;
public static void main(String[] args) {
ThreadPoolMain main = new ThreadPoolMain();
main.run();
}
private void cancelUsingReflection(ScheduledFuture<?> hndl) {
Method meth = manager.makeReflective();
try {
System.out.println("With Reflection");
meth.invoke(hndl);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
}
private void cancelUsingProxy(ScheduledFuture<?> hndl) {
CancelProxy proxy = manager.makeProxy();
System.out.println("With Proxy");
proxy.invoke(manager, hndl);
}
private void cancelUsingMH(ScheduledFuture<?> hndl) {
MethodHandle mh = manager.makeMh();
try {
System.out.println("With Method Handle");
mh.invokeExact(manager, hndl);
} catch (Throwable e) {
e.printStackTrace();
}
}
private void run() {
BlockingQueue<WorkUnit<String>> lbq = new LinkedBlockingQueue<>();
manager = new ThreadPoolManager(lbq);
final QueueReaderTask msgReader = new QueueReaderTask(100) {
@Override
public void doAction(String msg_) {
if (msg_ != null)
System.out.println("Msg recvd: " + msg_);
}
};
ScheduledFuture<?> hndl = manager.run(msgReader);
cancelUsingMH(hndl);
// cancelUsingProxy(hndl);
// cancelUsingReflection(hndl);
}
}

7、Path接口(重要接口更新)

Path

public class PathUsage {
public void usePath() {
Path path1 = Paths.get("folder1", "sub1");
Path path2 = Paths.get("folder2", "sub2");
path1.resolve(path2); //folder1sub1 older2sub2
path1.resolveSibling(path2); //folder1 older2sub2
path1.relativize(path2); //.... older2sub2
path1.subpath(0, 1); //folder1
path1.startsWith(path2); //false
path1.endsWith(path2); //false
Paths.get("folder1/./../folder2/my.text").normalize(); //folder2my.text
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
PathUsage usage = new PathUsage();
usage.usePath();
}
}

 

DirectoryStream

public class ListFile {
public void listFiles() throws IOException {
Path path = Paths.get("");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(path, "*.*")) {
for (Path entry: stream) {
//使用entry
System.out.println(entry);
}
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException {
ListFile listFile = new ListFile();
listFile.listFiles();
}
}

 

Files

public class FilesUtils {
public void manipulateFiles() throws IOException {
Path newFile = Files.createFile(Paths.get("new.txt").toAbsolutePath());
List<String> content = new ArrayList<String>();
content.add("Hello");
content.add("World");
Files.write(newFile, content, Charset.forName("UTF-8"));
Files.size(newFile);
byte[] bytes = Files.readAllBytes(newFile);
ByteArrayOutputStream output = new ByteArrayOutputStream();
Files.copy(newFile, output);
Files.delete(newFile);
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException {
FilesUtils fu = new FilesUtils();
fu.manipulateFiles();
}
}

 

WatchService

public class WatchAndCalculate {
public void calculate() throws IOException, InterruptedException {
WatchService service = FileSystems.getDefault().newWatchService();
Path path = Paths.get("").toAbsolutePath();
path.register(service, StandardWatchEventKinds.ENTRY_CREATE);
while (true) {
WatchKey key = service.take();
for (WatchEvent<?> event : key.pollEvents()) {
Path createdPath = (Path) event.context();
createdPath = path.resolve(createdPath);
long size = Files.size(createdPath);
System.out.println(createdPath + " ==> " + size);
}
key.reset();
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws Throwable {
WatchAndCalculate wc = new WatchAndCalculate();
wc.calculate();
}
}

8、fork/join計算框架

Java7提供的一個用於並行執行任務的框架,是一個把大任務分割成若干個小任務,最終匯總每個小任務結果后得到大任務結果的框架。

該框架為Java8的並行流打下了堅實的基礎

 

Java 8

Java 8可謂是自Java 5以來最具革命性的版本了,她在語言、編譯器、類庫、開發工具以及Java虛擬機等方面都帶來了不少新特性。

一、Lambda表達式

Lambda表達式可以說是Java 8最大的賣點,她將函數式編程引入了Java。Lambda允許把函數作為一個方法的參數,或者把代碼看成數據。

一個Lambda表達式可以由用逗號分隔的參數列表、–>符號與函數體三部分表示。例如:

Arrays.asList( "p", "k", "u","f", "o", "r","k").forEach( e -> System.out.println( e ) );

 

為了使現有函數更好的支持Lambda表達式,Java 8引入了函數式接口的概念。函數式接口就是只有一個方法的普通接口。java.lang.Runnable與java.util.concurrent.Callable是函數式接口最典型的例子。為此,Java 8增加了一種特殊的注解@FunctionalInterface

 

二、接口的默認方法與靜態方法

我們可以在接口中定義默認方法,使用default關鍵字,並提供默認的實現。所有實現這個接口的類都會接受默認方法的實現,除非子類提供的自己的實現。例如:

public interface DefaultFunctionInterface {
default String defaultFunction() {
return "default function";
}
}

 

我們還可以在接口中定義靜態方法,使用static關鍵字,也可以提供實現。例如:

public interface StaticFunctionInterface {
static String staticFunction() {
return "static function";
}
}

 

接口的默認方法和靜態方法的引入,其實可以認為引入了C++中抽象類的理念,以后我們再也不用在每個實現類中都寫重復的代碼了。

 

三、方法引用(含構造方法引用)

通常與Lambda表達式聯合使用,可以直接引用已有Java類或對象的方法。一般有四種不同的方法引用:

構造器引用。語法是Class::new,或者更一般的Class< T >::new,要求構造器方法是沒有參數;

靜態方法引用。語法是Class::static_method,要求接受一個Class類型的參數;

特定類的任意對象方法引用。它的語法是Class::method。要求方法是沒有參數的;

特定對象的方法引用,它的語法是instance::method。要求方法接受一個參數,與3不同的地方在於,3是在列表元素上分別調用方法,而4是在某個對象上調用方法,將列表元素作為參數傳入;

 

四、重復注解

在Java 5中使用注解有一個限制,即相同的注解在同一位置只能聲明一次。Java 8引入重復注解,這樣相同的注解在同一地方也可以聲明多次。重復注解機制本身需要用@Repeatable注解。Java 8在編譯器層做了優化,相同注解會以集合的方式保存,因此底層的原理並沒有變化。

 

五、擴展注解的支持(類型注解)

Java 8擴展了注解的上下文,幾乎可以為任何東西添加注解,包括局部變量、泛型類、父類與接口的實現,連方法的異常也能添加注解。

private @NotNull String name;

 

六、Optional

Java 8引入Optional類來防止空指針異常,Optional類最先是由Google的Guava項目引入的。Optional類實際上是個容器:它可以保存類型T的值,或者保存null。使用Optional類我們就不用顯式進行空指針檢查了。

 

七、Stream

Stream API是把真正的函數式編程風格引入到Java中。其實簡單來說可以把Stream理解為MapReduce,當然Google的MapReduce的靈感也是來自函數式編程。她其實是一連串支持連續、並行聚集操作的元素。從語法上看,也很像linux的管道、或者鏈式編程,代碼寫起來簡潔明了,非常酷帥!

 

八、Date/Time API (JSR 310)

Java 8新的Date-Time API (JSR 310)受Joda-Time的影響,提供了新的java.time包,可以用來替代 java.util.Date和java.util.Calendar。一般會用到Clock、LocaleDate、LocalTime、LocaleDateTime、ZonedDateTime、Duration這些類,對於時間日期的改進還是非常不錯的。

 

九、JavaScript引擎Nashorn

Nashorn允許在JVM上開發運行JavaScript應用,允許Java與JavaScript相互調用。

 

十、Base64

在Java 8中,Base64編碼成為了Java類庫的標准。Base64類同時還提供了對URL、MIME友好的編碼器與解碼器。

說在后面

除了這十大特性,還有另外的一些新特性:

更好的類型推測機制:Java 8在類型推測方面有了很大的提高,這就使代碼更整潔,不需要太多的強制類型轉換了。

編譯器優化:Java 8將方法的參數名加入了字節碼中,這樣在運行時通過反射就能獲取到參數名,只需要在編譯時使用-parameters參數。

並行(parallel)數組:支持對數組進行並行處理,主要是parallelSort()方法,它可以在多核機器上極大提高數組排序的速度。

並發(Concurrency):在新增Stream機制與Lambda的基礎之上,加入了一些新方法來支持聚集操作。

Nashorn引擎jjs:基於Nashorn引擎的命令行工具。它接受一些JavaScript源代碼為參數,並且執行這些源代碼。

類依賴分析器jdeps:可以顯示Java類的包級別或類級別的依賴。

JVM的PermGen空間被移除:取代它的是Metaspace(JEP 122)。

 

Java 9

經過4次跳票,歷經曲折的java 9 終於終於在2017年9月21日發布(距離上個版本足足3年半時間)java 9 提供了超過 150 項新功能特性,包括備受期待的模塊化系統、可交互的 REPL 工具:jshell,JDK 編譯工具,Java 公共 API 和私有代碼,以及安全增強、擴展提升、性能管理改善等。可以說 Java 9 是一個龐大的系統工程,完全做了一個整體改變。但本博文只介紹最重要的十大新特性

特性列表

  • 平台級modularity(原名:Jigsaw) 模塊化系統
  • Java 的 REPL 工具: jShell 命令
  • 多版本兼容 jar 包(這個在處理向下兼容方面,非常好用)
  • 語法改進:接口的私有方法
  • 語法改進:UnderScore(下划線)使用的限制
  • 底層結構:String 存儲結構變更(這個很重要)
  • 集合工廠方法:快速創建只讀集合
  • 增強的 Stream API
  • 全新的 HTTP 客戶端 API
  • 其它特性
  • 它的新特性來自於100於項JEP和40於項JSR

 

Java 10

2018年3月20日,Java 10 正式發布,這一次沒有跳票。它號稱有109項新特性,包含12個JEP。需要注意的是,本次Java10並不是Oracle的官方LTS版本,還是坐等java11的發布再考慮在生產中使用

特性列表

  • 局部變量的類型推斷 var關鍵字
  • GC改進和內存管理 並行全垃圾回收器 G1
  • 垃圾回收器接口
  • 線程-局部變量管控
  • 合並 JDK 多個代碼倉庫到一個單獨的儲存庫中
  • 新增API:ByteArrayOutputStream
  • 新增API:List、Map、Set
  • 新增API:java.util.Properties
  • 新增API: Collectors收集器
  • 其它特性

1、局部變量的類型推斷 var關鍵字

這個新功能將為Java增加一些語法糖 - 簡化它並改善開發者體驗。新的語法將減少與編寫Java相關的冗長度,同時保持對靜態類型安全性的承諾。

這可能是Java10給開發者帶來的最大的一個新特性。下面主要看例子:

public static void main(String[] args) {
var list = new ArrayList<String>();
list.add("hello,world!");
System.out.println(list);
}

 

這是最平常的使用。注意賦值語句右邊,最好寫上泛型類型,否則會有如下情況:

public static void main(String[] args) {
var list = new ArrayList<>();
list.add("hello,world!");
list.add(1);
list.add(1.01);
System.out.println(list);
}

 

list什么都可以裝,非常的不安全了。和js等語言不同的是,畢竟Java還是強類型的語言,所以下面語句是編譯報錯的:

public static void main(String[] args) {
var list = new ArrayList<String>();
list.add("hello,world!");
System.out.println(list);
list = new ArrayList<Integer>(); //編譯報錯
}

 

注意:下面幾點使用限制

局部變量初始化

for循環內部索引變量

傳統的for循環聲明變量

public static void main(String[] args) {
//局部變量初始化
var list = new ArrayList<String>();
//for循環內部索引變量
for (var s : list) {
System.out.println(s);
}
//傳統的for循環聲明變量
for (var i = 0; i < list.size(); i++) {
System.out.println(i);
}
}

 

下面這幾種情況,都是不能使用var的

方法參數全局變量

public static var list = new ArrayList<String>(); //編譯報錯

public static List<String> list = new ArrayList<>(); //正常編譯通過

構造函數參數方法返回類型字段捕獲表達式(或任何其他類型的變量聲明)

 

2、GC改進和內存管理 並行全垃圾回收器 G1

JDK 10中有2個JEP專門用於改進當前的垃圾收集元素。

Java 10的第二個JEP是針對G1的並行完全GC(JEP 307),其重點在於通過完全GC並行來改善G1最壞情況的等待時間。G1是Java 9中的默認GC,並且此JEP的目標是使G1平行。

 

3、垃圾回收器接口

這不是讓開發者用來控制垃圾回收的接口;而是一個在 JVM 源代碼中的允許另外的垃圾回收器快速方便的集成的接口。

 

4、線程-局部變量管控

這是在 JVM 內部相當低級別的更改,現在將允許在不運行全局虛擬機安全點的情況下實現線程回調。這將使得停止單個線程變得可能和便宜,而不是只能啟用或停止所有線程。

 

5、合並 JDK 多個代碼倉庫到一個單獨的儲存庫中

在 JDK9 中,有 8 個倉庫: root、corba、hotspot、jaxp、jaxws、jdk、langtools 和 nashorn 。在 JDK10 中這些將被合並為一個,使得跨相互依賴的變更集的存儲庫運行 atomic commit (原子提交)成為可能。

 

6、新增API:ByteArrayOutputStream

String toString(Charset): 重載 toString(),通過使用指定的字符集解碼字節,將緩沖區的內容轉換為字符串。

 

7、新增API:List、Map、Set

這3個接口都增加了一個新的靜態方法,copyOf(Collection)。這些函數按照其迭代順序返回一個不可修改的列表、映射或包含給定集合的元素的集合。

 

8、新增API:java.util.Properties

增加了一個新的構造函數,它接受一個 int 參數。這將創建一個沒有默認值的空屬性列表,並且指定初始大小以容納指定的元素數量,而無需動態調整大小。還有一個新的重載的 replace 方法,接受三個 Object 參數並返回一個布爾值。只有在當前映射到指定值時,才會替換指定鍵的條目。

 

9、新增API: Collectors收集器

toUnmodifiableList():

toUnmodifiableSet():

toUnmodifiableMap(Function, Function):

toUnmodifiableMap(Function, Function, BinaryOperator):

這四個新方法都返回 Collectors ,將輸入元素聚集到適當的不可修改的集合中。

 

10、其它特性

線程本地握手(JEP 312)

其他Unicode語言 - 標記擴展(JEP 314)

基於Java的實驗性JIT編譯器

根證書頒發認證(CA)

刪除工具javah(JEP 313)

從JDK中移除了javah工具,這個很簡單並且很重要。

最后

 

JDK10的升級幅度其實主要還是以優化為主,並沒有帶來太多對使用者驚喜的特性。所以建議廣大開發者還是坐等Java11吧,預計2018年9月份就會到來,最重要的是它是LTS版本哦,所以是可以運用在生產上的。

 

Java 11

2018年9月26日,Oracle 官方宣布 Java 11 正式發布。這是 Java 大版本周期變化后的第一個長期支持版本(LTS版本,Long-Term-Support,持續支持到2026年9月),非常值得關注。Java11 帶來了 ZGC、Http Client 等重要特性,一共包含 17 個 JEP(JDK Enhancement Proposals,JDK 增強提案)。

Java 5~11各個版本新特性史上最全總結

 

特性列表

官方新特性:

Java 5~11各個版本新特性史上最全總結

 

 

本文針對於讀者對關心、也是最實用的八大新特性做出一些講解

  • 本地變量類型推斷
  • 字符串加強
  • 集合加強
  • Stream 加強
  • Optional 加強
  • InputStream 加強
  • HTTP Client API
  • 化繁為簡,一個命令編譯運行源代碼

 

Java 5~11各個版本新特性史上最全總結

 

 

Java 5~11各個版本新特性史上最全總結

 

 

3、集合加強

自 Java 9 開始,Jdk 里面為集合(List/ Set/ Map)都添加了 of 和 copyOf 方法,它們兩個都用來創建不可變的集合,來看下它們的使用和區別。

示例1:

var list = List.of("Java", "Python", "C");
var copy = List.copyOf(list);
System.out.println(list == copy); // true

 

示例2:

var list = new ArrayList<String>();
var copy = List.copyOf(list);
System.out.println(list == copy); // false

 

示例1和2代碼差不多,為什么一個為true,一個為false?

來看下它們的源碼:

static <E> List<E> of(E... elements) {
switch (elements.length) { // implicit null check of elements
case 0:
return ImmutableCollections.emptyList();
case 1:
return new ImmutableCollections.List12<>(elements[0]);
case 2:
return new ImmutableCollections.List12<>(elements[0], elements[1]);
default:
return new ImmutableCollections.ListN<>(elements);
}
}
static <E> List<E> copyOf(Collection<? extends E> coll) {
return ImmutableCollections.listCopy(coll);
}
static <E> List<E> listCopy(Collection<? extends E> coll) {
if (coll instanceof AbstractImmutableList && coll.getClass() != SubList.class) {
return (List<E>)coll;
} else {
return (List<E>)List.of(coll.toArray());
}
}

 

可以看出 copyOf 方法會先判斷來源集合是不是 AbstractImmutableList 類型的,如果是,就直接返回,如果不是,則調用 of 創建一個新的集合。

示例2因為用的 new 創建的集合,不屬於不可變 AbstractImmutableList 類的子類,所以 copyOf 方法又創建了一個新的實例,所以為false.

注意:使用of和copyOf創建的集合為不可變集合,不能進行添加、刪除、替換、排序等操作,不然會報 java.lang.UnsupportedOperationException 異常。

上面演示了 List 的 of 和 copyOf 方法,Set 和 Map 接口都有。

public static void main(String[] args) {
Set<String> names = Set.of("Fred", "Wilma", "Barney", "Betty");
//JDK11之前我們只能這么寫
System.out.println(Arrays.toString(names.toArray(new String[names.size()])));
//JDK11之后 可以直接這么寫了
System.out.println(Arrays.toString(names.toArray(size -> new String[size])));
System.out.println(Arrays.toString(names.toArray(String[]::new)));
}

 

Collection.toArray(IntFunction)

在java.util.Collection接口中添加了一個新的默認方法toArray(IntFunction)。此方法允許將集合的元素傳輸到新創建的所需運行時類型的數組。

public static void main(String[] args) {
Set<String> names = Set.of("Fred", "Wilma", "Barney", "Betty");
//JDK11之前我們只能這么寫
System.out.println(Arrays.toString(names.toArray(new String[names.size()])));
//JDK11之后 可以直接這么寫了
System.out.println(Arrays.toString(names.toArray(size -> new String[size])));
System.out.println(Arrays.toString(names.toArray(String[]::new)));
}

 

4、Stream 加強

Stream 是 Java 8 中的新特性,Java 9 開始對 Stream 增加了以下 4 個新方法。

增加單個參數構造方法,可為null

Stream.ofNullable(null).count(); // 0
//JDK8木有ofNullable方法哦

 

源碼可看看:

/**
* @since 9
*/
public static<T> Stream<T> ofNullable(T t) {
return t == null ? Stream.empty()
: StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
}

 

2、增加 takeWhile 和 dropWhile 方法

Stream.of(1, 2, 3, 2, 1)
.takeWhile(n -> n < 3)
.collect(Collectors.toList()); // [1, 2]

 

takeWhile表示從開始計算,當 n < 3 時就截止。

Stream.of(1, 2, 3, 2, 1)
.dropWhile(n -> n < 3)
.collect(Collectors.toList()); // [3, 2, 1]

 

3)iterate重載

這個 iterate 方法的新重載方法,可以讓你提供一個 Predicate (判斷條件)來指定什么時候結束迭代。

 public static void main(String[] args) {
// 這構造的是無限流 JDK8開始
Stream.iterate(0, (x) -> x + 1);
// 這構造的是小於10就結束的流 JDK9開始
Stream.iterate(0, x -> x < 10, x -> x + 1);
}

 

5、Optional 加強

Opthonal 也增加了幾個非常酷的方法,現在可以很方便的將一個 Optional 轉換成一個 Stream, 或者當一個空 Optional 時給它一個替代的。

Optional.of("javastack").orElseThrow(); // javastack
Optional.of("javastack").stream().count(); // 1
Optional.ofNullable(null)
.or(() -> Optional.of("javastack"))
.get(); // javastac

 

or方法和stream方法顯然都是新增的

 

6、InputStream 加強

InputStream 終於有了一個非常有用的方法:transferTo,可以用來將數據直接傳輸到 OutputStream,這是在處理原始數據流時非常常見的一種用法,如下示例。

var classLoader = ClassLoader.getSystemClassLoader();
var inputStream = classLoader.getResourceAsStream("javastack.txt");
var javastack = File.createTempFile("javastack2", "txt");
try (var outputStream = new FileOutputStream(javastack)) {
inputStream.transferTo(outputStream);
}

 

7、HTTP Client API(重磅)

在java9及10被標記incubator的模塊jdk.incubator.httpclient,在java11被標記為正式,改為java.net.http模塊。這是 Java 9 開始引入的一個處理 HTTP 請求的的孵化 HTTP Client API,該 API 支持同步和異步,而在 Java 11 中已經為正式可用狀態,你可以在 java.net 包中找到這個 API。

來看一下 HTTP Client 的用法:

上面的 .GET() 可以省略,默認請求方式為 Get!

更多使用示例可以看這個 API,后續有機會再做演示。

現在 Java 自帶了這個 HTTP Client API,我們以后還有必要用 Apache 的 HttpClient 工具包嗎?我覺得沒啥必要了

 

8、化繁為簡,一個命令編譯運行源代碼

看下面的代碼。

// 編譯
javac Javastack.java
// 運行
java Javastack

 

在我們的認知里面,要運行一個 Java 源代碼必須先編譯,再運行,兩步執行動作。而在未來的 Java 11 版本中,通過一個 java 命令就直接搞定了,如以下所示。

java Javastack.java

 

移除項

移除了com.sun.awt.AWTUtilities

移除了sun.misc.Unsafe.defineClass,

使用 java.lang.invoke.MethodHandles.Lookup.defineClass來替代

移除了Thread.destroy()以及 Thread.stop(Throwable)方法移除了

sun.nio.ch.disableSystemWideOverlappingFileLockCheck、sun.locale.formatasdefault屬性

移除了jdk.snmp模塊

移除了javafx,openjdk估計是從java10版本就移除了,oracle jdk10還尚未移除javafx,而java11版本則oracle的jdk版本也移除了javafx

移除了Java Mission Control,從JDK中移除之后,需要自己單獨下載

移除了這些Root Certificates :Baltimore Cybertrust Code Signing CA,SECOM ,AOL and Swisscom

 

廢棄項

廢棄了Nashorn JavaScript Engine

廢棄了-XX+AggressiveOpts選項

-XX:+UnlockCommercialFeatures以及

-XX:+LogCommercialFeatures選項也不- 再需要

廢棄了Pack200工具及其API

 

說到最后

java11是java改為6個月發布一版的策略之后的第一個LTS(Long-Term Support)版本(oracle版本才有LTS),這個版本最主要的特性是:在模塊方面移除Java EE以及CORBA模塊,在JVM方面引入了實驗性的ZGC,在API方面正式提供了HttpClient類。

從java11版本開始,不再單獨發布JRE或者Server JRE版本了,有需要的可以自己通過jlink去定制runtime image

備注:ZGC作為實驗性功能包含在內。要啟用它,因此需要將-XX:+ UnlockExperimentalVMOptions選項與-XX:+ UseZGC選項結合使用。

ZGC的這個實驗版具有以下限制:

  • 它僅適用於Linux / x64。
  • 不支持使用壓縮的oops和/或壓縮的類點。默認情況下禁用-XX:+UseCompressedOops和-XX:+UseCompressedClassPointers選項。啟用它們將不起作用。
  • 不支持類卸載。默認情況下禁用-XX:+ ClassUnloading和-XX:+ - - ClassUnloadingWithConcurrentMark選項。啟用它們將不起作用。
  • 不支持將ZGC與Graal結合使用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM