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塊