JDK5-15新特性大全
前言
JDK 15釋出啦~ 我們一起回顧JDK 5-15 的新特性吧,大家一起學習哈~
Java 5 新特性
1. 泛型
泛型本質是引數化型別,解決不確定具體物件型別的問題。
1 List<String> strList=new ArrayList<String>();
2. 增強迴圈(for-each)
for-each迴圈簡化了集合的遍歷。
1 String [] str = {"關注","公眾號","撿田螺的小男孩"}; 2 for (String temp:str) { 3 System.out.println(temp); 4 }
3. 自動封箱拆箱
- 自動裝箱: 就是將基本資料型別自動轉換成對應的包裝類。
- 自動拆箱:就是將包裝類自動轉換成對應的基本資料型別。
包裝型別有:Integer,Double,Float,Long,Short,Character和Boolean
1 Integer i =666; //自動裝箱 2 int a= i; //自動拆箱
4. 列舉
關鍵字enum可以將一組具名的值的有限集合建立為一種新的型別,而這些具名的值可以作為常規的程式元件使用,這就是列舉型別。
1 enum SeasonEnum { 2 SPRING,SUMMER,FALL,WINTER; 3 }
5. 可變引數
我們在定義方法引數的時候不確定定義多少個,就可以定義為可變引數
public static void main(String[] args) throws Exception { String [] str = {"關注","公眾號","撿田螺的小男孩"}; testVarargs(str); String str1 = "關注公眾號,撿田螺的小男孩"; testVarargs(str1); } //可變引數String... args private static void testVarargs(String... args) { for (String arg : args) { System.out.println(arg); } }
6. 註解
可以把註解理解為程式碼裡的特殊標記,這些標記可以在編譯,類載入,執行時被讀取,並執行相應的處理。
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
7.靜態匯入
通過import static類,就可以使用類裡的靜態變數或方法。看一下例子哈~
1 import static java.lang.System.out; //靜態匯入System類的靜態變數out 2 public class Test { 3 public static void main(String[] args) throws Exception { 4 String str1 = "關注公眾號,撿田螺的小男孩"; 5 System.out.println(str1); //常規寫法 6 out.println(str1); //靜態匯入,可以直接使用out輸出 7 } 8 }
8. 執行緒併發庫(JUC)
JDK5 豐富了執行緒處理功能,java.util.concurrent包提供了以下的類、介面:
- 執行緒池:ExecutorService介面
- 執行緒護斥:Lock 類
- 執行緒通訊:Condition介面
- 同步佇列:ArrayBlockingQueue類
- 同步集合:ConcurrentHashMap類
Java 6 新特性
1.Desktop類和SystemTray類
JDK 6在java.awt包下,新增了兩個類:Desktop類和SystemTray類
- Desktop類: 用來開啟系統預設瀏覽器瀏覽指定的URL,開啟系統預設郵件客戶端發郵件等
- SystemTray類:用來在系統托盤區建立一個托盤程式,如果在微軟的Windows上,它被稱為“工作列”狀態區域。
1 //獲取Desktop例項 2 Desktop desktop = Desktop.getDesktop(); 3 desktop.browse(URI.create("https://www.baidu.com"));
2. 使用JAXB2來實現物件與XML之間的對映
JAXB,即Java Architecture for XML Binding,可以實現物件與XML之間的對映,常用註解如下:
- @XmlRootElement:註解在類上面,對應xml的跟元素,使用name屬性定義根節點的名稱。
- @XmlElement:指定一個欄位或get/set方法對映到xml的節點,使用name屬性定義這個根節點的名稱。
- @XmlAttribute:將JavaBean物件的屬性對映為xml的屬性,使用name屬性為生成的xml屬性指定別名。
- @XmlAccessorType:定義對映這個類中的何種型別都需要對映到xml。
- @XmlSchema: 將包對映到XML名稱空間
看個例子吧~
1 public class JAXB2XmlTest { 2 3 public static void main(String[] args) throws JAXBException, IOException { 4 5 List<Singer> list = new ArrayList<>(); 6 list.add(new Singer("jay", 8)); 7 list.add(new Singer("eason", 10)); 8 9 SingerList singerList = new SingerList(); 10 singerList.setSingers(list); 11 12 String str = JAXB2XmlTest.beanToXml(singerList, SingerList.class); 13 String path = "C:\\jay.txt"; 14 BufferedWriter bfw = new BufferedWriter(new FileWriter(new File(path))); 15 bfw.write(str); 16 bfw.close(); 17 18 } 19 20 private static String beanToXml(Object obj, Class<?> load) throws JAXBException { 21 JAXBContext context = JAXBContext.newInstance(load); 22 Marshaller marshaller = context.createMarshaller(); 23 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 24 marshaller.setProperty(Marshaller.JAXB_ENCODING, "GBK"); 25 StringWriter writer = new StringWriter(); 26 marshaller.marshal(obj,writer); 27 return writer.toString(); 28 } 29 } 30 public class Singer { 31 32 private String name; 33 private int age; 34 public Singer(String name, int age) { 35 this.name = name; 36 this.age = age; 37 } 38 @XmlAttribute(name="name") 39 public String getName() { 40 return name; 41 } 42 public void setName(String name) { 43 this.name = name; 44 } 45 @XmlAttribute(name="age") 46 public int getAge() { 47 return age; 48 } 49 public void setAge(int age) { 50 this.age = age; 51 } 52 } 53 @XmlRootElement(name="list") 54 public class SingerList { 55 56 private List<Singer> singers; 57 58 @XmlElement(name="singer") 59 public List<Singer> getSingers() { 60 return singers; 61 } 62 63 public void setSingers(List<Singer> singers) { 64 this.singers = singers; 65 } 66 } 67
執行效果:
1 <?xml version="1.0" encoding="GBK" standalone="yes"?> 2 <list> 3 <singer age="8" name="jay"/> 4 <singer age="10" name="eason"/> 5 </list>
3.輕量級 Http Server API
JDK 6中提供了簡單的Http Server API,可以構建嵌入式Http伺服器,同時支援Http和Https協議。HttpServer會呼叫HttpHandler實現類的回撥方法來處理客戶端請求,這裡使用者只需實現HttpHandler介面就可以了。
1 /** 2 * 根據Java提供的API實現Http伺服器 3 */ 4 public class MyHttpServer { 5 6 /** 7 * @param args 8 * @throws IOException 9 */ 10 public static void main(String[] args) throws IOException { 11 //建立HttpServer伺服器 12 HttpServer httpServer = HttpServer.create(new InetSocketAddress(8080), 10); 13 //將 /jay請求交給MyHandler處理器處理 14 httpServer.createContext("/", new MyHandler()); 15 httpServer.start(); 16 } 17 } 18 19 public class MyHandler implements HttpHandler { 20 21 public void handle(HttpExchange httpExchange) throws IOException { 22 //請求頭 23 Headers headers = httpExchange.getRequestHeaders(); 24 Set<Map.Entry<String, List<String>>> entries = headers.entrySet(); 25 26 StringBuffer response = new StringBuffer(); 27 for (Map.Entry<String, List<String>> entry : entries){ 28 response.append(entry.toString() + "\n"); 29 } 30 //設定響應頭屬性及響應資訊的長度 31 httpExchange.sendResponseHeaders(200, response.length()); 32 //獲得輸出流 33 OutputStream os = httpExchange.getResponseBody(); 34 os.write(response.toString().getBytes()); 35 os.close(); 36 } 37 }
4. 插入式註解處理API
JDK 6提供了插入式註解處理API,可以讓我們定義的註解在編譯期而不是執行期生效,從而可以在編譯期修改位元組碼。lombok框架就是使用該特性來實現的,Lombok通過註解的方式,在編譯時自動為屬性生成構造器、getter/setter、equals、hashcode、toString等方法,大大簡化了程式碼的開發。
5. STAX
STAX,是JDK6中一種處理XML文件的API。
1 public class STAXTest { 2 3 public static void main(String[] args) throws Exception { 4 5 XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); 6 XMLEventReader xmlEventReader = xmlInputFactory.createXMLEventReader(new FileInputStream("C:\\jay.xml")); 7 XMLEvent event = null; 8 StringBuffer stringBuffer = new StringBuffer(); 9 while (xmlEventReader.hasNext()) { 10 event = xmlEventReader.nextEvent(); 11 stringBuffer.append(event.toString()); 12 } 13 System.out.println("xml文件解析結果:"); 14 System.out.println(stringBuffer); 15 } 16 }
執行結果:
xml文件解析結果:
1 <?xml version="1.0" encoding='GBK' standalone='yes'?><list> 2 <singer name='jay' age='8'></singer> 3 <singer name='eason' age='10'></singer> 4 </list>ENDDOCUMENT
6. Common Annotations
Common annotations原本是Java EE 5.0(JSR 244)規範的一部分,現在SUN把它的一部分放到了Java SE 6.0中。隨著Annotation元資料功能加入到Java SE 5.0裡面,很多Java 技術都會用Annotation部分代替XML檔案來配置執行引數。
以下列舉Common Annotations 1.0裡面的幾個Annotations:
- @Generated:用於標註生成的原始碼
- @Resource: 用於標註所依賴的資源,容器據此注入外部資源依賴,有基於欄位的注入和基於setter方法的注入兩種方式 。
- @Resources:同時標註多個外部依賴,容器會把所有這些外部依賴注入
- @PostConstruct:標註當容器注入所有依賴之後執行的方法,用來進行依賴注入後的初始化工作,只有一個方法可以標註為PostConstruct 。
- @PreDestroy:當物件例項將要被從容器當中刪掉之前,要執行的回撥方法要標註為PreDestroy
7. Compiler API
javac編譯器可以把.java的原始檔編譯為.class檔案,JDK 6的新特性Compiler API(JSR 199)也可以動態編譯Java原始檔。
1 public class CompilerApiTest { 2 public static void main(String[] args) throws Exception { 3 JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); 4 StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null,null,null); 5 Iterable<? extends JavaFileObject> javaFileObjects = standardJavaFileManager.getJavaFileObjects("C:\\Singer.java"); 6 javaCompiler.getTask(null, standardJavaFileManager, null, null, null, javaFileObjects).call(); 7 standardJavaFileManager.close(); 8 } 9 }
執行結果:會在C目錄生成Singer.class檔案
8. 對指令碼語言的支援(如: ruby, groovy, javascript)
JDK6增加了對指令碼語言的支援(JSR 223),原理是將指令碼語言編譯成位元組碼,這樣指令碼語言也能享用Java平臺的諸多優勢,包括可移植性,安全等。JDK6實現包含了一個基於Mozilla Rhino的 指令碼語言引擎,因此可以支援javascript,當然JDK也支援ruby等其他語言
1 public class JavaScriptTest { 2 3 public static void main(String[] args) throws Exception { 4 ScriptEngineManager factory = new ScriptEngineManager(); 5 ScriptEngine engine = factory.getEngineByName("JavaScript"); 6 String script; 7 try { 8 script = "print('Hello')"; 9 engine.eval(script);// 執行指令碼 10 }catch (Exception e) { 11 e.printStackTrace(); 12 } 13 } 14 }
//output
Hello
Java 7 新特性
1.switch 支援String字串型別。
1 String singer = "jay"; 2 switch (singer) { 3 case "jay" : 4 System.out.println("周杰倫"); 5 break; 6 case "eason" : 7 System.out.println("陳奕迅"); 8 break ; 9 default : 10 System.out.println("其他"); 11 break ; 12 }
2.try-with-resources,資源自動關閉
JDK 7 之前:
1 BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt")); 2 try { 3 return br.readLine(); 4 } finally { 5 br.close(); 6 }
JDK 7 之後:
/* * 宣告在try括號中的物件稱為資源,在方法執行完畢後會被自動關閉 */ try (BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt")) { return br.readLine(); }
3. 整數型別如(byte,short,int,long)能夠用二進位制來表示
//0b或者0B表示二進位制 int a = 0b010; int b = 0B010;
4. 數字常量支援下劃線
int a = 11_11;//a的值為1111,下劃線不影響實際值,提升可讀性
5. 泛型例項化型別自動推斷,即”<>”
JDK 7 之前:
1 Map<String, List<String>> map = new HashMap<String, List<String>>();
JDK 7之後:
//不須宣告型別,自動根據前面<>推斷其型別 Map<String, List<String>> map = new HashMap<>();
6.一個catch中捕獲多個異常型別,用(|)分隔開
JDK 7之前
try{ //do something } catch (FirstException e) { logger.error(e); } catch (SecondException e) { logger.error(ex); }
JDk 7之後
try{ //do something } catch (FirstException | SecondException e) { logger.error(e); }
7. 增強的檔案系統
Java7 提供了全新的NIO2.0 API,方便檔案管理的編碼。如,可以在java.nio.file包下使用Path、Paths、Files、WatchService等常用型別。
Path path = Paths.get("C:\\jay\\七里香.txt"); //建立Path物件 byte[] bytes= Files.readAllBytes(path); //讀取檔案 System.out.println(path.getFileName()); //獲取當前檔名稱 System.out.println(path.toAbsolutePath()); // 獲取檔案絕對路徑 System.out.println(new String(bytes, "utf-8"));
8. Fork/join 框架
Java7提供的一個用於並行執行任務的框架,是一個把大任務分割成若干個小任務,最終彙總每個小任務結果後得到大任務結果的框架。
Fork/join計算1-1000累加值:
public class ForkJoinPoolTest { private static final Integer DURATION_VALUE = 100; static class ForkJoinSubTask extends RecursiveTask<Integer>{ // 子任務開始計算的值 private Integer startValue; // 子任務結束計算的值 private Integer endValue; private ForkJoinSubTask(Integer startValue , Integer endValue) { this.startValue = startValue; this.endValue = endValue; } @Override protected Integer compute() { //小於一定值DURATION,才開始計算 if(endValue - startValue < DURATION_VALUE) { System.out.println("執行子任務計算:開始值 = " + startValue + ";結束值 = " + endValue); Integer totalValue = 0; for (int index = this.startValue; index <= this.endValue; index++) { totalValue += index; } return totalValue; } else { // 將任務拆分,拆分成兩個任務 ForkJoinSubTask subTask1 = new ForkJoinSubTask(startValue, (startValue + endValue) / 2); subTask1.fork(); ForkJoinSubTask subTask2 = new ForkJoinSubTask((startValue + endValue) / 2 + 1 , endValue); subTask2.fork(); return subTask1.join() + subTask2.join(); } } } public static void main(String[] args) throws ExecutionException, InterruptedException { // Fork/Join框架的執行緒池 ForkJoinPool pool = new ForkJoinPool(); ForkJoinTask<Integer> taskFuture = pool.submit(new ForkJoinSubTask(1,1000)); Integer result = taskFuture.get(); System.out.println("累加結果是:" + result); } }
執行結果:
... 執行子任務計算:開始值 = 189;結束值 = 250 執行子任務計算:開始值 = 251;結束值 = 313 執行子任務計算:開始值 = 314;結束值 = 375 執行子任務計算:開始值 = 376;結束值 = 438 執行子任務計算:開始值 = 439;結束值 = 500 執行子任務計算:開始值 = 501;結束值 = 563 執行子任務計算:開始值 = 564;結束值 = 625 執行子任務計算:開始值 = 626;結束值 = 688 執行子任務計算:開始值 = 689;結束值 = 750 執行子任務計算:開始值 = 751;結束值 = 813 執行子任務計算:開始值 = 814;結束值 = 875 執行子任務計算:開始值 = 876;結束值 = 938 執行子任務計算:開始值 = 939;結束值 = 1000 累加結果是:500500
Java 8 新特性
1.lambada表示式
Lambda 允許把函式作為一個方法的引數,傳遞到方法中
語法格式:
(parameters) -> expression 或 (parameters) ->{ statements; }
程式碼示例:
Arrays.asList("jay", "Eason", "SHE").forEach( ( String singer ) -> System.out.print( singer + ",") );
2. 函式式介面
Lambda的設計者為了讓現有的功能與Lambda表示式很好相容,設計出函式式介面。
- 函式式介面是指只有一個函式的介面,可以隱式轉換為lambada表示式。
- Java 8 提供了註解@FunctionalInterface,顯示宣告一個函式式介面。
- java.lang.Runnable和java.util.concurrent.Callable是函式式介面的例子~
@FunctionalInterface public interface Runnable { public abstract void run(); }
3. 方法引用
方法引用提供了非常有用的語法,可以直接引用已有Java類或物件(例項)的方法或構造器。它與Lambda表示式配合使用,可以減少冗餘程式碼,使程式碼更加簡潔。
//利用函式式介面Consumer的accept方法實現列印,Lambda表示式如下 Consumer<String> consumer = x -> System.out.println(x); consumer.accept("jay"); //引用PrintStream類(也就是System.out的型別)的println方法,這就是方法引用 consumer = System.out::println; consumer.accept("關注公眾號撿田螺的小男孩");
4. 預設方法
預設方法就是一個在接口裡面有了一個實現的方法。它允許將新方法新增到介面,但不強制實現了該介面的類必須實現新的方法。
public interface ISingerService { // 預設方法 default void sing(){ System.out.println("唱歌"); } void writeSong(); } //JaySingerServiceImpl 不用強制實現ISingerService的預設sing()方法 public class JaySingerServiceImpl implements ISingerService { @Override public void writeSong() { System.out.println("寫了一首七里香"); } }
5.Stream API
Stream API,支援對元素流進行函式式操作,它整合在Collections API 中,可以對集合進行批量操作。常用API:
- filter 篩選
- map流對映
- reduce 將流中的元素組合起來
- collect 返回集合
- sorted 排序
- flatMap 流轉換
- limit返回指定流個數
- distinct去除重複元素
public class Singer { private String name; private Integer songNum; private Integer age; ... } List<Singer> singerList = new ArrayList<Singer>(); singerList.add(new Singer("jay", 11, 36)); singerList.add(new Singer("eason", 8, 31)); singerList.add(new Singer("JJ", 6, 29)); List<String> singerNameList = singerList.stream() .filter(singer -> singer.getAge() > 30) //篩選年齡大於30 .sorted(Comparator.comparing(Singer::getSongNum)) //根據歌曲數量排序 .map(Singer::getName) //提取歌手名字 .collect(Collectors.toList()); //轉換為List
6. Optional
Java 8引入Optional類,用來解決NullPointerException。Optional代替if...else解決空指標問題,使程式碼更加簡潔。
if...else 判空
Singer singer = getSingerById("666"); if (singer != null) { String name = singer.getName(); System.out.println(name); }
Optional的判空
Optional<Singer> singer = Optional.ofNullable(getSingerById("666"));
singer.ifPresent(s -> System.out.println(s.getName()));
7. Date Time API
JDK 8之前的日期API處理存在非執行緒安全、時區處理麻煩等問題。Java 8 在 java.time包下提供了新的日期API,簡化了日期的處理~
LocalDate today = LocalDate.now(); int year = today.getYear(); System.out.println("今年是" + year); //是否閏年 System.out.println("今年是不是閏年:" + today.isLeapYear()); LocalDateTime todayTime = LocalDateTime.now(); System.out.println("當前時間" + todayTime); //時區指定 System.out.println("美國時間:" + ZonedDateTime.of(todayTime,ZoneId.of("America/Los_Angeles"))); LocalDate specailDate = LocalDate.of(2020, 6, 20); LocalDate expectDate = specailDate.plus(100, ChronoUnit.DAYS); System.out.println("比較特別的一天" + specailDate); System.out.println("特殊日期的100天" + expectDate);
8. 重複註解
重複註解,即一個註解可以在一個類、屬性或者方法上同時使用多次;用@Repeatable定義重複註解
@Repeatable(ScheduleTimes.class) public @interface ScheduleTime { String value(); } public @interface ScheduleTimes { ScheduleTime[] value(); } public class ScheduleTimeTask { @ScheduleTime("10") @ScheduleTime("12") public void doSomething() { } }
9. Base64
Java 8把Base64編碼的支援加入到官方庫中~
1 String str = "公眾號:撿田螺的小男孩"; 2 String encoded = Base64.getEncoder().encodeToString(str.getBytes( StandardCharsets.UTF_8)); 3 String decoded = new String(Base64.getDecoder().decode(encoded), StandardCharsets.UTF_8);
10. JVM的新特性
使用元空間Metaspace代替持久代(PermGen space),JVM引數使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize設定大小。
Java 9 新特性
1. java模組系統
什麼是模組化?
一個大型系統,比如一個商城網站,它會包含很多模組的,如:訂單模組,使用者資訊模組,商品資訊模組,廣告位模組等等。各個模組之間會相互呼叫。如果每個模組單獨執行都會帶動其他所有模組,效能非常低效。但是,如果某一模組執行時,只會啟動它所依賴的模組,效能大大提升。這就是JDK 9模組化的思想。
什麼是JDK 9模組化?
Java 平臺模組系統,即Project Jigsaw,把模組化開發實踐引入到了Java平臺中。在引入了模組系統之後,JDK 被重新組織成94個模組。Java 應用可以通過新增的jlink 工具,創建出只包含所依賴的JDK模組的自定義執行時映象。這樣可以極大的減少Java執行時環境的大小。
Java 9 模組的重要特徵:
- 在其工件(artifact)的根目錄中包含了一個描述模組的 module-info.class 文 件。
- 工件的格式可以是傳統的 JAR 檔案或是 Java 9 新增的 JMOD 檔案。
- 這個檔案由根目錄中的原始碼檔案 module-info.java 編譯而來。
- 該模組宣告檔案可以描述模組的不同特徵。
在 module-info.java 檔案中,我們可以用新的關鍵詞module來宣告一個模組,如下所示。下面給出了一個模組com.mycompany.mymodule的最基本的模組宣告
module com.jay.sample { //關鍵詞module來宣告一個模組 exports com.jay.sample; //使用 exports可以宣告模組對其他模組所匯出的包。 requires com.jay.common; //使用requires可以宣告模組對其他模組的依賴關係。 }
2. 不可變集合工廠方法
為了建立不可變集合,JDK9之前醬紫的:
List<String> stringList = new ArrayList<>(); stringList.add("關注公眾號:"); stringList.add("撿田螺的小男孩"); List<String> unmodifiableList = Collections.unmodifiableList(stringList);
JDK 9 提供了List.of()、Set.of()、Map.of()和Map.ofEntries()等工廠方法來建立不可變集合:
List<String> unmodifiableList = List.of("關注公眾號:","撿田螺的小男孩");
3. 介面支援私有方法
JDK 8支援在介面實現預設方法和靜態方法,但是不能在介面中建立私有方法,為了避免了程式碼冗餘和提高閱讀性,JDK 9在介面中支援私有方法。
public interface IPrivateInterfaceTest { //JDK 7 之前 String a = "jay"; void method7(); //JDK 8 default void methodDefault8(){ System.out.println("JDK 8新特性預設方法"); } static void methodStatic8() { System.out.println("JDk 8新特性靜態方法"); } //Java 9 介面支援私有方法 private void method9(){} }
4. 鑽石操作符升級
- 鑽石操作符是在 java 7 中引入的,可以讓程式碼更易讀,但它不能用於匿名的內部類。
- 在 java 9 中, 它可以與匿名的內部類一起使用,從而提高程式碼的可讀性。
//JDK 5,6 Map<String, String> map56 = new HashMap<String,String>(); //JDk 7,8 Map<String, String> map78 = new HashMap<>(); //JDK 9 結合匿名內部類的實現 Map<String, String> map9 = new HashMap<>(){};
5. Optional 類改進
java 9 中,java.util.Optional 添加了很多新的有用方法,如:
- stream()
- ifPresentOrElse()
- or()
ifPresentOrElse 方法的改進就是有了 else,接受兩個引數 Consumer 和 Runnable。
1 import java.util.Optional; 2 3 public class OptionalTest { 4 public static void main(String[] args) { 5 Optional<Integer> optional = Optional.of(1); 6 7 optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() -> 8 System.out.println("Not Present.")); 9 10 optional = Optional.empty(); 11 12 optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() -> 13 System.out.println("Not Present.")); 14 } 15 }
6. 多版本相容Jar包
很多公司使用的JDK都是老版本的,JDK6、JDk5 ,甚至JDk4的,不是他們不想升級JDk版本,而是擔心相容性問題。JDK 9的一個新特性,多版本相容Jar包解決了這個問題。舉個例子:假設你一直用的是小米8,已經非常習慣它的執行流程了,突然出來小米9,即使小米9很多新功能引人入勝,但是有些人不會輕易買小米9,因為已經已經習慣小米8的流程。同理,為什麼很多公司不升級JDK,就是在此。但是呢,JDK 9的這個功能很強大,它可以讓你的版本升級到JDK 9,但是還是老版本的執行流程,即在老的執行流程繼承新的功能~
7. JShell工具
jShell工具相當於cmd工具,然後呢,你可以像在cmd工具操作一樣,直接在上面執行Java方法,Java語句等~
jshell> System.out.println("我愛你,部落格園");
我愛你,部落格園
8. try-with-resources的改進
JDK 9對try-with-resources異常處理機制進行了升級~
//JDK 7,8 try (BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt")) { br.readLine(); }catch(IOException e){ log.error("IO 異常,e:{}",e); } //JDk 9 BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt") try(br){ br.readLine(); }catch(IOException e){ log.error("IO 異常,e:{}",e); }
9. Stream API的改進
JDK 9 為Stream API引入以下這些方法,豐富了流處理操作:
- takeWhile()
- dropWhile()
- iterate
- ofNullable
takeWhile
使用一個斷言(Predicate 介面)作為引數,返回給定Stream的子集直到斷言語句第一次返回 false
// 語法格式 default Stream<T> takeWhile(Predicate<? super T> predicate) //程式碼示例 Stream.of(1,2,3).takeWhile(s-> x<2) .forEach(System.out::println); //輸出 1
dropWhile
與 takeWhile()作用相反,使用一個斷言(Predicate 介面)作為引數,直到斷言語句第一次返回true,返回給定Stream的子集
1 //語法 2 default Stream<T> dropWhile(Predicate<? super T> predicate) 3 //程式碼示例 4 Stream.of(1,2,3).dropWhile(s-> x<2) 5 .forEach(System.out::println); 6 //輸出 7 2 8 3
iterate
iterate() 方法能夠返回以seed(第一個引數)開頭,匹配 Predicate(第二個引數)直到返回false,並使用第三個引數生成下一個元素的元素流。
//語法 static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next) //程式碼示例 IntStream.iterate(2, x -> x < 10, x -> x*x).forEach(System.out::println); //輸出 2 4
ofNullable
如果指定元素為非null,則獲取一個元素並生成單個元素流,元素為null則返回一個空Stream。
//語法 static <T> Stream<T> ofNullable(T t) //程式碼示例 Stream<Integer> s1= Stream.ofNullable(100); s1.forEach(System.out::println) Stream<Integer> s2 = Stream.ofNullable(null); s2.forEach(System.out::println) //輸出 100
10.其他
- HTTP 2客戶端 (支援 WebSocket和 HTTP2 流以及伺服器推送)
- 程序API(控制和管理作業系統程序)
- String底層儲存結構更改(char[]替換為byte[])
- 識別符號新增限制( String _ ="hello"不能用)
- 響應式流 API (支援Java 9中的響應式程式設計)
Java 10 新特性
1.區域性變數型別推斷
JDK 10增加了區域性變數型別推斷(Local-Variable Type Inference)功能,讓 Java 可以像Js裡的var一樣可以自動推斷資料型別。Java中的var是一個保留型別名稱,而不是關鍵字。
JDK 10之前
List<String> list = new ArrayList<String>(); Stream<Integer> stream = Stream.of(1, 2, 3);
JDK 10 之後
var list = new ArrayList<String>(); // ArrayList<String> var stream = Stream.of(1, 2, 3);
var 變數型別推斷的使用也有侷限性,僅侷限於以下場景:
- 具有初始化器的區域性變數
- 增強型for迴圈中的索引變數
- 傳統for迴圈中宣告的區域性變數
而不能用於
- 推斷方法的引數型別
- 建構函式引數型別推斷
- 推斷方法返回型別
- 欄位型別推斷
- 捕獲表示式
2. 不可變集合的改進
JDK 10中,List,Set,Map 提供了一個新的靜態方法copyOf(Collection<? extends E> coll),它返回Collection集合一個不可修改的副本。
JDK 原始碼:
static <E> List<E> copyOf(Collection<? extends E> coll) { return ImmutableCollections.listCopy(coll); }
使用例項:
var oldList = new ArrayList<String>(); oldList.add("歡迎關注公眾號:"); oldList.add("撿田螺的小男孩"); var copyList = List.copyOf(oldList); oldList.add("在看、轉載、點贊三連"); copyList.add("雙擊666"); //UnsupportedOperationException異常
3. 並行全垃圾回收器 G1
JDK 9引入 G1 作為預設垃圾收集器,執行GC 時採用的是基於單執行緒標記掃描壓縮演算法(mark-sweep-compact)。為了最大限度地減少 Full GC 造成的應用停頓的影響,Java 10 中將為 G1 引入多執行緒並行 GC,同時會使用與年輕代回收和混合回收相同的並行工作執行緒數量,從而減少了 Full GC 的發生,以帶來更好的效能提升、更大的吞吐量。
4. 執行緒本地握手
Java 10 中執行緒管控引入JVM安全點的概念,將允許在不執行全域性JVM安全點的情況下實現執行緒回撥,由執行緒本身或者JVM執行緒來執行,同時保持執行緒處於阻塞狀態,這將會很方便使得停止單個執行緒或不停止執行緒成為可能。
5. Optional新增orElseThrow()方法
Optional、OptionalDouble等類新增一個方法orElseThrow(),在沒有值時丟擲異常
6. 其他新特性
- 基於 Java 的 實驗性 JIT 編譯器
- 類資料共享
- Unicode 語言標籤擴充套件
- 根證書
- 基於時間(Time-Based)的版本控制模型
Java 11 新特性
1.字串操作
String類是Java最常用的類,JDK 11增加了一系列好用的字串處理方法
- isBlank() 判空。
- strip() 去除首尾空格
- stripLeading() 去除字串首部空格
- stripTrailing() 去除字串尾部空格
- lines() 分割獲取字串流。
- repeat() 複製字串
// 判斷字串是否為空白 " ".isBlank(); // true // 去除首尾空格 " jay ".strip(); // "jay" // 去除首部空格 " jay ".stripLeading(); // "jay " 去除字串尾部空格 " jay ".stripLeading(); // " jay" // 行數統計 "a\nb\nc".lines().count(); // 3 // 複製字串 "jay".repeat(3); // "jayjayjay"
2.用於 Lambda 引數的區域性變數語法
區域性變數型別推斷是Java 10引入的新特性,但是不能在Lambda 表示式中使用。Java 11再次創新,它允許開發者在 Lambda 表示式中使用 var 進行引數宣告。
var map = new HashMap<String, Object>(); map.put("name", "給給給2"); map.forEach((var k, var v) -> { System.out.println(k + ": " + v); });
3.標準化HTTP Client
Java 9 引入Http Client API,Java 10對它更新,Java 11 對它進行標準化。這幾個版本後,Http Client幾乎被完全重寫,支援HTTP/1.1和HTTP/2 ,也支援 websockets。
HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://github.com/whx123/JavaHome")) .GET() .build(); // 同步 HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); // 非同步 client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(HttpResponse::body) .thenAccept(System.out::println);
4. 單個命令編譯執行原始碼
Java 11增強了Java 啟動器,使之能夠執行單一檔案的Java 原始碼。
- Java 11之前,要執行一個 Java 原始碼必須先編譯,再執行
// 編譯 javac Jay.java // 執行 java Jay
- Java 11之後,只要一個java命令就搞定
java Jay.java
5. ZGC:可伸縮低延遲垃圾收集器
ZGC ,即 Z Garbage Collector(垃圾收集器或垃圾回收器)。它是一個可伸縮的、低延遲的垃圾收集器。 ZGC 主要為了滿足如下目標進行設計:
- GC 停頓時間不超過 10ms
- 既能處理幾百 MB 的小堆,也能處理幾個 TB 的大堆
- 應用吞吐能力不會下降超過 15%(與 G1 回收演算法相比)
- 方便在此基礎上引入新的 GC 特性和利用 colord
- 針以及 Load barriers 優化奠定基礎
- 當前只支援 Linux/x64 位平臺
6.其他一些特性
- 新增 Epsilon 垃圾收集器。
- 支援 TLS 1.3 協議
- 飛行記錄器分析工具
- 動態類檔案常量
- 低開銷的 Heap Profiling
Java 12 新特性
1. Switch 表示式擴充套件(預覽功能)
傳統的switch語句,容易漏寫break而出錯,同時寫法並不簡潔優雅。
Java 12之前
switch (day) { case MONDAY: case FRIDAY: case SUNDAY: System.out.println(6); break; case TUESDAY: System.out.println(7); break; case THURSDAY: case SATURDAY: System.out.println(8); break; case WEDNESDAY: System.out.println(9); break; }
JDk 12 之後,Switch表示式得到增強,能接受語句和表示式。
switch (day) { case MONDAY, FRIDAY, SUNDAY -> System.out.println(6); case TUESDAY -> System.out.println(7); case THURSDAY, SATURDAY -> System.out.println(8); case WEDNESDAY -> System.out.println(9); }
2. 緊湊的資料格式
JDK 12 新增了NumberFormat對複雜數字的格式化
NumberFormat numberFormat = NumberFormat.getCompactNumberInstance(Locale.CHINA, NumberFormat.Style.SHORT); System.out.println(numberFormat.format(100000)); //output 10萬
3. 字串支援transform、indent操作
- transform 字串轉換,可以配合函式式介面Function一起使用
List<String> list1 = List.of("jay", " 給給給2"); List<String> list2 = new ArrayList<>(); list1.forEach(element -> list2.add(element.transform(String::strip) .transform((e) -> "Hello," + e)) ); list2.forEach(System.out::println); //輸出 Hello,jay Hello,給給給2
- indent 縮排,每行開頭增加空格space和移除空格
String result = "Java\n Python\nC".indent(3); System.out.println(result); //輸出 Java Python C
4. Files.mismatch(Path, Path)
Java 12 新增了mismatch方法,此方法返回第一個不匹配的位置,如果沒有不匹配,則返回 -1L。
public static long mismatch(Path path, Path path2) throws IOException;
程式碼示例:
Path file1 = Paths.get("c:\\jay.txt"); Path file2 = Paths.get("c:\\撿田螺的小男孩.txt"); try { long fileMismatch = Files.mismatch(file1, file2); System.out.println(fileMismatch); } catch (IOException e) { e.printStackTrace(); }
5. Teeing Collector
Teeing Collector 是 Streams API 中引入的新的收集器實用程式,它的作用是 merge 兩個 collector 的結果,API格式如下:
public static <T, R1, R2, R> Collector<T, ?, R> teeing(Collector<? super T, ?, R1> downstream1, Collector<? super T, ?, R2> downstream2, BiFunction<? super R1, ? super R2, R> merger)
直接看程式碼例子吧,如下為求學生的平均分和總分的例子
List<Student> studentList= Arrays.asList( new Student("jay", 90), new Student("給給給2", 100), new Student("給給給2", 80) ); String teeingResult=studentList.stream().collect( Collectors.teeing( Collectors.averagingInt(Student::getScore), Collectors.summingInt(Student::getScore), (s1,s2)-> s1+ ":"+ s2 ) ); System.out.println(teeingResult); //90:270
6.其他特性
- 支援unicode 11(684個新字元、11個新blocks、7個新指令碼)
- JVM 常量 API (主要在新的java.lang.invoke.constant包中定義了一系列基於值的符號引用型別,能夠描述每種可載入常量。)
- Shenandoah GC(低暫停時間垃圾收集器)
- G1 收集器提升 (可中止的混合收集集合、及時返回未使用的已分配記憶體)
- 預設CDS檔案
- JMH 基準測試
Java 13 新特性
Switch 表示式擴充套件(引入 yield 關鍵字)
傳統的switch:
private static String getText(int number) { String result = ""; switch (number) { case 1, 2: result = "one or two"; break; case 3: result = "three"; break; case 4, 5, 6: result = "four or five or six"; break; default: result = "unknown"; break;
Java 13之後,value break 語句不再被編譯,而是用 yield 來進行值返回
private static String getText(int number) { return switch (number) { case 1, 2: yield "one or two"; case 3: yield "three"; case 4, 5, 6: yield "four or five or six"; default: yield "unknown"; }; }
2.文字塊升級
Java 13之前,字串不能夠多行使用,需要通過換行轉義或者換行連線符等等,反正就是好麻煩、好難維護。
String html = "<html>\n" + " <body>\n" + " <p>Hello, 給給給2</p>\n" + " </body>\n" + "</html>\n";
Java 13之後,清爽多了~
String html = """
<html>
<body>
<p>Hello, 給給給2</p>
</body>
</html>
""";
3. SocketAPI 重構
- 傳統的Java Socket API(java.net.ServerSocket 和 java.net.Socket)依賴於SocketImpl 的內部實現
- 在 Java 13之前,通過使用 PlainSocketImpl 作為 SocketImpl 的具體實現。
- Java 13 中的新底層實現,引入 NioSocketImpl 的實現用以替換 SocketImpl 的 PlainSocketImpl 實現,此實現與 NIO(新 I/O)實現共享相同的內部基礎結構,並且與現有的緩衝區快取記憶體機制整合在一起。
一個Socket簡單例子:
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class SocketAPITest { public static void main(String[] args) { try (ServerSocket serverSocket = new ServerSocket(8080)){ boolean runFlag = true; while(runFlag){ Socket clientSocket = serverSocket.accept(); //搞事情 } } catch (IOException e) { e.printStackTrace(); } } }
執行以上的例項,看下是否有以下關鍵詞輸出~
[class,load] sun.nio.ch.NioSocketImpl
4.FileSystems.newFileSystem新方法
FileSystems 類中添加了以下三種新方法,以便更容易地使用將檔案內容視為檔案系統的檔案系統提供程式:
- 1、newFileSystem(Path)
- 2、newFileSystem(Path, Map<String, ?>)
- 3、newFileSystem(Path, Map<String, ?>, ClassLoader)
5. 增強 ZGC 釋放未使用記憶體
- ZGC 是Java 11 中引入的最為矚目的垃圾回收特性,是一種可伸縮、低延遲的垃圾收集器。但是實際使用中,它不能夠主動將未使用的記憶體釋放給作業系統。
- Java 13 中對 ZGC 的改進,包括釋放未使用記憶體給作業系統、支援最大堆大小為 16TB、JVM引數-XX:SoftMaxHeapSize 來軟限制堆大小
6.其他特性
- 動態 CDS 存檔, 擴充套件了 Java 10 中引入的類資料共享功能, 使用CDS 存檔變得更容易。
- 文字塊的字串類新方法,如formatted(Object…args),stripIndent()等。
Java 14 新特性
1. instanceof模式匹配
instanceof 傳統使用方式:
if (person instanceof Singer) { Singer singer = (Singer) person; singer.sing(); } else if (person instanceof Writer) { Writer writer = (Writer) person; writer.write(); }
Java 14 對 instanceof 進行模式匹配改進之後
if (person instanceof Singer singer) { singer.sing(); } else if (person instanceof Writer writer) { writer.write(); }
2.Record 型別(預覽功能)
Java 14將Record 型別作為預覽特性而引入,有點類似於Lombok 的@Data註解,看個例子吧:
public record Person(String name, int age) { public static String address; public String getName() { return name; } }
反編譯結果:
public final class Person extends java.lang.Record { private final java.lang.String name; private final java.lang.String age; public Person(java.lang.String name, java.lang.String age) { /* compiled code */ } public java.lang.String getName() { /* compiled code */ } public java.lang.String toString() { /* compiled code */ } public final int hashCode() { /* compiled code */ } public final boolean equals(java.lang.Object o) { /* compiled code */ } public java.lang.String name() { /* compiled code */ } public java.lang.String age() { /* compiled code */ } }
可以發現,當用 Record 來宣告一個類時,該類將自動擁有下面特徵:
- 構造方法
- hashCode() 方法
- euqals() 方法
- toString() 方法
- 類物件被final 關鍵字修飾,不能被繼承。
3. Switch 表示式-標準化
switch 表示式在之前的 Java 12 和 Java 13 中都是處於預覽階段,終於在 Java 14 標準化,成為穩定版本。
- Java 12 為switch 表示式引入Lambda 語法
- Java 13 使用yield代替 break 關鍵字來返回表示式的返回值。
String result = switch (day) { case "M", "W", "F" -> "MWF"; case "T", "TH", "S" -> "TTS"; default -> { if (day.isEmpty()) { yield "Please insert a valid day."; } else { yield "Looks like a Sunday."; } } }; System.out.println(result);
4. 改進 NullPointerExceptions提示資訊
Java 14 之前:
String name = song.getSinger().getSingerName() //堆疊資訊 Exception in thread "main" java.lang.NullPointerException at NullPointerExample.main(NullPointerTest.java:6)
Java 14,通過引入JVM 引數-XX:+ShowCodeDetailsInExceptionMessages,可以在空指標異常中獲取更為詳細的呼叫資訊。
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Singer.getSingerName()" because the return value of "rainRow.getSinger()" is null at NullPointerExample.main(NullPointerTest.java:6)
5. 其他特性
- G1 的 NUMA 可識別記憶體分配
- 刪除 CMS 垃圾回收器
- GC 支援 MacOS 和 Windows 系統
Java 15 新特性
1.EdDSA 數字簽名演算法
- 使用 Edwards-Curve 數字簽名演算法(EdDSA)實現加密簽名。
- 與其它簽名方案相比,EdDSA 具有更高的安全性和效能。
- 得到許多其它加密庫(如 OpenSSL、BoringSSL)的支援。
2.Sealed Classes(封閉類,預覽)
封閉類,可以是封閉類、封閉介面,防止其他類或介面擴充套件或實現它們。
public abstract sealed class Singer permits Jay, Eason{ ... }
類Singer被sealed 修飾,是封閉類,只能被2個指定子類(Jay, Eason)繼承。
3. Hidden Classes(隱藏類)
- 隱藏類天生為框架設計的。
- 隱藏類只能通過反射訪問,不能直接被其他類的位元組碼。
4. Remove the Nashorn JavaScript Engine
- Nashorn太難維護了,移除 Nashorn JavaScript引擎成為一種必然
- 其實早在JDK 11 中就已經被標記為 deprecated 了。
5.Reimplement the Legacy DatagramSocket API(重新實現DatagramSocket API)
- 重新實現老的DatagramSocket API
- 更改java.net.DatagramSocket 和 java.net.MulticastSocket 為更加簡單、現代化的底層實現。
6.其他
- Disable and Deprecate Biased Locking(準備禁用偏向鎖)
- instanceof 自動匹配模式(預覽)
- ZGC,一個可伸縮、低延遲的垃圾回收器。(轉正)
- Text Blocks,文字功能轉正(JDK 13和14預覽,14終於轉正)
- Remove the Solaris and SPARC Ports(刪除 Solaris 和 SPARC 埠)
- 外部儲存器訪問 API(允許Java 應用程式安全有效地訪問 Java 堆之外的外部記憶體。)
- Record型別二次預覽(在Java 14就預覽過啦)
作者:Jay_huaxiao
連結:https://juejin.im/post/6873983588506238990
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。