1. 程式人生 > >在JDK11中執行單檔案程式碼

在JDK11中執行單檔案程式碼

翻譯:叩丁狼教育吳嘉俊 

JEP330-啟動單檔案程式碼程式(Launch Single-File Source-Code Programs)是即將更新的JDK11(18.9)版本中一個很不錯的功能。這個功能允許你直接使用java解析器執行java程式碼。java檔案會在記憶體中執行編譯並且直接執行。唯一的約束在於所有相關的類必須定義在東一個java檔案中。

這個特徵非常適合剛剛準備學習java的童鞋,或者想快速嘗試一些簡單程式碼。這個功能和jshell會成為所有java初學者的最強大的工具。不僅僅如此,所有的成熟的開發,可以使用這個工具來快速驗證和學習新的API。

在本文中,我不會具體去探討這個功能是如何實現的,相反,我們會集中精力在如何使用這個功能。好了,我們仍然從Hello World示例開始!

最基礎的案例

把以下程式碼儲存到Hello.java檔案中:

public class HelloWorld{
    public static void main(String[] args){
        System.out.println("Hello World!!!");
    }
}

我們將會按照下面的方法來執行上面的程式碼:

PS G:\samples\java11\single-file> java HelloWorld.java
Hello World!!!

在上面的例子,我們僅僅只是在一個類中包含了一個main方法。我們直接使用java命令去執行這個.java檔案。如果這個檔案不是以.java結尾,我們可以使用—source引數來執行,這個待會會看到。

包含命令列引數

接下來的案例,我們傳入一個引數,允許給所有人打招呼:

public class Greeting{
    public static void main(String[] args){
        if ( args == null || args.length < 1 ){
            System.err.println("Name required");
            System.exit(1);
        }
        System.out.println(String.format("Hello %s!!", args[0]));
    }
}

我們把上面的程式碼儲存到HelloGreeting.java檔案中。注意,這個檔名字和我們的類的名字不匹配。我們按照如下命令執行:

PS G:\samples\java11\single-file> java HelloGreeting.Java sana
Hello sana!!

任何一個跟在檔名後面的引數都被作為方法的引數傳入方法執行。我們把HelloGreeting.java直接重新命名為greeting(注意,沒有.java字尾),我們再次執行:

PS G:\samples\java11\single-file> java greeting sana
Error: Could not find or load main class greeting
Caused by: java.lang.ClassNotFoundException: greeting

可以看到,在沒有.java結尾的情況下,java編譯器會嘗試直接使用傳入的名稱作為類名去尋找.class檔案。在這種情況下,我們需要使用—source選項:

PS G:\samples\java11\single-file> java --source 11 greeting sana
Hello sana!!

有了—source選項,我們可以非常方便的演示在JDK10中寫的程式碼不能再JDK9中執行的情況:

public class Java10Compatible{
    public static void main(String[] args){
        var message = "Hello world";
        System.out.println(message);
    }
}

我們分別在JDK10和JDK9下執行:

PS G:\samples\java11\single-file> java --source 10 Java10Compatible.java
Hello world
PS G:\samples\java11\single-file> java --source 9 Java10Compatible.java
.\Java10Compatible.java:3: error: cannot find symbol
        var message = "Hello world";
        ^
  symbol:   class var
  location: class Java10Compatible
1 error
error: compilation failed

一個檔案中包含多個類

文章開頭我就提到,這個特性只是要求所有需要執行的程式碼是在同一個java檔案中即可,而沒有規定在這個java檔案中只能有一個類。我們下面就來看看在一個java檔案中包含多個類的情況:

public class SimpleInterest{
    public static void main(String[] args){
        if ( args == null || args.length < 3 ){
            System.err.println("Three arguments required: principal, rate, period");
            System.exit(1);
        }
        int principal = Integer.parseInt(args[0]);
        int rate = Integer.parseInt(args[1]);
        int period = Integer.parseInt(args[2]);
        double interest = Maths.simpleInterest(principal, rate, period);
        System.out.print("Simple Interest is: " + interest);
    }
}

public class Maths{

    public static double simpleInterest(int principal, int rate, int period){
        return ( principal * rate * period * 1.0 ) / 100;
    }
}

