JavaRush /Java блог /Java Developer /Компіляція в Java
Professor Hans Noodles
41 рівень

Компіляція в Java

Стаття з групи Java Developer
Програмування в IDE – прекрасно: пов'язаність залежностей коду, зручний дебаг, зрозуміле тестування, темна тема. Так ось, завдяки IDE розробка розвивається семимильними кроками. Але вона розслабляє. З кожним днем, занурюючись у функціонал IDE, розробник звикає до коміту однією кнопкою або збірки двома кліками. Компіляція в Java - 1Набагато гірша ситуація з новачками в програмуванні, які з самого початку працюють в IDE, ігноруючи роботу в командному рядку. Наприклад, в Intellij IDEA компіляція Java-застосунку демонструється завантажувальним баром у нижній панелі, а всі параметри компіляції, оброблення classpath та інші принади Java-життя залишаються за кадром. Пропонуємо поговорити про компіляцію в Java без IDE. Для запуску прикладів у статті слід переконатися, що на вашій машині встановлено JDK 1.7 і старше.

Як скомпілювати програму?

Компіляція в програмуванні – це приведення вихідного коду в байт-код для подальшого старту програми. Порядок дій від вихідного коду до запуску програм виглядає так:
  1. Є вихідний код у файлі з ім'ям НазваКласу.java;
  2. Якщо в коді немає помилок, він компілюється в байт-код (у файл НазваКласу.class);
  3. Програма запускається.
Зазвичай кожна програма міститься в окремому каталозі. Як найпростіший приклад візьмемо виведення в консоль:

class Test {
   public static void main(String[] args) {
      System.out.println("Це говорить застосунок із командного рядка");
   }
}

Для чого потрібна команда javac

Окей, перший пункт виконано. Йдемо далі, щоб зрозуміти: скомпілювати – це як? :) У цьому нам допоможе команда javac, в аргументі якої необхідно вказати потрібний файл:
javac Test.java
Якщо немає помилок у коді, поруч із файлом Test.java з'явиться файл Test.class. Це і є скомпільований байт-код. Тепер його потрібно запустити. Тут використовується команда java, що запускає байт-код: Компіляція в Java - 2На скриншоті видно, що у виведенні отримуємо якісь ієрогліфи: очевидно, це збите кодування. Зазвичай це відбувається в системі Windows. Для коректного відображення кирилиці в консолі, є такі команди:
REM change CHCP to UTF-8 CHCP 65001 CLS
Вони змінюють поточну кодову сторінку командної консолі на період роботи поточного вікна. Спробуємо ще раз:
D:\Java>java Test
Це говорить застосунок із командного рядка. Знати принцип роботи команди javac дуже корисно, тому що ця команда лежить в основі будь-якої системи збирання проєктів.

Компіляція та виконання декількох класів

Для роботи з кількома класами потрібен classpath. Він схожий на файлову систему, у якій містяться класи, а функцію папок виконують пакети (packages). На цьому етапі варто поміркувати про відокремлення файлів вихідного коду від скомпільованих файлів. Зазвичай вихідні коди знаходяться в каталозі src, а скомпільовані класи – в bin. Наприклад, у нас є клас Box і клас BoxMachine, у якому міститься метод main. Клас Box:

package src;

public class Box {
   private double size;

   public Box(double size) {
       this.size = size;
   }

   public String toString() {
       return "Box have size " + size;
   }
}
Він знаходиться в пакеті src, це необхідно зафіксувати. Клас BoxMachine:

package src;

