这是Java脚本吗?

對於正在尋找JavaScript相關文章的大家,很抱歉本內容可能無法為您提供幫助,請按瀏覽器的返回按鈕。

此外,這是一個相當嚴肅的 Java 笑話,因此我們請諸位Java初學者不要當真對待。

从OpenJDK 11 开始,可以直接运行Java文件。

最近我刚刚知道,在OpenJDK 11中引入了JEP 330:启动单文件源代码程序,这样就可以在不使用javac等编译的情况下运行单个Java文件的程序。

    • ソース・ファイル・モードで単一ファイルのソース・コードのプログラムを起動する方法

 

    • JEP-330 Single-FIle Source-Code Programs って何? Java ファイルが java コマンドで実行できるってホント?! shebang でどう指定するの?調べてみた!

 

    【Modern Java】JEP 330 Launch Single-File Source-Code Programs

在Shell中,我们使用各种脚本,对吧?在执行带有可执行属性的脚本文件时,Unix系统根据shebang的指定来解释该脚本的程序。像#!/bin/sh或#!/bin/bash这样指定了Shell的脚本被称为”Shell脚本”,而像#!/usr/bin/env perl这样指定了脚本语言的脚本被称为”Perl脚本”。那么,如果指定了#!/usr/bin/env java,这个脚本就被称为”Java脚本”,不是吗?

我在 macOS 上安装了 OpenJDK 15 进行了尝试,但幸好在之前的博客文章中,mike_neck 已经确定了可能出现问题的地方,所以我很顺利地执行了。这看起来很有趣。

Java脚本的文件格式

虽然我还没有完全掌握规范,但我首先会认真查看JEP 330。即使参考了Oracle的文档,最终还是写道要查看JEP 330。

我认为通常脚本都以 shebang 开头,所以在本文中,我将 JEP 330 中称为 shebang 文件的内容称为 Java 脚本。

#!/path/to/java –源代码版本

在JEP 330中提到,可以在第一行中编写如上所述的shebang。然而,我认为通过使用#!/usr/bin/env java –source 11这样的env方式可以提高可移植性。

在一个shebang文件中,前两个字节必须是0x23 0x21。

她的 shebang 必须是由0x23 0x21 字节序列组成。如果想要用 Java 编写,也必须将最开始的两个字节像 UTF-8 那样写入。

shebang 文件的名称不符合 Java 源文件的标准命名规范。

这基本上意思就是,不管是 public class Hello 还是 Hello.java,文件名可以是 hello 或 foobar 等其他名称。虽然不确定是否有意为之,但正如下面的例子一样,即使一个文件中有多个 public class,也能正常运行!

当启动器读取源文件时,如果文件不是Java源文件(即,其文件名不以.java结尾),并且如果第一行以#!开头,则在确定要传递给编译器的源代码时,将忽略该行的内容,直到第一个换行符之前的内容。

Shebang 行不会被传递给编译器,会被忽略。Java 的行注释不是用 #,而是用 //,通过这个技巧使其能够正常工作。

文件名以 .java 结尾时会被认为是 Java 源文件,在这部分会出现编译错误。只要不是 .java 结尾,例如 foobar.js 或 foobar.sh,都可以正常运行。可恼的是,这是无法通过扩展名来表示使用的语言的特性。如果其他人打开这个文件时,会想着”这个脚本怎么有bug啊?”然后竟然是一个 Java 程序!我相信他们一定会大吃一惊的。

剩下的就是普通的Java程序。main方法中的String[] args会完成好工作。

1. 我试着创建一个Shell命令。

作为一个例子,我创建了一个命令,它以x坐标和y坐标作为参数,并返回它们所在的第几象限。

我們試圖通過在程式腳本中宣告使用機會很少的 var 來展現腳本語言的特色。

#!/usr/bin/env java --source 11

public class Quadrant {
    public static void main(String[] args) {
        if (args.length == 2) {
            try {
                 var x = Double.parseDouble(args[0]);
                 var y = Double.parseDouble(args[1]);
                 String s;
                 switch(Coordinate2D.quadrantOf(x, y)) {
                     case 1:  s = "1st"; break;
                     case 2:  s = "2nd"; break;
                     case 3:  s = "3rd"; break;
                     case 4:  s = "4th"; break;
                     default: throw new IllegalStateException();
                 };
                 System.out.println("The quadrant of (" + x + ", " + y + ") is the " + s);
                 System.exit(0);
            } catch (Exception e) {
                 System.err.println(e.getMessage());
            }
        }

        // show usage and exit abnormally
        System.err.println("usage: quadrant x y");
        System.err.println("       where x and y are non-zero coordinate values in double");
        System.exit(1);
    }
}

