Java9到Java13各版本新特性代碼所有詳解(全網獨家原創)

Java如今已經發展到了Java13了(正式版本),相信不少朋友還對各個版本還不是很熟悉,這裏面專門把Java9到Java13各個版本的一些新特性作了一些詳細講解。我在網上也找了不少,但基本都是官方文檔的CV,沒有任何代碼演示,並且官方的示例代碼也不是很好找獲得,官方API目前仍是Java10,官方文檔真是坑啊。因此我在這裏專門寫了一篇文章,主要針對平時開發與有關的功能Java9到Java13各個版本都作了代碼詳細講解。html

【PS】:這個季節太冷了,南方溼冷,個人手都生凍瘡了,看在年前最後幾天了,沒辦法,我最後選擇去網吧花了幾天時間,網費都花了好幾百塊,爲了打造這篇乾貨不惜下血本啊。終於奮戰幾天寫出來了這篇文章。每個語法細節都通過實例演示過的,我特地把每一個版本的Open JDK都下載了一遍,體驗裏面的細節差距和新特性。java

但願你們點贊,評論和收藏三連,也不負個人一片苦心,謝謝你們了。shell

想得到更多幹貨,歡迎你們多多關注個人博客。本文爲做者AWeiLoveAndroid原創,未經受權,嚴禁轉載express


1、Java 9

【注:】Java9的更新是最多的,這個須要特別注意學一下。編程

Java 9 集合工廠方法

示例:bash

public static void main(String[] args) {
  Set<String> set = Set.of("set1", "set2", "set3");
  // set: [set1, set3, set2]
  System.out.println("set: " + set);
       
  Map<String, String> maps1 = Map.of(
     "map1","Apple", "map2","Orange","map3","Banana", "map4","cherry");
  // maps1: {map3=Banana, map2=Orange, map1=Apple, map4=cherry}        
  System.out.println("maps1: " + maps1);
    
  Map<String, String> maps2 = Map.ofEntries (
           new AbstractMap.SimpleEntry<>("map1","Apple"),
           new AbstractMap.SimpleEntry<>("map2","Orange"),
           new AbstractMap.SimpleEntry<>("map3","Banana"),
           new AbstractMap.SimpleEntry<>("map4","cherry"),
           new AbstractMap.SimpleEntry<>("map5","Apple"),
           new AbstractMap.SimpleEntry<>("map6","Orange"),
           new AbstractMap.SimpleEntry<>("map7","Banana"),
           new AbstractMap.SimpleEntry<>("map8","cherry"),
           new AbstractMap.SimpleEntry<>("map9","Apple"),
           new AbstractMap.SimpleEntry<>("map10","Orange"),
           new AbstractMap.SimpleEntry<>("map11","Banana"),
           new AbstractMap.SimpleEntry<>("map12","cherry")
  );
  // maps2: {map3=Banana, map2=Orange, map1=Apple, map12=cherry, map11=Banana, map10=Orange, 
  // map9=Apple, map8=cherry, map7=Banana, map6=Orange, map5=Apple, map4=cherry}      
  System.out.println("maps2: " + maps2);
}
複製代碼

Java9之前的作法:ide

List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");

Set<String> set = new HashSet<>();
set.add("A");
set.add("B");
set.add("C");

Map<String, String> map = new HashMap<>();
map.put("A","Apple");
map.put("B","Boy");
map.put("C","Cat");
複製代碼

Java9能夠直接輸出集合的內容,在此以前必須遍歷集合才能所有獲取裏面的元素。這是一個很大的改進。函數

Java 9 List,Set 和 Map 接口中,新增靜態工廠方法能夠建立這些集合的不可變實例。工具

Java 9 中,可使用如下方法建立 List,Set 和 Map 的集合對象。重載方法有不少,示例以下:oop

static <E> List<E> of()
static <E> List<E> of(E e1)
static <E> List<E> of(E e1, E e2)
static <E> List<E> of(E e1, E e2, E e3)
static <E> List<E> of(E e1, E e2, E e3, E e4)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
static <E> List<E> of(E... elements)

static <E> Set<E> of()
static <E> Set<E> of(E e1)
static <E> Set<E> of(E e1, E e2)
static <E> Set<E> of(E e1, E e2, E e3)
static <E> Set<E> of(E e1, E e2, E e3, E e4)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9)
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
static <E> Set<E> of(E... elements)


