Compile: примеры (JAVA)

Руководство по компиляции Java и примерам
Раздел: Верификация (валидация), Регулярные выражения
compile(String regex): Pattern

Описание операции компиляции в Java

Термин «compile» в контексте Java обозначает процесс преобразования исходного кода Java в байт-код (файлы .class) или иной артефакт. Основные способы компиляции в Java: командная утилита javac и программный интерфейс компилятора javax.tools.JavaCompiler. Процесс обычно применяется на этапе сборки, при динамической генерации классов во время выполнения и при реализации инструментов разработки.

Аргументы и опции командного компилятора (частые):

  • -classpath / -cp <path> - поиск зависимостей (библиотек и классов).
  • -d <dir> - каталог вывода для .class файлов.
  • -source <release> - уровень исходного кода (например, 1.8, 11).
  • -target <release> - целевая версия байт-кода.
  • --release <version> - кросс-компиляция с учетом API целевой платформы.
  • -encoding <enc> - кодировка исходников.
  • -parameters - сохранение имен параметров в байт-коде.
  • -proc:none|only - управление запуском процессоров аннотаций.
  • -Xlint[:all|name] - оповещения компилятора.
  • -g - включение отладочной информации (по умолчанию).

Поведение и возвращаемые значения:

  • Командная утилита javac завершает выполнение с кодом возврата 0 при успешной компиляции и ненулевым кодом при ошибках. Сообщения об ошибках выводятся в stderr.
  • Класс javax.tools.JavaCompiler предоставляет метод run(InputStream, OutputStream, OutputStream, String... args), который возвращает int (0 - успех). Более гибкий интерфейс - getTask(...), возвращающий JavaCompiler.CompilationTask, у которого call() возвращает Boolean (true - успешная компиляция).
  • Диагностика ошибок доступна через DiagnosticCollector<?> у программного API и через stderr для javac. Возвращаемые значения отражают успех или неудачу, детали ошибок находятся в сообщениях диагностического потока.

Короткие примеры использования

1) Командная строка: простой пример

// Файл Hello.java
public class Hello {
    public static void main(String[] args) {
        System.out.println("Hi from Java");
    }
}
$ javac Hello.java
$ ls
Hello.class  Hello.java
$ java Hello
Hi from Java

2) Программная компиляция строки кода с JavaCompiler (упрощённый)

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int res = compiler.run(null, null, null, "Hello.java");
System.out.println("exit=" + res);
exit=0  // при успешной компиляции
// при ошибке код будет ненулевым и в stderr появятся сообщения

3) Вызов javac из кода через ProcessBuilder

ProcessBuilder pb = new ProcessBuilder("javac", "Hello.java");
Process p = pb.inheritIO().start();
int code = p.waitFor();
System.out.println("exit=" + code);
exit=0

Похожие инструменты и варианты в Java

Вместо системного javac используются другие компиляторы и подходы, в зависимости от целей.

  • Eclipse Compiler for Java (ECJ)
  • Поддерживает инкрементальную компиляцию. Предпочтителен в IDE и при необходимости быстрого пересобирания модулей.

  • Javac API (javax.tools)
  • Подходит при программной компиляции и необходимости встраивания компилятора в приложение.

  • Инструменты сборки (Maven, Gradle)
  • Автоматизируют компиляцию, управляют зависимостями и жизненным циклом сборки, предпочтительны для проектов с множеством модулей.

  • Ahead-of-Time (AOT) / Native Image
  • Инструменты типа GraalVM native-image создают нативные исполняемые файлы вместо байт-кода; используются при требовании уменьшения времени запуска и уменьшения потребления памяти.

Аналоги компиляции в других языках

Python (динамическая компиляция байт-кода)

import py_compile
py_compile.compile('script.py')
# Создаст файл __pycache__/script.cpython-38.pyc

JavaScript / TypeScript

// TypeScript: tsc hello.ts
// hello.ts
const x: number = 1;
console.log(x);
$ tsc hello.ts
$ node hello.js
1

C# (Roslyn / csc)

// Файл Hello.cs
using System;
class Hello { static void Main(){ Console.WriteLine("Hi"); } }
$ csc Hello.cs
$ mono Hello.exe
Hi

Go

// Файл hello.go
package main
import "fmt"
func main(){ fmt.Println("Hi") }
$ go build -o hello
$ ./hello
Hi

Kotlin

// Файл Hello.kt
fun main(){ println("Hi") }
$ kotlinc Hello.kt -include-runtime -d Hello.jar
$ java -jar Hello.jar
Hi