我們來執行這個程式碼:

PS G:\samples\java11\single-file> java .\SimpleInterest.java 1000 2 10
Simple Interest is: 200.0

在這個檔案中,我們定義了多個類,但是在執行的時候,java編譯器會執行這個檔案中第一個類中的main方法(注:意思是,這個檔案中的第一個類需要包含main方法,並且這個main方法作為執行的方法)

使用模組

在記憶體中編譯和執行的類會作為一個添加了—add-modules=ALL-DEFAULT引數的匿名模組。這允許程式碼使用不同的模組,而不需要額外的定義module-info.java。

下面我們就來看一個使用了新HTTP Client API的HTTP請求案例。HTTP Client API是Java9作為獨立的模組,放在java.net.http模組中的。下面的程式碼演示了這個特性:

import java.net.http.*;
import java.net.http.HttpResponse.BodyHandlers;
import java.net.*;
import java.io.IOException;

public class ExternalModuleDepSample{
    public static void main(String[] args) throws Exception{
        HttpClient client = HttpClient.newBuilder().build();
        HttpRequest request = HttpRequest.newBuilder()
            .GET()
            .uri(URI.create("https://reqres.in/api/users"))
            .build();

        HttpResponse<String> response = 
            client.send(request, BodyHandlers.ofString());
        System.out.println(response.statusCode());
        System.out.println(response.body());     
    }
}

我們可以直接使用命令執行:

PS G:\samples\java11\single-file>java ExternalModuleDepSample.java
200
{"page":1,"per_page":3,"total":12,"total_pages":4,
"data":[{"id":1,"first_name":"George","last_name":"Bluth",
"avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg"},
{"id":2,"first_name":"Janet","last_name":"Weaver",
"avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg"},
{"id":3,"first_name":"Emma","last_name":"Wong",
"avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/olegpogodaev/128.jpg"}]}

這個特性允許我們快速的實驗一個新的模組,而不需要建立額外的module-info檔案。

Shebang檔案

在本小節中,我們會建立一個shebang檔案。Shebang檔案是Unix系統中常見的檔案,以#!/path/to/executable作為檔案的開頭第一行,可以作為指令碼小程式直接執行一段程式碼。

我們來建立一個shebang檔案:

#!/g/jdk-11/bin/java --source 11

public class SimpleInterest{
    public static void main(String[] args){
        if ( args == null || args.length < 3 ){
            System.err.println("Three arguments required: principal, rate, period");
            System.exit(1);
        }
        int principal = Integer.parseInt(args[0]);
        int rate = Integer.parseInt(args[1]);
        int period = Integer.parseInt(args[2]);
        double interest = Maths.simpleInterest(principal, rate, period);
        System.out.print("Simple Interest is: " + interest);
    }
}

public class Maths{

    public static double simpleInterest(int principal, int rate, int period){
        if ( rate > 100 ){
            System.err.println("Rate of interest should be <= 100. But given values is " + rate);
            System.exit(1);
        }
        return ( principal * rate * period * 1.0 ) / 100;
    }
}

當檔案的名字不符合java命名規範的時候,就可以建立shebang檔案來執行。比如我們上面的程式碼就可以儲存在一個叫simpleInterest的檔案中。我們需要按照下面的方式來執行:

[email protected]  /g/samples/java11/single-file (master)
$ ./simpleInterest 1000 20 2
Simple Interest is: 400.0

在windows下,我們只能使用bash shell來執行。當然,還有諸如Cygwin,Windows 10 Ubuntu Support等工具來執行。

注:JEP330中對Shebang的說明:

Single-file programs are also common when the task at hand needs a small utility program. In this context, it is desirable to be able to run a program directly from source using the “#!” mechanism on Unix-derived systems, such as macOS and Linux. This is a mechanism provided by the operating system which allows a single-file program (such as a script or source code) to be placed in any conveniently named executable file whose first line begins with #! and which specifies the name of a program to “execute” the contents of the file. Such files are called “shebang files”.

原文:https://sanaulla.info/2018/07/05/launch-single-file-source-code-programs-in-jdk-11/