static <K, V> Map<K, V> of() 
static <K, V> Map<K, V> of(K k1, V v1)
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2)
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3)
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4)
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5)
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6)
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6, K k7, V v7)
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6, K k7, V v7, K k8, V v8)
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9)
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10)
static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries)
複製代碼

List ,Set 和Map 接口, of(...) 方法重載了 0 ~ 10 個參數的不一樣方法 。Map 接口若是超過 10 個參數, 可使用 ofEntries(...) 方法。

REPL (JShell)

REPL(Read Eval Print Loop)意爲交互式的編程環境。JShell 是 Java 9 新增的一個交互式的編程環境工具。它容許你無需使用類或者方法包裝來執行 Java 語句。它與 Python 的解釋器相似,能夠直接輸入表達式並查看其執行結果。

例如:

輸入「jshell」打開jshell命令窗口:

輸入「/help」查看幫助信息:

進行運算,建立和使用函數,以及退出:

接口支持私有方法和私有靜態方法:

下圖是Java8和java9的接口的變化的對比:

示例以下:

interface Test{
    String fields = "interface field";

    public abstract void abstractMethods();

    default void defaultMethods() {
        System.out.println("default Method");
        staticMethods();
        privateMethods();
        privateStaticMethods();
     }

    static void staticMethods() {
        System.out.println("static Method");
     }

    private void privateMethods() {
        System.out.println("private Method");
    }
   
    private static void privateStaticMethods() {
        System.out.println("private Static Method");
    }
   
}
複製代碼

接口實現類:

public class TestImpl implements Test{

    @Override
    public void abstractMethods() {
        System.out.println("abstract Method");
    }
    
}
複製代碼

測試類:

public class Demo{
    public static void main(String[] args) {
        TestImpl testImpl = new TestImpl();
        System.out.println(testImpl.fields);
        testImpl.abstractMethods();
        testImpl.defaultMethods();
    }
}
複製代碼

測試結果:

interface field
abstract Method
default Method
static Method
private Method
private Static Method
複製代碼

改進的 Stream API和Optional 類

Java 9 改進的 Stream API ,爲 Stream 新增了幾個方法:dropWhile、takeWhile、ofNullable,爲 iterate 方法新增了一個重載方法,使流處理更容易。

Optional 類在Java8中引入,它的引入很好的解決空指針異常,在 java 9 中, 添加了stream(),ifPresentOrElse()和or()三個方法來改進它的功能。

示例以下:

Stream.of("a","b","c","","e","f").takeWhile(s->!s.isEmpty())
    .forEach(System.out::print);
System.out.println();
Stream.of("10","20","30","","40","50").dropWhile(s-> !s.isEmpty())
    .forEach(System.out::print);
System.out.println();
IntStream.iterate(3, x -> x < 10, x -> x+ 3).forEach(System.out::print);
System.out.println();
System.out.println(Stream.ofNullable(100).count());
System.out.println(Stream.ofNullable(null).count());
複製代碼

結果:

// abc
// 4050
// 369
// 1
// 0
複製代碼
public static void main(String[] args) {
    // stream()用法:
    List<Optional<String>> list = Arrays.asList (
        Optional.of("data1"), 
        Optional.empty(), 
        Optional.of("data2"),
        Optional.empty(),
        Optional.of("data3"));

    List<String> result = list.stream()
    .flatMap(Optional::stream)
    .collect(Collectors.toList());
    // 結果 [data1, data2, data3]
    System.out.println(result); 

  // ifPresentOrElse使用:
  Optional<String> optional = Optional.of("datas");
  // 結果 Value: datas
  optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() -> 
    System.out.println("No data found"));
  optional = Optional.empty();
  // 結果 No data found
  optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() -> 
  System.out.println("No data found"));

    Optional<String> optional1 = Optional.of("datas");
    Supplier<Optional<String>> nullData = () -> Optional.of("No data found");
    optional1 = optional1.or(nullData);
    // Value: datas
    optional1.ifPresent( x -> System.out.println("Value: " + x));

    optional1 = Optional.empty();    
    optional1 = optional1.or(nullData);
    // Value: No data found
    optional1.ifPresent( x -> System.out.println("Value: " + x));

}
複製代碼

改進的 CompletableFuture API

支持 delays 和 timeouts,提高了對子類化的支持,新的工廠方法:

public CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit):在timeout(單位在java.util.concurrent.Timeunits units中,好比 MILLISECONDS )前以給定的 value 完成這個 CompletableFutrue。返回這個 CompletableFutrue。

