1. Введение
JDK 11 — реализация Java SE 11, выпущенная в сентябре 2018 года.
В этом руководстве мы рассмотрим новую функцию Java 11 для запуска однофайловых программ с исходным кодом.
2. До Java 11
Однофайловая программа — это программа, помещающаяся в один исходный файл.
До Java 11 даже для программы с одним файлом нам приходилось выполнять двухэтапный процесс для запуска программы.
Например, если файл с именем HelloWorld.java
содержит класс HelloWorld
с методом main() ,
мы должны сначала его скомпилировать:
$ javac HelloWorld.java
Это создаст файл класса, который нам нужно будет запустить с помощью команды:
$ java HelloWorld
Hello Java 11!
Обратите внимание: поскольку мы уже создали файл .class
посредством компиляции, команда java
запускает его. В качестве доказательства мы могли бы изменить содержимое, которое мы печатаем в нашем исходном файле, но если мы не скомпилируем его в другой раз, повторный запуск той же команды java
все равно напечатает «Hello world».
Такие программы являются стандартными на ранних этапах изучения Java или при написании небольших служебных программ. В этом контексте необходимость компилировать программу перед ее запуском несколько церемониальна.
Но разве не было бы здорово вместо этого использовать одношаговый процесс? Java 11 пытается решить эту проблему, позволяя нам запускать такие программы непосредственно из исходного кода.
3. Запуск однофайловых программ с исходным кодом
Во-первых, давайте отметим, что в Java 11 мы все еще можем компилировать и запускать наши Java-программы, как мы привыкли делать с более ранними версиями Java.
Кроме того, начиная с Java 11, мы можем использовать следующую команду для выполнения однофайловой программы:
$ java HelloWorld.java
Hello Java 11!
Обратите внимание, как мы передали в команду java
имя файла исходного кода Java, а не класс Java .
JVM компилирует исходный файл в память, а затем запускает первый найденный общедоступный метод main() .
Мы получим ошибки компиляции, если исходный файл содержит ошибки, но в противном случае он будет работать так же, как если бы мы его уже скомпилировали.
Также отметим, что эта команда более либеральна в отношении совместимости имени файла и имени класса.
Например, если бы мы переименовали наш файл WrongName.java
, не меняя его содержимого, мы могли бы запустить его:
java WrongName.java
Это сработает и выведет ожидаемый результат на консоль. Однако если мы попытаемся скомпилировать WrongName.java с помощью команды 'javac', мы получим сообщение об ошибке, поскольку имя класса, определенного внутри файла, не соответствует имени файла.
При этом по-прежнему не рекомендуется не следовать почти универсальным соглашениям об именах. Соответствующее переименование нашего файла или класса должно быть правильным.
4. Параметры командной строки
Средство запуска Java представило новый режим исходного файла
для поддержки этой функции. Режим исходного файла включается, если выполняется одно из следующих двух условий:
- Первый элемент в командной строке, за которым следуют параметры JVM, — это имя файла с расширением
.java .
- Командная строка содержит параметр
–source
version.
Если файл не соответствует стандартным соглашениям об именах для исходных файлов Java, нам нужно использовать параметр –source
. Подробнее о таких файлах мы поговорим в следующем разделе.
Любые аргументы, размещенные после имени исходного файла в исходной командной строке, передаются скомпилированному классу при его выполнении.
Например, у нас есть файл Addition.java
, содержащий класс Addition .
Этот класс содержит метод main()
, который вычисляет сумму своих аргументов:
$ java Addition.java 1 2 3
Кроме того, мы можем передавать такие параметры, как –class-path
перед именем файла:
$ java --class-path=/some-path Addition.java 1 2 3
Теперь мы получим сообщение об ошибке, если в пути к классам приложения есть класс с тем же именем, что и класс, который мы выполняем .
Например, скажем, в какой-то момент во время разработки мы скомпилировали файл, присутствующий в нашем текущем рабочем каталоге, с помощью javac
:
$ javac HelloWorld.java
Теперь у нас есть и HelloWorld.java, и HelloWorld.class
в текущем рабочем каталоге:
$ ls
HelloWorld.class HelloWorld.java
Но, если мы попытаемся использовать режим исходного файла, мы получим ошибку:
$ java HelloWorld.java
error: class found on application class path: HelloWorld
5. Файлы Шебанга
В системах, производных от Unix, таких как macOS и Linux, обычно используется символ «#!» директива для запуска исполняемого файла сценария.
Например, сценарий оболочки обычно начинается с:
#!/bin/sh
Затем мы можем выполнить скрипт:
$ ./some_script
Такие файлы называются «шебанг-файлами».
Теперь мы можем выполнять однофайловые программы Java, используя тот же механизм.
Если мы добавим следующее в начало файла:
#!/path/to/java --source version
Например, давайте добавим следующий код в файл с именем add
:
#!/usr/local/bin/java --source 11
import java.util.Arrays;
public class Addition
{
public static void main(String[] args) {
Integer sum = Arrays.stream(args)
.mapToInt(Integer::parseInt)
.sum();
System.out.println(sum);
}
}
И пометить файл как исполняемый:
$ chmod +x add
Затем мы можем выполнить файл так же, как скрипт:
$ ./add 1 2 3
6
Мы также можем явно использовать программу запуска для вызова файла shebang:
$ java --source 11 add 1 2 3
6
Опция –source
обязательна, даже если она уже присутствует в файле. Шебанг в файле игнорируется и рассматривается как обычный файл Java без расширения .java
.
Однако мы не можем рассматривать файл .java
как файл шебанга, даже если он содержит допустимый шебанг. Таким образом, следующее приведет к ошибке:
$ ./Addition.java
./Addition.java:1: error: illegal character: '#'
#!/usr/local/bin/java --source 11
^
Последнее, что следует отметить в отношении файлов shebang, заключается в том, что директива делает файл зависимым от платформы. Файл нельзя будет использовать на таких платформах, как Windows, которые изначально его не поддерживают.
6. Заключение
В этой статье мы увидели новую функцию исходного кода с одним файлом, представленную в Java 11.
Как обычно, фрагменты кода можно найти на GitHub .