1. 程式人生 > 其它 >17.Java 11 的新特性

17.Java 11 的新特性

由於 jdk 9 和 jdk10都不是長期支援的版本,因此將它們的新特性放到 jdk 11 中講

一、JDK 和 JRE 目錄結構的改變

沒有名為jre的子目錄
bin目錄 包含所有命令。在Windows平臺上,它繼續包含系統的執行時動態連結庫
conf目錄 包含使用者可編輯的配置檔案,例如以前位於jre/bin目錄中.properties和.policy檔案
include目錄 包含要在以前編輯原生代碼時使用的C/C++標頭檔案。它只存在於JDK中/td>
jmods目錄 包含JMOD格式的平臺模組。建立自定義執行時映像時需要它。它只存在於JDK中/td>
legal目錄 包含法律宣告
lib目錄 包含非Windows平臺上的動態連線本地庫。其子目錄和檔案不應由開發人員直接編輯或使用

二、模組化系統

  每次JVM啟動的時候,至少會有30~60MB的記憶體載入,主要原因時JVM需要載入rt.jar,不管其中的類是否被classloader載入,第一步整個jar都會被JVM載入到記憶體當中去(而模組化可以根據模組的需要載入程式執行需要的class)。每一個公共類都可以被類路徑之下任何其它的公共類所訪問到,這就會導致無意中使用了並不想被公開訪問的API。

  本質上將,模組(moudule)的概念,其實就是package外再裹一層,也就是說,用模組來管理各個package,通過宣告某個package暴露,不宣告預設就是隱藏。因此,模組化使的程式碼組織上更安全,因此它可以指定哪些部分可以暴露,哪些部分可以隱藏。

實現目標

  • 模組化的主要目的在於減少記憶體的開銷
  • 只須必要模組,而非全部jdk模組,可簡化各種類庫和大型應用的開發和維護
  • 改進 Java SE 平臺,使其可以適應不同大小的計算裝置
  • 改進其安全性,可維護性,提高效能
package stars.grace.test;

import stars.grace.routine.Person;

public class ModuleTest {
    public static void main(String[] args) {

        Person person = new Person("Sakura",10);
        System.out.println(person);
    }
}
module test {
    requires routine;
}
package stars.grace.routine;

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

module routine {
    exports stars.grace.routine;
}

三、Java的REPL工具:jShell命令

  jSell工具讓Java可以像指令碼語言一樣執行,從控制檯啟動jSell,利用jShell在沒有建立類的情況下直接宣告變數,計算表示式,執行語句。即開發時在命令列裡直接執行Java的程式碼,而不需要建立Java檔案。jShell也可以從檔案中載入語句或者將語句儲存到檔案中。jShell也可以使用tab鍵進行自動補全和自動新增分號。

四、語法改進

4.1、介面的私有方法

  Java 8 規定介面中的方法處理抽象方法之外,還可以定義靜態方法和預設方法。一定程度上,拓展了介面的功能,此時的介面更像是一個抽象類。在 Java 9 中,介面更加的靈活和強大,連方法的訪問修飾符都可以宣告為private的,此時方法將不會為你對外暴露的API的一部分。

public class MyInterfaceImplements implements MyInterface{
    public static void main(String[] args) {

        //介面中的靜態方法只能由介面自己呼叫
        MyInterface.staticMethod();

        MyInterfaceImplements myInterfaceImplements = new MyInterfaceImplements();
        myInterfaceImplements.defaultMethod();
        //介面的私有方法,不能在介面外部呼叫
        //myInterfaceImplements.privateMethod();
    }

    @Override
    public void abstractMethod() {
        
    }
    
    @Override
    public void defaultMethod() {
        System.out.println("實現類重寫了介面中的預設方法");
    }
}
public interface MyInterface {

    //許可權修飾符為public
    void abstractMethod();

    //許可權修飾符為public
    static void staticMethod(){
        System.out.println("我是介面中的靜態方法");
    }

    //許可權修飾符為public
    default void defaultMethod(){
        System.out.println("我是介面中的預設方法");
        privateMethod();
    }

    private void privateMethod(){
        System.out.println("我是介面中的私有方法");
    }
}

4.2、鑽石操作符的使用升級

import java.util.ArrayList;
import java.util.Comparator;

public class Template {
    public static void main(String[] args) {

        //JDK 7 中的新特性:型別推斷
        ArrayList<String> list = new ArrayList<>();

        //鑽石操作符與匿名實現類在 Java 8 中不能共存,在 Java 9 中可以
        Comparator<Object> comparator = new Comparator<>(){
            @Override
            public int compare(Object o1, Object o2) {
                return 0;
            }
        };
    }
}

4.3、try語句的升級

  Java 8 中,可以實現資源的自動關閉,但是要求執行後必須關閉的所有資源必須在try子句中初始化,否則編譯不通過。

import java.io.IOException;
import java.io.InputStreamReader;

public class Template {
    public static void main(String[] args) {

        //Java 9 中資源關閉操作:需要自動關閉的資源的例項化可以放在try的一對小括號外、
        //此時的資源屬性是常量,宣告為final,不可修改
        InputStreamReader reader = new InputStreamReader(System.in);
        try(reader){
            char[] cbuf = new char[20];
            int len;
            if((len = reader.read(cbuf)) != -1){
                String str = new String(cbuf,0,len);
                System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

五、型別推斷

  在處理 var 時,編譯器先是查看錶達式右邊的部分,並根據右邊變數值的型別進行推斷,作為左邊變數的型別,然後將該型別寫入位元組碼當中。var 不是關鍵字

import java.util.ArrayList;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class Template {
    public static void main(String[] args) {

        //宣告變數時,根據所賦的指,推斷變數的型別
        //區域性變數不賦值,不能實現型別推斷
        var num = 10;

        var list = new ArrayList<String>();
        list.add("Sakura");
        list.add("Mikoto");
        list.add("Misaka");

        for (var i : list) {
            System.out.println(i);
            System.out.println(i.getClass().getName());
        }

        //Lambda表示式和方法引用中,左邊函式式介面不能宣告var
        //var supplier = () -> Math.random();
        //var consumer = System.out::println;

        //陣列的靜態初始化
        //var array = {1,2,3,4};
    }
}

不能使用型別推斷的情景

  • 沒有初始化的區域性變數的宣告
  • 方法的返回型別
  • 方法的引數型別
  • 構造器的引數型別
  • 屬性
  • catch塊