public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit):若是沒有在給定的 timeout 內完成,就以 java.util.concurrent.TimeoutException 完成這個 CompletableFutrue,並返回這個 CompletableFutrue。

public <U> CompletableFuture<U> newIncompleteFuture():使得CompletableFuture能夠被更簡單的繼承

<U> CompletionStage<U> completedStage(U value):返回一個新的以指定 value 完成的CompletionStage ,而且只支持 CompletionStage 裏的接口。

<U> CompletionStage<U> failedStage(Throwable ex):返回一個新的以指定異常完成的CompletionStage ,而且只支持 CompletionStage 裏的接口。

異常處理機制改進try-with-resources

try-with-resources 聲明在 JDK 9 已獲得改進。若是你已經有一個資源是 final 或等效於 final 變量,您能夠在 try-with-resources 語句中使用該變量,而無需在 try-with-resources 語句中聲明一個新變量。

示例以下:

public static void main(String[] args) throws IOException {
  System.out.println(readData("test"));// 結果:test
}

static String readData(String message) throws IOException {
    Reader inputString = new StringReader(message);
    BufferedReader br = new BufferedReader(inputString); 
    // Java8處理方式:
    // try (BufferedReader br1 = br) {
    //    return br1.readLine();
    // }
    // Java9處理方式:
    try (br) {
      return br.readLine();
    }
}
複製代碼

改進的 @Deprecated 註解

Java 9 中註解增長了兩個新元素:sinceforRemovalsince: 元素指定已註解的API元素已被棄用的版本。 forRemoval: 元素表示註解的 API 元素在未來的版本中被刪除,應該遷移 API。 示例以下:

@Deprecated(since = "1.9", forRemoval = true)
class Test{
}
複製代碼

鑽石操做符(Diamond Operator「<>」)

在 java 9 中, 「<>」能夠與匿名的內部類一塊兒使用,從而提升代碼的可讀性。

示例:

public class Test {
   public static void main(String[] args) {
      Handler<Integer> intHandler = new Handler<>(1) {
         @Override
         public void handle() {
            System.out.println(content);
         }
      };
      intHandler.handle();
      Handler<? extends Number> intHandler1 = new Handler<>(2) {
         @Override
         public void handle() {
            System.out.println(content);
         }
      };
      intHandler1.handle();
      Handler<?> handler = new Handler<>("test") {
         @Override
         public void handle() {
            System.out.println(content);
         }
      };
 
      handler.handle();    
   }  
}
 
abstract class Handler<T> {
   public T content;
 
   public Handler(T content) {
      this.content = content; 
   }
   
   abstract void handle();
}
複製代碼

在java8中,上例中的 newHandler<>後面的<>裏面必須帶有泛型類型。Java9就不須要了。

Unicode 7.0擴展支持:

從Java SE 9,升級現有平臺的API,支持7.0版本的Unicode標準,主要在如下類中:

java.lang.Character和java.lang.String java.text包中的Bidi,BreakIterator和Normalizer 這次升級將包括改善雙向行爲,從而能夠更好地顯示Unicode 6.3中引入的阿拉伯語和希伯來語等文本。 Unicode 7.0自己將添加大約三千個字符和二十多個腳本。

更多詳情請查看: openjdk.java.net/projects/jd…


2、Java 10

這裏重點看咱們開發者可以直接體驗到的一些功能:

var 局部變量類型推斷

示例:

var list = new ArrayList<String>();  // 表明 ArrayList<String>
var stream = list.stream();          // 表明 Stream<String>
複製代碼

這種處理將僅限於帶有初始值設定項的局部變量,加強的for循環中的索引以及在傳統的for循環中聲明的局部變量。它不適用於方法形式,構造函數形式,方法返回類型,字段,catch形式或任何其餘類型的變量聲明。

支持Unicode 8.0。

加強了java.util.Locale和相關的API,以實現BCP 47語言標籤的其餘Unicode擴展。

這次針對BCP 47語言標籤擴展包括:

  • cu (貨幣類型)
  • fw (一週的第一天)
  • rg (區域覆蓋)
  • tz (時區)