public class BoxMachine {
   public static void main(String[] args) {
       for(int  i = 0; i < 5; i++) {
           System.out.println(new Box(Math.random()*10));
       }
   }
}
Цей клас також знаходиться в пакеті src. У методі main він створює п'ять об'єктів класу Box різного розміру і виводить у консоль інформацію про них. Щоб скомпілювати цю групу класів, необхідно з головного каталогу (в якому лежать папки src і bin) використовувати команду javac з аргументами:
javac -d bin ./src/*
-d – прапор, після якого слід вказати місце, куди потраплять скомпільовані класи. Це дуже зручно, оскільки перекладати, наприклад, 1000 класів – дуже трудомісткий процес. bin – назва папки. ./src/* – розташування вихідних файлів. * вказує, що необхідно скомпілювати всі файли. Тепер скомпільовані класи з'явилися в папці bin. Для їхнього запуску використовується команда java з тієї ж директорії, також з аргументами:
java -classpath ./bin src.BoxMachine
-classpath – прапор, після якого слід вказати місце розташування скомпільованих класів. Java шукатиме головний клас і всі супутні саме в цій директорії. ./bin – назва папки, в якій знаходяться скомпільовані класи. src.BoxMachine – повна назва головного класу. Як і в першому випадку, не слід вказувати .class, оскільки це назва класу, а не файлу. Виведення:
D:\Java>java -classpath ./bin src.BoxMachine Box have size 4.085985295359718 Box have size 8.63682158248986 Box have size 6.027448124299726 Box have size 7.288317703877914 Box have size 1.106181659384694

Створення JAR-файлів

Щоб програму було легко переносити і запускати, можна зібрати скомпільовані класи в jar-файл – архів класів. Головна відмінність від zip або rar-архівів – наявність файлу маніфесту. У цьому маніфесті вказується головний клас, який буде запускатися під час виконання jar-файлу, classpath, а також багато додаткової інформації. У головному каталозі створимо файл manifest.mf. Його вміст буде таким:
main-class: src.BoxMachine class-path: bin/
main-class вказує клас, який містить метод main і буде виконаний під час запуску. class-path – шлях до скомпільованих класів або додаткових бібліотек. Настав час зібрати справжню програму без IDE за допомогою команди jar:
jar -cmf manifest.mf box-machine.jar -C bin .
-cmf – прапор, після якого слід вказати шлях до файлу маніфесту. manifest.mf – шлях до маніфесту. box-machine.jar – назва вихідного jar-файлу. – прапор, після якого вказується шлях до скомпільованих класів. . – шлях, куди буде поміщено jar-файл. У нашому випадку – це головний каталог. Тепер можна запустити. Запуск jar-файлів виконується також за допомогою команди java, але одразу ж після потрібно вказати прапор -jar: він говорить про те, що запускається Jar-файл, а другий аргумент – шлях до jar-файлу, включно з розширенням:
java -jar box-machine.jar
Виведення:
Box have size 5.5495235762547965 Box have size 9.695870044165662 Box have size 2.3408385788129227 Box have size 7.2790741216674135 Box have size 2.3620854470160513

Компіляція в Java без IDE: огляд систем збирання

Незважаючи на відносну простоту використання командного рядка, з його допомогою дуже складно збирати середні та великі проєкти. Це займає багато часу і загрожує помилками різного ступеня. На щастя, є системи збирання, які в рази полегшують процес роботи. Кількома командами ця система може зібрати проєкт будь-якої складності, а велика кількість плагінів, створених за час існування таких систем, може позбавити практично від будь-якого головного болю.

Як скомпілювати Java?

Найвідоміші системи збирання на Java – це Ant, Maven і Gradle. Серед них немає поганої чи хорошої: кожна з них створена для вирішення певних завдань. Розглянемо кожну з них докладніше.

Ant

Ant – інструмент збирання, який використовує сценарій, описаний за допомогою xml-файлу. Структура xml-файлу:

<?xml version="1.0"?>
<project name="имяПроекта" default="сценарийПоУмолчанию">
    <target name="имяСценария">
  // Дії сценарію
        <echo>Hello, World!</echo>
    </target>
  // Другий сценарій
  // Тощо
</project>
Створимо в головному каталозі файл build.xml з таким вмістом:

<?xml version="1.0"?>
<project name="BoxMachine" default="test">
   <target name="test">
       <echo>First build in Ant!</echo>
   </target>
</project>
У цьому ж каталозі викличемо команду ant:
D:\Java>D:\Temp\ant\bin\ant Buildfile: D:\Java\build.xml test: [echo] First build in Ant! BUILD SUCCESSFUL Total time: 0 seconds
У тезі <target> можна вказувати різні завдання, що дають змогу керувати збиранням і файловою системою. У Ant є понад 150 доступних команд, які вказані в документації. У прикладі нижче використовуємо тільки 5:
  • mkdir – створення директорій
  • delete – видалення файлів і директорій
  • javac – компіляція Java-коду
  • java – запуск скомпільованого коду
Так виглядає простий сценарій компіляції, збирання або очищення:

<?xml version="1.0"?>
<project name="BoxMachine" default="compile">
   <target name="compile">
       <mkdir dir="result/classes"/>
       <javac destdir="result/classes" includeantruntime="false">
           <src path="src"/>
       </javac>
   </target>
   <target name="run" depends="compile">
       <java classname="BoxMachine" classpath="result/classes"/>
   </target>
   <target name="clean">
       <delete dir="result"/>
   </target>
</project>
У сценарії описано три дії – compile, ,code>run і clean. compile створює директорію result, у ній classes, потім за допомогою javac компілює класи у створену директорію. run запускає скомпільовані класи командою java. clean видаляє директорію result. Якщо в головному каталозі виконати команду ant без аргументів, запуститься дія compile. Якщо потрібно виконати певну дію, її вказують в аргументі.
D:\Java>D:/Temp/ant/bin/ant compile Buildfile: D:\Java\build.xml compile: [mkdir] Created dir: D:\Java\result\classes [javac] Compiling 2 source files to D:\Java\result\classes BUILD SUCCESSFUL Total time: 1 second

Maven

Maven пропонує дещо інший підхід до збирання проєктів. Тут розробник радше описує свій проєкт і додаткові інструменти, які використовує, на відміну від Ant, де збирання – це послідовність дій. Maven популярний серед розробників завдяки простому управлінню залежностями та зручній інтеграції з усіма середовищами розробки. Під час роботи з Maven дотримуються такої структури проєкту: Компіляція в Java - 3Правила збирання, залежності та інше описано у файлі pom.xml. Зазвичай він міститься в головній папці проєкту. Під час запуску Maven перевіряє структуру і синтаксис файлу, попереджаючи про помилки. У головній директорії поруч із папками bin і src створюємо файл pom.xml, всередину додаємо:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>ru.javarush.testmaven</groupId>
  <artifactId>testMavenWithoutIde</artifactId>
  <version>1.0.0</version>

  <build>
     <defaultGoal>compile</defaultGoal>
     <sourceDirectory>src</sourceDirectory>
     <outputDirectory>bin</outputDirectory>
     <finalName>${project.artifactId}-${project.version}</finalName>
  </build>
</project>
Далі в командному рядку виконуємо команду mvn:
D:\Java>mvn [INFO] Scanning for projects... [INFO] [INFO] -------------< ru.javarush.testmaven:testMavenWithoutIde >-------------- [INFO] Building testMavenWithoutIde 1.0.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ testMavenWithoutIde --- [WARNING] Using platform encoding (Cp1251 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory D:\Java\src\main\resources [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ testMavenWithoutIde --- [INFO] Changes detected - recompiling the module! [WARNING] File encoding has not been set, using platform encoding Cp1251, i.e. build is platform dependent! [INFO] Compiling 2 source files to D:\Java\bin [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 15.521 s [INFO] Finished at: 2019-06-25T20:18:05+03:00 [INFO] ------------------------------------------------------------------------
Тепер у папці bin є папка src, в якій знаходяться скомпільовані класи. У pom.xml у тезі build визначено ціль збирання – компіляцію, директорії файлів вихідного коду і результату компіляції, а також ім'я проєкту. У Maven є безліч цілей збирання і плагінів для запуску тестування, створення Jar-файлів, збирання дистрибутивів та інших завдань.

Gradle

Це наймолодша система збирання, яка ґрунтується на Ant і Maven. Головна відмінність – робота на базі ациклічного графа для визначення порядку виконання завдань. Це дуже корисно у разі більш складних завдань, наприклад, інкрементальних і багатопроєктних збірках. Під час збирання за допомогою Gradle також рекомендується дотримуватися структури папок проекту Maven. До речі, файл для збирання в Gradle називається build.gradle і має набагато менший вигляд, ніж у Maven. Приклад для наших класів:

apply plugin: 'java'
apply plugin: 'application'

sourceSets {
   main {
       java {
           srcDirs 'src'
       }
   }
}
sourceSets.main.output.classesDir = file("bin")

mainClassName = "src.BoxMachine"

defaultTasks 'compileJava', 'run'
У файлі відбувається підключення плагінів, визначення директорії файлів вихідного коду (якщо не використовується структура проєктів Maven), директорія результатів збирання, ім'я головного класу, а також завдання за замовчуванням. За запуск збирання відповідає команда gradle в директорії, де лежить файл build.gradle:
d:\Java>D:\Temp\gradle\bin\gradle Welcome to Gradle 5.4.1! Here are the highlights of this release: - Run builds with JDK12 - New API for Incremental Tasks - Updates to native projects, including Swift 5 support For more details see https://docs.gradle.org/5.4.1/release-notes.html Starting a Gradle Daemon (subsequent builds will be faster) > Task :help Welcome to Gradle 5.4.1. To run a build, run gradle <task> ... To see a list of available tasks, run gradle tasks To see a list of command-line options, run gradle --help To see more detail about a task, run gradle help --task <task> For troubleshooting, visit https://help.gradle.org BUILD SUCCESSFUL in 52s 1 actionable task: 1 executed

Висновок

На перший погляд, уміння компіляції та збирання коду без IDE здається марним. Дійсно, навіщо мучитися з командними рядками та гуглити всі команди, коли є затишна IDEшечка з плагінами, автоперевіркою всього, що можна (сучасні IDE хіба що рівень IQ не перевіряють) та інтеграцією з популярними системами. Однак практика показує, що вміння збирати код без середовища розробки і розуміння кожного кроку цього процесу – сувора необхідність. Ця навичка заощадить чимало нервових клітин і часу вам і вашій компанії. Освоїти роботу в IDE, попрактикуватися в написанні коду і, звісно ж, отримати фундаментальні основи з програмування на Java ви можете тут – на JavaRush. Час повернутися до навчання :)
Коментарі (1)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
17 лютого 2023
"що на вашій машині встановлено JDK 1.7 і старше." так розумію, що вищі версії від 1.7 мають на увазі? Бо перше прочитання, навело на думку, що потрібно 1.6, 1.5 і т.д., і задумався де такі шукати і для чого їх встановлювати)