public class Coordinate2D {
    public static int quadrantOf(double x, double y) {
        if (x > 0.0 && y > 0.0)
            return 1;
        else if (x < 0.0 && y > 0.0)
            return 2;
        else if (x < 0.0 && y < 0.0)
            return 3;
        else if (x > 0.0 && y < 0.0)
            return 4;
        else
            throw new IllegalArgumentException("point must not be on any axis");
    }
}

最近我多数使用IntelliJ,但这次为了体验写脚本的感觉,我使用了vim。switch语句的密集描述是因为没有使用格式化工具。我喜欢switch表达式,因为它不容易出错,但为了使脚本具有高可移植性,我选择了Java 11,并不情愿地用switch语句编写了脚本。

也许是因为我对Java很熟悉,所以写错误处理感觉很容易。只有我在Shell脚本中处理错误总是匆忙马虎吗?

% chmod +x quadrant
% ./quadrant  
usage: quadrant x y
       where x and y are non-zero coordinate values in double
% echo $?
1
% ./quadrant 2 -3
The quadrant of (2.0, -3.0) is the 4th
% echo $?
0

你真的不会觉得这是用Java编写的,只看到这些东西时候,实际上是这样。

尝试在 Java 脚本中执行 JavaScript

下一步,我们将使用令人怀念的 Rhino,在Java脚本中执行JavaScript。

Rhino.png

https://github.com/mozilla/rhino 的 “JavaScript in Java” 这个信息恰好符合我的心情。

说实话,在 JDK 自带的时候我从未使用过 Rhino。今天是我第一次使用它,但官方文档让我感到困惑…。不过,我只是想通过 Java 脚本执行 JavaScript,仅此而已。

经过一番适当的搜索,我找到了一个使用Rhino从Java调用外部JavaScript文件的简单示例,这个示例很容易理解。所以我将它简化并将其转换为执行JavaScript的Java脚本。

#!/usr/bin/env java --source 11 -cp rhino-1.7.13.jar

import org.mozilla.javascript.Context;

class JavaScriptInJavaScript {
    public static void main(String[] args) throws Exception {
        var ctx = Context.enter();
        var obj = ctx.evaluateString(
            ctx.initStandardObjects(),
            "'Java' + 'Script'",
            "<Java script>",
            1,
            null
        );
        System.out.println(obj + " in a Java script!");
    }
}

我使用 Shebang 在类路径中指定了Rhino的jar包。

% curl -OsSL https://github.com/mozilla/rhino/releases/download/Rhino1_7_13_Release/rhino-1.7.13.jar 
% chmod +x javascript_in_java_script 
% ./javascript_in_java_script 
JavaScript in a Java script!

我可以从Java脚本中执行JavaScript并得到’Java’ + ‘Script’这个结果。

最后

你觉得怎么样?崩坏JavaScript概念的过程有点有趣。

我会全力以赴,认真整理。

Shell脚本常常无法理解各种B Shell之间微小的行为差异,往往只能在bash和特定的Linux发行版上运行。虽然可以通过使用脚本语言来避免这个问题,但另一方面会经常面临无法使用perl或python3的环境的缺点。

我认为,在以Java 11或更高版本开发的项目中,有能力运行Java脚本的JDK的两个Java命令具有以下特点:静态类型、便于确保Java程序员的可移植性等。因此,我认为它们是作为脚本语言的选择的一个值得考虑的候选项。

我可能還沒有足夠的勇氣在實務中使用它,但對於讀者們來說,挑戰一下「一次編寫,到處運行」的Java腳本也是很有趣的吧。期待您的報告。

和你一起使用JavaScript,立刻运行。

请使用#!/usr/bin/env node指定这是一个“JavaScript脚本”。 我可以接受异议。 ↩

GraalVM不受支持。 ↩

仅限于解释Shebang的环境。 ↩

请使用您喜欢的文件扩展名。 ↩