具體API變動有:

  • java.text.DateFormat::get*Instance將根據擴展名返回實例ca,rg和/或tz
  • java.text.DateFormatSymbols::getInstance 將根據擴展名返回實例 rg
  • java.text.DecimalFormatSymbols::getInstance 將根據擴展名返回實例 rg
  • java.text.NumberFormat::get*Instance將根據擴展名nu和/或返回實例rg
  • java.time.format.DateTimeFormatter::localizedBy將返回DateTimeFormatter基於擴展狀況下ca,rg和/或tz
  • java.time.format.DateTimeFormatterBuilder::getLocalizedDateTimePattern將根據rg擴展名返回模式字符串。
  • java.time.format.DecimalStyle::of將DecimalStyle根據擴展名返回實例nu,和/或rg
  • java.time.temporal.WeekFields::of將WeekFields根據擴展名fw和/或返回實例rg
  • java.util.Calendar::{getFirstDayOfWeek,getMinimalDaysInWeek}將根據擴展名fw和/或返回值rg
  • java.util.Currency::getInstance將Currency根據擴展名cu和/或返回實例rg
  • java.util.Locale::getDisplayName 將返回一個字符串,其中包括這些U擴展名的顯示名稱
  • java.util.spi.LocaleNameProvider 這些U擴展的鍵和類型將具備新的SPI

其餘特性都是有關垃圾回收,編譯器,證書,以及命令工具等有關的,這裏就不列舉了。

更多詳情請查看: openjdk.java.net/projects/jd…


3、Java 11

局部變量的語法lambda參數

Java11中的lambda表達式能夠爲隱式類型,其中類型的形式參數均可以被推斷出。對於隱式類型的lambda表達式的形式參數,容許使用保留的類型名稱var,以便: (var x, var y) -> x.process(y) 等效於:

(x, y) -> x.process(y) // 這樣的對的
(var x, int y) -> x.process(y)  // 這樣就會報錯
複製代碼

其餘的lambda用法和Java8裏的lambda用法同樣。

啓動單文件源代碼程序

加強java啓動器以運行做爲Java源代碼的單個文件提供的程序,包括經過「 shebang」文件和相關技術從腳本內部使用該程序。

從JDK 10開始,java啓動器以三種模式運行:啓動類文件,啓動JAR文件的main類或啓動模塊的main類。在這裏,咱們添加了新的第四種模式:啓動在源文件中聲明的類。

若是「類名」標識具備.java擴展名的現有文件,則選擇源文件模式,並編譯和運行該文件。該--source選項可用於指定源代碼的源版本。

若是文件沒有.java擴展名,則--source必須使用該選項來強制源文件模式。例如當源文件是要執行的「腳本」而且源文件的名稱不遵循Java源文件的常規命名約定時。

更多詳情請查看: openjdk.java.net/projects/jd…


4、Java 12

對 switch 語句進行擴展:

擴展switch語句,以即可以將其用做語句或表達式,而且兩種形式均可以使用「傳統」或「簡化」做用域並控制流的行爲。這些變化將簡化平常編碼在switch中。這是JDK 12中的預覽功能。

請注意:此JEP已被JDK 13的JEP 354取代。

普通寫法:

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;
}
複製代碼

如今引入一種新的switch標籤形式,寫爲「case L ->」,表示若是匹配標籤,則只執行標籤右邊的代碼。例如,如今能夠編寫之前的代碼:

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);
}
複製代碼

再好比局部變量,普通寫法是這樣的:

int numLetters;
switch (day) {
    case MONDAY:
    case FRIDAY:
    case SUNDAY:
        numLetters = 6;
        break;
    case TUESDAY:
        numLetters = 7;
        break;
    case THURSDAY:
    case SATURDAY:
        numLetters = 8;
        break;
    case WEDNESDAY:
        numLetters = 9;
        break;
    default:
        throw new IllegalStateException("Wat: " + day);
}
複製代碼

如今的寫法是這樣的:

int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    case THURSDAY, SATURDAY     -> 8;
    case WEDNESDAY              -> 9;
};
複製代碼

更多詳情請查看: openjdk.java.net/projects/jd…


5、Java 13

switch表達式預覽版

JDK 13中新增 switch 表達式beta 版本,這是對Java12 switch表達式功能的加強版本,而且Java13版本的switch表達式的更新能夠用於生產環境中。switch 表達式擴展了 switch 語句,使其不只能夠做爲語句(statement),還能夠做爲表達式(expression),而且兩種寫法均可以使用傳統的 switch 語法。

除了Java12的用法以外,Java13的更新引入一個新的關鍵字yield。大多數switch表達式在「case L ->」開關標籤的右側都有一個表達式。若是須要一個完整的塊,須要使用yield語句來產生一個值,該值是封閉switch表達式的值。