Lua

-- simple.lua
print('Hi')
-- компиляция в байт-код luac
$ luac -o simple.luac simple.lua
$ lua simple.lua
Hi

Отличия от Java: в некоторых языках (Python, JS) компиляция отражает преобразование в байт-код или транслирование, а в компилируемых языках (C#, Go, Kotlin) процесс похож на javac по созданию исполняемых артефактов. Программные API (Roslyn, py_compile, tsc API) дают возможности, аналогичные JavaCompiler.

Типичные ошибки при компиляции и примеры

1) cannot find symbol / Не найден символ (отсутствует зависимость или ошибка имени)

// File A.java
public class A{ B b; }
// File B.java отсутствует
$ javac A.java
A.java:1: error: cannot find symbol
public class A{ B b; }
               ^
  symbol:   class B
1 error

2) package ... does not exist / Неправильный classpath

import com.example.Lib;
// com/example/Lib.class отсутствует в classpath
error: package com.example does not exist
import com.example.Lib;
^

3) source/target mismatch и --release

// Использование API Java 11 при компиляции с target 1.8
error: 'var' is not allowed in source level 1.8

4) Отсутствие JavaCompiler в среде

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
System.out.println(compiler);
null  // В JRE без JDK доступ к системному компилятору отсутствует

5) Неправильная кодировка исходников

// файл с кириллицей, но без указания -encoding
error: unmappable character for encoding Cp1252

Последние изменения и эволюция процесса компиляции

Компиляция в Java развивалась преимущественно через добавление опций и расширение API, тогда как базовый механизм остался прежним.

  • Java 8: опция -parameters добавлена для сохранения имен параметров в байт-коде.
  • Java 9: введён модульный путь и изменение поведения компиляции для модулей, добавлена опция --release для корректной кросс-компиляции.
  • Поздние релизы: улучшения производительности javac, дополнительные предупреждения в -Xlint и поддержка новых языковых конструкций (local-variable type inference в Java 10 и далее) без изменения API компилятора.
  • javax.tools.JavaCompiler остаётся стабильным API; основные изменения касались расширения диагностических возможностей и поддержки новых флагов командной строки.

Расширенные и редкие сценарии использования

1) Компиляция исходника из строки в памяти и загрузка класса

Пример java
// Упрощённый пример: InMemoryJavaFileObject и класс-лоадер
// Создаётся JavaFileObject из строки, компилируется через JavaCompiler.getTask, затем загружается через кастомный ClassLoader
// Результат: получен класс в рантайме, можно вызвать метод main или другие методы
// Пример выводит: Hello from dynamic class

2) Сборка с указанием модульного пути

Пример java
$ javac --module-path libs -d out --module-source-path src $(find src -name "*.java")
// Компилирует модульную структуру, создаёт модульные artefacts в out

3) Использование DiagnosticCollector для детальной диагностики

Пример java
import javax.tools.*;
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fm = compiler.getStandardFileManager(diagnostics, null, null);
Iterable<JavaFileObject> files = fm.getJavaFileObjectsFromStrings(Arrays.asList("A.java"));
JavaCompiler.CompilationTask task = compiler.getTask(null, fm, diagnostics, null, null, files);
boolean ok = task.call();
for (Diagnostic&lt;?&gt; d : diagnostics.getDiagnostics()) {
    System.out.println(d.getKind() + ": " + d.getMessage(null));
}
// Выводит подробные ошибки/предупреждения с номерами строк и позициями

4) Инкрементальная компиляция с ECJ

Пример java
// Подключение Eclipse Compiler в сборщик для ускорения пересборок
// Конфигурация в Gradle/Maven заменяет вызов javac на ECJ
// Результат: существенно быстреее время пересборки в больших проектах, поддержка специфических фич Eclipse

5) Кросс-компиляция с --release

Пример java
$ javac --release 8 -d out-8 src/com/example/**/*.java
// Сгенерирует байт-код и API, совместимые с Java 8, даже если установлен JDK 11+

6) Компиляция с пользовательским FileManager

Пример java
// FileManager может перенаправлять выходные .class в базу данных, память или сетевой сервис
// Позволяет применять сложные сценарии хранения артефактов и интеграции с облачными пайплайнами

Каждый пример требует учёта прав доступа к JDK (наличие компилятора) и корректной настройки путей (classpath, module-path). Программная компиляция подходит для генерации кода, тестовых фреймворков и плагинов, а командная утилита удобна для CI и локальной сборки.

джава compile function comments

En
Compile Compiles the given regular expression into a pattern