\documentclass[main.tex]{subfiles} \begin{document} \section{Платформа: история и окружение} \subsection{В этом разделе} Краткая история (причины возникновения); инструментарий, выбор версии; CLI; структура проекта; документирование; некоторые интересные способы сборки проектов. В этом разделе происходит первое знакомство со внутреннем устройством языка Java и фреймворком разработки приложений с его использованием. Рассматривается примитивный инструментарий и базовые возможности платформы для разработки приложений на языке Java. Разбирается структура проекта, а также происходит ознакомление с базовым инструментарием для разработки на Java. \begin{itemize} \item \nom{JDK}{(от англ. Java Development Kit) — комплект разработчика приложений на языке Java, включающий в себя компилятор, стандартные библиотеки классов, примеры, документацию, различные утилиты и исполнительную систему. В состав JDK не входит интегрированная среда разработки на Java, поэтому разработчик, использующий только JDK, вынужден использовать внешний текстовый редактор и компилировать свои программы, используя утилиты командной строки.} \item \nom{JRE}{(от англ. Java Runtime Environment) — минимальная (без компилятора и других средств разработки) реализация виртуальной машины, необходимая для исполнения Java-приложений. Состоит из виртуальной машины Java Virtual Machine и библиотеки Java-классов.} \item \nom{JVM}{(от англ. Java Virtual Machine) — виртуальная машина Java, основная часть исполняющей системы Java. Виртуальная машина Java исполняет байт-код, предварительно созданный из исходного текста Java-программы компилятором. JVM может также использоваться для выполнения программ, написанных на других языках программирования.} \item \nom{JIT}{(англ. Just-in-Time, компиляция «точно в нужное время»), динамическая компиляция — технология увеличения производительности программных систем, использующих байт-код, путём компиляции байт-кода в машинный код или в другой формат непосредственно во время работы программы. Таким образом достигается высокая скорость выполнения по сравнению с интерпретируемым байт-кодом за счёт увеличения потребления памяти (для хранения результатов компиляции) и затрат времени на компиляцию. Технология JIT базируется на двух более ранних идеях, касающихся среды выполнения: компиляции байт-кода и динамической компиляции.} \item \nom{CLI}{(англ. Command line interface, Интерфейс командной строки) — разновидность текстового интерфейса между человеком и компьютером, в котором инструкции компьютеру даются в основном путём ввода с клавиатуры текстовых строк (команд). Также известен под названиями «консоль» и «терминал».} \item \nom{Docker}{программное обеспечение для автоматизации развёртывания и управления приложениями, контейнеризатор приложений. Позволяет «упаковать» приложение со всем его окружением и зависимостями в контейнер, который может быть развёрнут почти на любой системе.} \end{itemize} \nomenclature{GPL}{GNU General Public License (чаще всего переводят как Открытое лицензионное соглашение GNU) — лицензия на свободное программное обеспечение, созданная в рамках проекта GNU, по которой автор передаёт программное обеспечение в общественную собственность. Её также сокращённо называют GNU GPL или даже просто GPL, если из контекста понятно, что речь идёт именно о данной лицензии. GNU Lesser General Public License (LGPL) — это ослабленная версия GPL, предназначенная для некоторых библиотек ПО.} \subsection{Краткая история (причины возникновения)} \begin{itemize} \item Язык создавали для разработки встраиваемых систем, сетевых приложений и прикладного \nom{ПО}{программное обеспечение}; \item Популярен из-за скорости исполнения и полного абстрагирования от исполнителя кода; \item Часто используется для программирования бэк-энда веб-приложений из-за изначальной нацеленности на сетевые приложения. \end{itemize} \begin{figure}[H] \centering \includegraphics[width=17cm]{jc-01-tiobe.png} \caption{График популярности языков программирования TIOBE} \label{pic:java-in-tiobe} \end{figure} \subsubsection{Задания для самопроверки} \begin{enumerate} \item Как Вы думаете, почему язык программирования Java стал популярен в такие короткие сроки? \begin{itemize} \item существовавшие на тот момент Pascal и C++ были слишком сложными; \item Java быстрее C++; \item Однажды написанная на Java программа работает везде. \end{itemize} \end{enumerate} \subsection{Базовый инструментарий, который понадобится (выбор IDE)} \begin{itemize} \item NetBeans - хороший, добротный инструмент с лёгким ностальгическим оттенком; \item Eclipse - для поклонников Eclipse Foundation и швейцарских ножей с полусотней лезвий; \item IntelliJ IDEA - стандарт де-факто, используется на курсе и в большинстве современных компаний; \item Android Studio - если заниматься мобильной разработкой. \end{itemize} \subsubsection{Задания для самопроверки} \begin{enumerate} \item Как Вы думаете, почему среда разработки IntelliJ IDEA стала стандартом де-факто в коммерческой разработке приложений на Java? \begin{itemize} \item NetBeans перестали поддерживать; \item Eclipse слишком медленный и тяжеловесный; \item IDEA оказалась самой дружелюбной к начинающему программисту; \item Все варианты верны. \end{itemize} \end{enumerate} \subsection{Что нужно скачать, откуда (как выбрать вендора, версии)} Для разработки понадобится среда разработки (\nom{IDE}{(от англ. Integrated Development Environment) – это интегрированная, единая среда разработки, которая используется разработчиками для создания различного программного обеспечения. IDE представляет собой комплекс из нескольких инструментов, а именно: текстового редактора, компилятора или интерпретатора, средств автоматизации сборки и отладчика.}) и инструментарий разработчика (JDK). JDK выпускается несколькими поставщиками, большинство из них бесплатны и полнофункциональны, то есть поддерживают весь функционал языка и платформы. В последнее время, с развитием контейнеризации приложений, часто устанавливают инструментарий в Docker-контейнер и ведут разработку прямо в контейнере, это позволяет не захламлять компьютер разработчика разными версиями инструментария и быстро разворачивать свои приложения в \nom{CI}{(англ. Continious Integration) практика разработки программного обеспечения, которая заключается в постоянном слиянии рабочих копий в общую основную ветвь разработки и выполнении частых автоматизированных сборок проекта для скорейшего выявления потенциальных дефектов и решения интеграционных проблем.} или на целевом сервере. \begin{frm} В общем случае, для разработки на любом языке программирования нужны так называемые \nom{SDK}{(от англ. software development kit, комплект для разработки программного обеспечения) — это набор инструментов для разработки программного обеспечения в одном устанавливаемом пакете. Они облегчают создание приложений, имея компилятор, отладчик и иногда программную среду. В основном они зависят от комбинации аппаратной платформы компьютера и операционной системы.} (Software Development Kit, англ. - инструментарий разработчика приложений или инструментарий для разработки приложений). Частный случай такого SDK - инструментарий разработчика на языке Java - Java Development Kit. \end{frm} На курсе будет использоваться BellSoft Liberica JDK 11, но возможно использовать и других производителей, например, самую распространённую Oracle JDK. Производителя следует выбирать из требований по лицензированию, так, например, Oracle JDK можно использовать бесплатно только в личных целях, за коммерческую разработку с использованием этого инструментария придётся заплатить. \begin{frm} Для корректной работы самого инструментария и сторонних приложений, использующих инструментарий, проследите, пожалуйста, что установлены следующие переменные среды ОС: \begin{itemize} \item в системную \code{PATH} добавить путь до исполняемых файлов JDK, например, для UNIX-подобных систем: \verb|PATH=$PATH:/usr/lib/jvm/jdk1.8.0_221/bin| \item \code{JAVA_HOME} путь до корня JDK, например, для UNIX-подобных систем: \code{JAVA_HOME=/usr/lib/jvm/jdk1.8.0_221/} \item \code{JRE_HOME} путь до файлов JRE из состава установленной JDK, например, для UNIX-подобных систем: \code{JRE_HOME=/usr/lib/jvm/jdk1.8.0_221/jre/} \item \code{J2SDKDIR} устаревшая переменная для JDK, используется некоторыми старыми приложениями, например, для UNIX-подобных систем: \code{J2SDKDIR=/usr/lib/jvm/jdk1.8.0_221/} \item \code{J2REDIR} устаревшая переменная для JRE, используется некоторыми старыми приложениями, например, для UNIX-подобных систем: \code{J2REDIR=/usr/lib/jvm/jdk1.8.0_221/jre/} \end{itemize} \end{frm} Также возможно использовать и другие версии, но не старше 1.8. Это обосновано тем, что основные разработки на данный момент только начинают обновлять инструментарий до более новых версий (часто 11 или 13) или вовсе переходят на другие JVM-языки, такие как Scala, Groovy или Kotlin. Иногда для решения вопроса менеджмента версий прибегают к стороннему инструментарию, такому как SDKMan. Для решения некоторых несложных задач курса мы будем писать простые приложения, не содержащие ООП, сложных взаимосвязей и проверок, в этом случае нам понадобится Jupyter notebook с установленным ядром (kernel) IJava. \subsubsection{Задания для самопроверки} \begin{enumerate} \item Чем отличается SDK от JDK? \item Какая версия языка (к сожалению) остаётся самой популярной в разработке на Java? \item Какие ещё JVM языки существуют? \end{enumerate} \subsection{Из чего всё состоит (JDK, JRE, JVM и их друзья)} TL;DR: \begin{itemize} \item JDK = JRE + инструменты разработчика; \item JRE = JVM + библиотеки классов; \item JVM = Native API + механизм исполнения + управление памятью. \end{itemize} Как именно всё работает? Если коротко, то слой за слоем накладывая абстракции. Программы на любом языке программирования исполняются на компьютере, то есть, так или иначе, задействуют процессор, оперативную память и прочие аппаратурные компоненты. Эти аппаратурные компоненты предоставляют для доступа к себе низкоуровневые интерфейсы, которые задействует операционная система, предоставляя в свою очередь интерфейс чуть проще программам, взаимодействующим с ней. Этот интерфейс взаимодействия с \nom{ОС}{(операционная система) — комплекс управляющих и обрабатывающих программ, которые, с одной стороны, выступают как интерфейс между устройствами вычислительной системы и прикладными программами, а с другой стороны — предназначены для управления устройствами, управления вычислительными процессами, эффективного распределения вычислительных ресурсов между вычислительными процессами и организации надёжных вычислений.} мы для простоты будем называть Native API. С ОС взаимодействует JVM (\href{https://ru.m.wikipedia.org/wiki/Список_виртуальных_машин_Java}{Wikipedia: Список виртуальных машин Java}), то есть, используя Native API, нам становится всё равно, какая именно ОС установлена на компьютере, главное уметь выполняться на JVM. Это открывает простор для создания целой группы языков, они носят общее бытовое название JVM-языки, к ним относят Scala, Groovy, Kotlin и другие. Внутри JVM осуществляется управление памятью, существует механизм исполнения программ, специальный JIT\footnote{JIT, just-in-time - англ. в\'{о}время, прямо сейчас}-компилятор, генерирующий платформенно-зависимый код. JVM для своей работы запрашивает у ОС некоторый сегмент оперативной памяти, в котором хранит данные программы. Это хранение происходит «слоями»: \begin{enumerate} \item Eden Space (heap) – в этой области выделяется память под все создаваемые из программы объекты. Большая часть объектов живёт недолго (итераторы, временные объекты, используемые внутри методов и т.п.), и удаляются при выполнении сборок мусора это области памяти, не перемещаются в другие области памяти. Когда данная область заполняется (т.е. количество выделенной памяти в этой области превышает некоторый заданный процент), сборщик мусора выполняет быструю (minor collection) сборку. По сравнению с полной сборкой, она занимает мало времени, и затрагивает только эту область памяти, а именно, очищает от устаревших объектов Eden Space и перемещает выжившие объекты в следующую область. \item Survivor Space (heap) – сюда перемещаются объекты из предыдущей области после того, как они пережили хотя бы одну сборку мусора. Время от времени долгоживущие объекты из этой области перемещаются в Tenured Space. \item Tenured (Old) Generation (heap) — Здесь скапливаются долгоживущие объекты (крупные высокоуровневые объекты, синглтоны, менеджеры ресурсов и прочие). Когда заполняется эта область, выполняется полная сборка мусора (full, major collection), которая обрабатывает все созданные JVM объекты. \item Permanent Generation (non-heap) – Здесь хранится метаинформация, используемая JVM (используемые классы, методы и т.п.). \item Code Cache (non-heap) — эта область используется JVM, когда включена JIT-компиляция, в ней кешируется скомпилированный платформенно-зависимый код. \end{enumerate} JVM самостоятельно осуществляет сборку так называемого мусора, что значительно облегчает работу программиста по отслеживанию утечек памяти, но важно помнить, что в Java утечки памяти всё равно существуют, особенно при программировании многопоточных приложений. \begin{figure}[H] \centering \def\svgwidth{150mm} \input{pics/jc-01-jvm-struct.pdf_tex} \label{jvm:structure} \caption{принцип работы JVM} \end{figure} На пользовательском уровне важно не только исполнять базовые инструкции программы, но чтобы эти базовые инструкции умели как-то взаимодействовать со внешним миром, в том числе другими программами, поэтому JVM интегрирована в JRE - Java Runtime Environment. JRE - это набор из классов и интерфейсов, реализующих \begin{itemize} \item возможности сетевого взаимодействия; \item рисование графики и графический пользовательский интерфейс; \item мультимедиа; \item математический аппарат; \item наследование и полиморфизм; \item рефлексию; \item ... многое другое. \end{itemize} Java Development Kit является изрядно дополненным специальными Java приложениями SDK. JDK дополняет JRE не только утилитами для компиляции, но и утилитами для создания документации, отладки, развёртывания приложений и многими другими. В таблице \ref{table:jdk-contents} на странице \pageref{table:jdk-contents}, приведена примерная структура и состав JDK и JRE, а также указаны их основные и наиболее часто используемые компоненты из состава Java Standard Edition. Помимо стандартной редакции существует и Enterprise Edition, содержащий компоненты для создания веб-приложений, но JEE активно вытесняется фреймворками Spring и Spring Boot. \begin{table}[H] \centering \begin{adjustbox}{angle=90} \begin{tabular}{|l|ll|llllllll|} \cline{1-1} \cline{4-11} \multirow{15}{*}{\rotatebox[origin=c]{270}{Java Development Kit }} & & & \multicolumn{8}{l|}{Language} \\ \cline{4-11} & & & \multicolumn{1}{l|}{\multirow{3}{23mm}{tools + tools api}} & \multicolumn{1}{l|}{javac} & \multicolumn{1}{l|}{java} & \multicolumn{1}{l|}{javadoc} & \multicolumn{1}{l|}{javap} & \multicolumn{1}{l|}{jar} & \multicolumn{2}{l|}{JPDA} \\ \cline{5-11} & & & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{JConsole} & \multicolumn{1}{p{23mm}|}{JavaVisualVM} & \multicolumn{1}{l|}{JMC} & \multicolumn{1}{l|}{JFR} & \multicolumn{1}{l|}{Java DB} & \multicolumn{1}{l|}{Int'l} & JVM TI \\ \cline{5-11} & & & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{IDL} & \multicolumn{1}{l|}{Troubleshoot} & \multicolumn{1}{l|}{Security} & \multicolumn{1}{l|}{RMI} & \multicolumn{1}{l|}{Scripting} & \multicolumn{1}{l|}{Web services} & Deploy \\ \cline{2-2} \cline{4-11} & \multicolumn{1}{l|}{\multirow{11}{*}{\rotatebox[origin=c]{270}{Java Runtime Environment }}} & & \multicolumn{1}{l|}{deployment} & \multicolumn{4}{l|}{Java Web} & \multicolumn{3}{l|}{Applet/Java plug-in} \\ \cline{3-11} & \multicolumn{1}{l|}{} & \multirow{10}{*}{\rotatebox[origin=c]{270}{Java Standard Edition }} & \multicolumn{1}{l|}{\multirow{2}{*}{UI toolkit}} & \multicolumn{2}{l|}{Swing} & \multicolumn{2}{l|}{Java 2D} & \multicolumn{1}{l|}{AWT} & \multicolumn{2}{l|}{Accessibility} \\ \cline{5-11} & \multicolumn{1}{l|}{} & & \multicolumn{1}{l|}{} & \multicolumn{2}{l|}{Drag'n'Drop} & \multicolumn{2}{l|}{Input Methods} & \multicolumn{1}{l|}{Image I/O} & \multicolumn{1}{l|}{Print Service} & Sound \\ \cline{4-11} & \multicolumn{1}{l|}{} & & \multicolumn{1}{p{23mm}|}{Integration libraries} & \multicolumn{1}{l|}{IDL} & \multicolumn{1}{l|}{JDBC} & \multicolumn{1}{l|}{JNDI} & \multicolumn{1}{l|}{RMI} & \multicolumn{1}{l|}{RMI-IIOP} & \multicolumn{2}{l|}{Scripting} \\ \cline{4-11} & \multicolumn{1}{l|}{} & & \multicolumn{1}{l|}{\multirow{3}{23mm}{Other base libraries}} & \multicolumn{2}{l|}{Override Mechanism} & \multicolumn{2}{l|}{Intl Support} & \multicolumn{2}{l|}{Input/Output} & JMX \\ \cline{5-11} & \multicolumn{1}{l|}{} & & \multicolumn{1}{l|}{} & \multicolumn{2}{l|}{XML JAXP} & \multicolumn{2}{l|}{Math} & \multicolumn{2}{l|}{Networking} & Beans \\ \cline{5-11} & \multicolumn{1}{l|}{} & & \multicolumn{1}{l|}{} & \multicolumn{2}{l|}{Security} & \multicolumn{2}{l|}{Serialization} & \multicolumn{2}{l|}{Extension Mechanism} & JNI \\ \cline{4-11} & \multicolumn{1}{l|}{} & & \multicolumn{1}{l|}{\multirow{3}{23mm}{Java lang and util base libs}} & \multicolumn{1}{l|}{JAR} & \multicolumn{1}{l|}{Lang and util} & \multicolumn{2}{l|}{Ref Objects} & \multicolumn{2}{l|}{Preference API} & Reflection \\ \cline{5-11} & \multicolumn{1}{l|}{} & & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{Zip} & \multicolumn{1}{l|}{Management} & \multicolumn{2}{l|}{Instrumentation} & \multicolumn{2}{l|}{Stream API} & Collections \\ \cline{5-11} & \multicolumn{1}{l|}{} & & \multicolumn{1}{l|}{} & \multicolumn{1}{l|}{Logging} & \multicolumn{1}{p{23mm}|}{Regular Expressions} & \multicolumn{2}{p{23mm}|}{Concurrency Utilities} & \multicolumn{2}{l|}{Datetime} & Versioning \\ \cline{4-11} & \multicolumn{1}{l|}{} & & \multicolumn{1}{l|}{JVM} & \multicolumn{7}{l|}{Java Hot Spot VM (JIT)} \\ \hline \end{tabular} \end{adjustbox} \label{table:jdk-contents} \caption{Общее представление состава JDK} \end{table} \subsubsection{Задания для самопроверки} \begin{enumerate} \item JVM и JRE - это одно и тоже? \item Что входит в состав JDK, но не входят в состав JRE? \item Утечки памяти \begin{itemize} \item Невозможны, поскольку работает сборщик мусора; \item Возможны; \item Существуют только в С++ и других языках с открытым менеджментом памяти. \end{itemize} \end{enumerate} \subsection{Структура проекта (пакеты, классы, метод main, комментарии)} Проекты могут быть любой сложности. Часто структуру проекта задаёт сборщик проекта, предписывая в каких папках будут храниться исходные коды, исполняемые файлы, ресурсы и документация. Без их использования необходимо задать структуру самостоятельно. \textbf{Простейший проект} чаще всего состоит из одного файла исходного кода, который возможно скомпилировать и запустить как самостоятельный объект. Отличительная особенность в том, что чаще всего это один или несколько статических методов в одном классе. Файл \code{Main.java} в этом случае может иметь следующий, минималистичный вид \begin{lstlisting}[language=Java,style=JCodeStyle] public class Main { public static void main(String[] args) { System.out.println("Hello, world!"); } } \end{lstlisting} \textbf{Скриптовый проект} это достаточно новый тип проектов, он получил развитие благодаря растущей популярности Jupyter Notebook. Скриптовые проекты удобны, когда нужно отработать какую-то небольшую функциональность или пошагово пояснить работу какого-то алгоритма. \begin{figure}[H] \centering \includegraphics[width=12cm]{jc-01-jupyter-example.png} \caption{Пример простого Java проекта в Jupyter Notebook} \label{pic:jupyter-sample} \end{figure} \textbf{Обычный проект} состоит из пакетов, которые содержат классы, которые в свою очередь как-то связаны между собой и содержат код, который исполняется. \begin{itemize} \item Пакеты. Пакеты объединяют классы по смыслу. Классы, находящиеся в одном пакете доступны друг другу даже если находятся в разных проектах. У пакетов есть правила именования: обычно это обратное доменное имя (например, для gb.ru это будет ru.gb), название проекта, и далее уже внутренняя структура. Пакеты именуют строчными латинскими буквами. Чтобы явно отнести класс к пакету, нужно прописать в классе название пакета после оператора \code{package}. \item Классы. Основная единица исходного кода программы. Одному файлу следует сопоставлять один класс. Название класса - это имя существительное в именительном падеже, написанное с заглавной буквы. Если требуется назвать класс в несколько слов, применяют UpperCamelCase. \item \code{public static void main(String[] args)}. Метод, который является точкой входа в программу. Должен находиться в публичном классе. При создании этого метода важно полностью повторить его сигнатуру и обязательно написать его с название со строчной буквы. \item Комментарии. Это часть кода, которую игнорирует компилятор при преобразовании исходного кода. Комментарии бывают: \begin{itemize} \item \code{// comment} - до конца строки. Самый простой и самый часто используемый комментарий. \item \code{/* comment */} - внутристрочный или многострочный. Никогда не используйте его внутри строк, несмотря на то, что это возможно. \item \code{/** comment */} - комментарий-документация. Многострочный. Из него утилитой Javadoc создаётся веб-страница с комментарием. \end{itemize} \end{itemize} Для примера был создан проект, содержащий два класса, находящихся в разных пакетах. Дерево проекта представлено на рис. \hrf{pic:simple-tree}, где папка с выходными (скомпилированными) бинарными файлами пуста, а файл README.md создан для лучшей демонстрации корня проекта. \begin{figure}[H] \begin{forest} for tree={ font=\ttfamily, grow'=0, child anchor=west, parent anchor=south, anchor=west, calign=first, edge path={ \noexpand\path [draw, \forestoption{edge}] (!u.south west) +(7.5pt,0) |- node[fill,inner sep=1.5pt] {} (.child anchor)\forestoption{edge label}; }, before typesetting nodes={ if n=1 {insert before={[,phantom]}} {} }, fit=band, before computing xy={l=20pt}, } [Sample [src [ru [gb [jcore [regular [OtherClass.java] ] [sample [Main.java] ] ] ] ] ] [out ] [README.md] ] \end{forest} \label{pic:simple-tree} \caption{Структура простого проекта} \end{figure} Содержимое файлов исходного кода представлено ниже. \begin{lstlisting}[language=Java,style=JCodeStyle] package ru.gb.jcore.sample; import ru.gb.jcore.regular.OtherClass; public class Main { public static void main(String[] args) { System.out.println("Hello, world!"); // greetings int result = OtherClass.sum(2, 2); // using a class from other package System.out.println(OtherClass.decorate(result)); } } \end{lstlisting} \begin{lstlisting}[language=Java,style=JCodeStyle] package ru.gb.jcore.regular; public class OtherClass { public static int sum(int a, int b) { return a + b; // return without overflow check } public static String decorate(int a) { return String.format("Here is your number: %d.", a); } } \end{lstlisting} \subsubsection{Задания для самопроверки} \begin{enumerate} \item Зачем складывать классы в пакеты? \item Может ли существовать класс вне пакета? \item Комментирование кода \begin{itemize} \item Нужно только если пишется большая подключаемая библиотека; \item Хорошая привычка; \item Захламляет исходники. \end{itemize} \end{enumerate} \subsection{Отложим мышки в сторону (CLI: сборка, пакеты, запуск)} \label{subsec:cli} Простейший проект возможно скомпилировать и запустить без использования тяжеловесных сред разработки, введя в командной строке ОС две команды: \begin{itemize} \item javac скомпилирует файл исходников и создаст в этой же папке файл с байт-кодом; \item java Name запустит скомпилированный класс (из файла с расширением \code{.class}). \end{itemize} \begin{lstlisting}[style=ASMStyle] ivan-igorevich@gb sources % ls Main.java ivan-igorevich@gb sources % javac Main.java ivan-igorevich@gb sources % ls Main.class Main.java ivan-igorevich@gb sources % java Main Hello, world! \end{lstlisting} \begin{frm} Скомпилированные классы всегда содержат одинаковые первые четыре байта, которые в шестнадцатиричном представлении формируют надпись «кофе, крошка». \begin{figure}[H] \centering \includegraphics[width=14cm]{jc-01-cafe-babe.png} \end{figure} \end{frm} Для компиляции более сложных проектов, необходимо указать компилятору, откуда забирать файлы исходников и куда складывать готовые файлы классов, а интерпретатору, откуда забирать файлы скомпилированных классов. Для этого существуют следующие ключи: \begin{itemize} \item javac: \begin{itemize} \item \code{-d} выходная папка (директория) назначения; \item \code{-sourcepath} папка с исходниками проекта; \end{itemize} \item java: \begin{itemize} \item \code{-classpath} папка с классами проекта; \end{itemize} \end{itemize} Классы проекта компилируются в выходную папку с сохранением иерархии пакетов. \begin{lstlisting}[style=ASMStyle] ivan-igorevich@gb Sample % javac -sourcepath ./src -d out src/ru/gb/jcore/sample/Main.java ivan-igorevich@gb Sample % java -classpath ./out ru.gb.jcore.sample.Main Hello, world! Here is your number: 4. \end{lstlisting} \subsubsection{Задания для самопроверки} \begin{enumerate} \item Что такое javac? \item Кофе, крошка? \item Где находится класс в папке назначения работы компилятора? \begin{itemize} \item В подпапках, повторяющих структуру пакетов в исходниках \item В корне плоским списком; \item Зависит от ключей компиляции. \end{itemize} \end{enumerate} \subsection{Документирование (Javadoc)} Документирование конкретных методов и классов всегда ложится на плечи программиста, потому что никто не знает программу и алгоритмы в ней лучше, чем программист. Утилита Javadoc избавляет программиста от необходимости осваивать инструменты создания веб-страниц и записывать туда свою документацию. Достаточно писать хорошо отформатированные комментарии, а остальное Javadoc возьмёт на себя. \begin{figure}[H] \centering \includegraphics[width=12cm]{jc-01-javadoc.png} \caption{Часть cтраницы автосгенерированной документации} \label{pic:} \end{figure} Чтобы просто создать документацию надо вызвать утилиту javadoc с набором ключей. \begin{itemize} \item \code{ru} пакет, для которого нужно создать документацию; \item \code{-d} папка (или директория) назначения; \item \code{-sourcepath} папка с исходниками проекта; \item \code{-cp} путь до скомпилированных классов; \item \code{-subpackages} нужно ли заглядывать в пакеты-с-пакетами; \end{itemize} Часто необходимо указать, в какой кодировке записан файл исходных кодов, и в какой кодировке должна быть выполнена документация (например, файлы исходников на языке Java всегда сохраняются в кодировке \nom{UTF-8}{(от англ. Unicode Transformation Format, 8-bit — «формат преобразования Юникода, 8-бит») — распространённый стандарт кодирования символов, позволяющий более компактно хранить и передавать символы Юникода, используя переменное количество байт (от 1 до 4), и обеспечивающий полную обратную совместимость с 7-битной кодировкой ASCII. Кодировка UTF-8 сейчас является доминирующей в веб-пространстве. Она также нашла широкое применение в UNIX-подобных операционных системах.}, а основная кодировка для ОС Windows - \nom{cp1251}{набор символов и кодировка, являющаяся стандартной 8-битной кодировкой для русских версий Microsoft Windows до 10-й версии. Была создана на базе кодировок, использовавшихся в ранних русификаторах Windows.}) \begin{itemize} \item \code{-locale ru_RU} язык документации (для правильной расстановки переносов и разделяющих знаков); \item \code{-encoding} кодировка исходных текстов программы; \item \code{-docencoding} кодировка конечной сгенерированной документации. \end{itemize} Чаще всего в комментариях используются следующие ключевые слова: \begin{itemize} \item \code{@param} описание входящих параметров \item \code{@throws} выбрасываемые исключения \item \code{@return} описание возвращаемого значения \item \code{@see} где ещё можно почитать по теме \item \code{@since} с какой версии продукта доступен метод \item \code{{@code "public"}} вставка кода в описание \end{itemize} \subsubsection{Задания для самопроверки} \begin{enumerate} \item Javadoc находится в JDK или JRE? \item Что делает утилита Javadoc? \begin{itemize} \item Создаёт комментарии в коде; \item Создаёт программную документацию; \item Создаёт веб-страницу с документацией из комментариев. \end{itemize} \end{enumerate} \subsection{Автоматизируй это (Makefile, Docker)} В подразделе \hrf{subsec:cli} мы проговорили о сборке проектов вручную. Компилировать проект таким образом — занятие весьма утомительное, особенно когда исходных файлов становится много, в проект включаются библиотеки и прочее. \begin{frm} \code{Makefile} — это набор инструкций для программы \code{make} (классическая, это GNU Automake), которая помогает собирать программный проект в одну команду. Если запустить \code{make} то программа попытается найти файл с именем по-умолчанию \code{Makefile} в текущем каталоге и выполнить инструкции из него. \end{frm} Make, не привносит ничего принципиально нового в процесс компиляции, а только лишь автоматизируют его. В простейшем случае, в \code{Makefile} достаточно описать так называемую цель, \code{target}, и что нужно сделать для достижения этой цели. Цель, собираемая по-умолчанию называется \code{all}, так, для простейшей компиляции нам нужно написать: \begin{lstlisting}[style=ASMStyle] all: javac -sourcepath .src/ -d out src/ru/gb/jcore/sample/Main.java \end{lstlisting} \begin{frm} Внимание поклонникам войны за пробелы против табов в тексте программы: в Makefile для отступов при описании таргетов нельзя использовать пробелы. Только табы. Иначе make обнаруживает ошибку синтаксиса. \end{frm} По сути, это всё. Но возможно сделать более гибко настраиваемый файл, чтобы не нужно было запоминать, как называются те или иные папки и файлы. В Makefile можно записывать переменные, например: \begin{itemize} \item SRCDIR := src \item OUTDIR := out \end{itemize} И далее вызывать их (то есть подставлять их значения в нужное место текста) следующим образом: \begin{lstlisting}[style=ASMStyle] javac -sourcepath .${SRCDIR}/ -d ${OUTDIR} \end{lstlisting} Чтобы вызвать утилиту для сборки цели по-умолчанию, достаточно в папке, содержащей \code{Makefile} в терминале написать \code{make}. Чтобы воспользоваться другими написанными таргетами нужно после имени утилиты написать через пробел название таргета \begin{frm} Docker — программное обеспечение для автоматизации развёртывания и управления приложениями, контейнеризатор приложений. Позволяет «упаковать» приложение со всем его окружением и зависимостями в контейнер, который может быть развёрнут на любой системе, поддерживающей соответствующую технологию. \end{frm} Docker также не привносит ничего технологически нового, но даёт возможность не устанавливать JDK и не думать о переключении между версиями, достаточно взять контейнер с нужной версией инструментария и запустить приложение в нём. Образы и контейнеры создаются с помощью специального файла, имеющего название \code{Dockerfile}. Первой строкой \code{Dockerfile} мы обязательно должны указать, какой виртуальный образ будет для нас основой. Здесь можно использовать как образы ОС, так и образы SDK. \begin{lstlisting}[style=ASMStyle] FROM bellsoft/liberica-openjdk-alpine:11.0.16.1-1 \end{lstlisting} При создании образа необходимо скопировать все файлы из папки \code{src} проекта внутрь образа, в папку \code{src}. \begin{lstlisting}[style=ASMStyle] COPY ./src ./src \end{lstlisting} Потом, также при создании образа, надо будет создать внутри папку \code{out} простой терминальной командой, чтобы компилятору было куда складывать готовые классы. \begin{lstlisting}[style=ASMStyle] RUN mkdir ./out \end{lstlisting} Последнее, что будет сделано при создании образа - запущена компиляция. \begin{lstlisting}[style=ASMStyle] RUN javac -sourcepath ./src -d out ./src/ru/gb/dj/Main.java \end{lstlisting} Последняя команда в \code{Dockerfile} говорит, что нужно сделать, когда контейнер создаётся из образа и заускается. \begin{lstlisting}[style=ASMStyle] CMD java -classpath ./out ru.gb.dj.Main \end{lstlisting} Docker-образ и, как следствие, Docker-контейнеры возможно настроить таким образом, чтобы скомпилированные файлы находились не в контейнере, а складывались обратно на компьютер пользователя через общие папки. Часто команды разработчиков эмулируют таким образом реальный продакшн сервер, используя в качестве исходного образа не JDK, а образ целевой ОС, вручную устанавливают на ней JDK, запуская далее своё приложение. \subsection*{Домашнее задание} \begin{itemize} \item Создать проект из трёх классов (основной с точкой входа и два класса в другом пакете), которые вместе должны составлять одну программу, позволяющую производить четыре основных математических действия и осуществлять форматированный вывод результатов пользователю; \item Скомпилировать проект, а также создать для этого проекта стандартную веб-страницу с документацией ко всем пакетам; \item Создать Makefile с задачами сборки, очистки и создания документации на весь проект. \item *Создать два Docker-образа. Один должен компилировать Java-проект обратно в папку на компьютере подьзователя, а второй забирать скомпилированные классы и исполнять их. \end{itemize} \end{document}