示例:

int j = switch (day) {
    case MONDAY  -> 0;
    case TUESDAY -> 1;
    default      -> {
        int k = day.toString().length();
        int result = f(k);
        yield result;
    }
};
複製代碼

上例也可使用傳統的switch語句:

int result = switch (s) {
    case "Foo": 
        yield 1;
    case "Bar":
        yield 2;
    default:
        System.out.println("Neither Foo nor Bar, hmmm...");
        yield 0;
};
複製代碼

switch表達的狀況必須詳細;對於全部可能的值,必須有一個匹配的switch標籤。(顯然,switch聲明並不是必須詳細。)這一般意味着須要一個default子句。可是enum switch對於覆蓋全部已知常量的表達式,default編譯器會插入一個子句以指示該enum定義在編譯時和運行時之間已更改。依靠這種隱式default子句的插入可使代碼更健壯。如今,當從新編​​譯代碼時,編譯器將檢查全部狀況是否獲得明確處理。

此外,switch表達式必須以一個值正常完成,或者必須經過引起異常來忽然完成。這有許多後果。首先,編譯器會檢查每一個開關標籤是否匹配,而後產生一個值。

示例:

int i = switch (day) {
    case MONDAY -> {
        System.out.println("Monday"); 
        // ERROR! Block doesn't contain a yield statement } default -> 1; }; i = switch (day) { case MONDAY, TUESDAY, WEDNESDAY: yield 0; default: System.out.println("Second half of the week"); // ERROR! Group doesn't contain a yield statement
};
複製代碼

另外一種後果是,控制語句,break,yield,return和continue,沒法經過跳switch表達式,示例:

z: 
    for (int i = 0; i < MAX_VALUE; ++i) {
        int k = switch (e) { 
            case 0:  
                yield 1;
            case 1:
                yield 2;
            default: 
                continue z; 
                // ERROR! Illegal jump through a switch expression 
        };
    ...
    }

複製代碼

Text Blocks預覽版(文字塊)

簡單地說就是:能夠跨多行顯示字符串而且不對轉義字符進行轉義。目標是編寫Java程序的任務,同時避免了常見狀況下的轉義序列,加強Java程序中表示用非Java語言編寫的代碼的字符串的可讀性。

在Java中,在字符串文字中嵌入HTML,XML,SQL或JSON片斷"..."一般須要先進行轉義和串聯的大量編輯工做,而後才能編譯包含該代碼塊的代碼。該代碼快一般難以閱讀且難以維護。可是Java13的代碼塊功能會更直觀地表示字符串,並且能夠跨越多行,並且不會出現轉義的視覺混亂,這將提升Java程序的可讀性和可寫性。本質上是二維文本塊,而不是一維字符序列。

基本語法形式:

""" line 1 line 2 line 3 """
複製代碼

等效於:"line 1\nline 2\nline 3\n"

或字符串文字的串聯:

"line 1\n" +
"line 2\n" +
"line 3\n"
複製代碼

若是在字符串的末尾不須要行終止符,則能夠將結束定界符放在內容的最後一行。例如,文本塊:

""" line 1 line 2 line 3"""
複製代碼

具體使用:

字符串裏面寫HTML代碼,

Java13以前寫法:

String html = "<html>\n" +
              " <body>\n" +
              " <p>Hello, world</p>\n" +
              " </body>\n" +
              "</html>\n";
複製代碼

Java13寫法:

String html = """ <html> <body> <p>Hello, world</p> </body> </html> """;
複製代碼

再好比SQL示例:

Java13以前寫法:

String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
               "WHERE `CITY` = 'INDIANAPOLIS'\n" +
               "ORDER BY `EMP_ID`, `LAST_NAME`;\n";
複製代碼

Java13寫法:

String query = """ SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB` WHERE `CITY` = 'INDIANAPOLIS' ORDER BY `EMP_ID`, `LAST_NAME`; """;
               
複製代碼

再好比:

Java13以前寫法:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval("function hello() {\n" +
                         " print('\"Hello, world\"');\n" +
                         "}\n" +
                         "\n" +
                         "hello();\n");
                         
複製代碼

Java13寫法:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval(""" function hello() { print('"Hello, world"'); } hello(); """);

複製代碼

更多詳情請查看: openjdk.java.net/projects/jd…

相關文章
相關標籤/搜索