在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的文件中。我们需要按照下面的方式来运行:

sanaulla@Sana-Laptop  /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/

 

猜你喜欢

转载自blog.csdn.net/wolfcode_cn/article/details/83058169