Настройка окружения для программирования на Java

19 мая 2014

Как ни крути, но Java — популярный язык программирования и программистам довольно часто приходится иметь с ним дело, нравится им это или нет. Причины могут быть разные. Возможно, вы хотите запустить примеры к прочитанной недавно книге. Или вы работаете с софтом, написанном на Java (Cassandra, Voldemort, Hadoop, ZooKeeper, Jenkins, …). Или вы просто играетесь с одним из относительно новых языков под JVM, например, Groovy, Scala, Clojure или даже каким-нибудь Frege. В общем, Java уже повсюду, и хочешь не хочешь, а приходится в ней немного разбираться.

На самом деле, есть подозрения, что Java не так уж плоха, как о ней говорят. Статическая типизация? Хорошо. Автоматическая сборка мусора? Отлично. Кроссплатформенность? Неплохая скорость дробления чисел? Множество готовых библиотек? Готовый инструментарий? Куча написанных книг? Лямбды и параллельные коллекции начиная с Java 8? Просто супер! Более того, в ранних версиях Java были даже легковесные потоки, но от них, к сожалению, решили отказаться. Есть, конечно, и множество шероховатостей, но, во всяком случае, общая идея, надо признать, правильная.

Нельзя не сказать пару слов о местной терминологии. В мире Java любят всякие непонятные аббревиатуры. В частности, вам часто будут встречаться следующие:

  • JRE (Java Runtime Environment) — это виртуальная машина Java и стандартная библиотека, то есть, минимум из того, что необходимо для запуска Java-приложений;
  • JDK (Java Development Kit) включает в себя компилятор Java (javac) и прочие утилиты, документацию, примеры, а также JRE — то есть, JDK представляет собой минимальный набор инструментов, необходимый программисту на Java;
  • SDK (Software Development Kit) — устаревший термин, означающий в точности то же самое, что и JDK;
  • Java SE (Standard Edition) представляет собой стандартный вариант платформы Java, «for general-purpose use», в состав Java SE входят такие стандартные библиотеки, как java.io, java.net, java.math и тд;
  • Java ME (Micro Edition), урезанный вариант SE для использования на мобильных устройствах, телевизорах и так далее, включает в себя некоторые библиотеки, специфичные для такого окружения;
  • Java EE (Enterprise Edition), расширенный вариант Java SE, в который дополнительно входят JMS (API для обмена сообщениями), библиотеки для парсинга XML, сервлеты и много чего еще;
  • JNI (Java Native Interface) — такая штука, которая позволяет вызывать код на ассемблере, Си и C++ из Java, а также наоборот. В сообществе джавников использование JNI не очень приветствуется, но, скажем, на серверсайде, если очень нужно — почему бы и нет;

Установка JDK. Есть больше одной реализации JDK, наиболее популярными являются OpenJDK и Oracle JDK. Опытные джавники заверили меня, что OpenJDK ни на что не годится и что дескать пользоваться нужно только Oracle JDK. Мои личные наблюдения это подтверждают, на Oracle JDK Java-приложения работают заметно быстрее. Установку Oracle JDK мы уже рассматривали здесь. Если в двух словах:

sudo apt-get remove openjdk\*
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java7-installer
sudo apt-get install oracle-java7-unlimited-jce-policy

Должна успешно установиться Java 1.7. Проверяем, сказав java -version.

Также нам понадобится Maven (о нем чуть ниже):

sudo apt-get install maven

Касательной версий Java нужно отметить, что тут есть небольшая путаница. Строго говоря, версии имеют номера 1.1, 1.2 и так далее до последней на сегодняшний день 1.8. Но единичку в начале иногда опускают. То есть, Java 7 и Java 1.7 — это одно и то же. Приложения на Java не всегда одинаково хорошо работают на разных версиях виртуальной машины Java. Очевидно, что если приложение писалось под Java 6, оно может не запуститься на Java 5. Но я наблюдал и обратное. Приложение, которое писалось и тестировалось на Java 6 может не совсем корректно работать, а то и вовсе не запускаться на Java 7.

Писать на Java без IDE, например, в Vim, можно, но не очень удобно. Отчасти это связано с необходимостью писать всякие public static void, отчасти — с явной декларацией типов, отчасти — с тем, что для разрешения конфликтов имен в Java принято давать имена пакетов в стиле ru.example.some.package, то есть, как бы доменное имя, записанное задом наперед. Также предполагается, что вы владеете доменом example.ru, и потому ваши имена не будут конфликтовать с именами других разработчиков. При этом классы в пакете должны находится в каталоге src/main/java/ru/example/some/package — седьмой вложенности! В общем и целом, без IDE на Java писать очень грустно.

Никакой IDE по умолчанию в JDK не входит, поэтому возникает проблема выбора. IDE под Java много, например, Eclipse, NetBeans и IntelliJ IDEA. Опрос среди коллег-джавников показал, что IDEA является наиболее адекватной (быстрой, удобной, …), поэтому ею и воспользуемся. Качаем с сайта JetBrains последнюю бесплатную версию (Community Edition), распаковываем куда-нибудь архив.

У себя для запуска IntelliJ IDEA я положил в ~/bin такой скрипт:

#!/bin/sh

/home/eax/path/to/idea-ide/bin/idea.sh

В моем оконном менеджере теперь можно просто сказать «Ctr+D → idea» и IntelliJ IDEA будет запущена. Приятной неожиданностью лично для меня оказалось то, что как под Linux, так и под Windows (я не поленился проверить), IntelliJ IDEA внешне практически не отличается от нативных приложений, несмотря на то, что написана она на Swing, а не SWT.

Давайте попробуем создать новый проект. Create New Project → Java/Maven → Next. В GroupId пишем «ru.example», в ArtifactId — «helloworld», жмем Next. В поле Project name указываем «HelloWorld», затем находим Project SDK. Фактически, IntelliJ IDEA найдет подходящий путь за нас. Лично у меня он получился таким: /usr/lib/jvm/java-6-oracle. Жмем Finish. После первого запуска IntelliJ IDEA может иногда тупить, поскольку она будет занята индексацией классов и еще чем-то. Поглядывайте на статусбар внизу IDE.

Дополнение: На самом деле, с Java 6 лучше не связывайтесь. Работать с этой версией очень грустно из-за отсутствия try с ресурсами, diamond syntax, классов Path и Files, возможности ловить несколько исключений в одном catch’е, а также других фичей. Берите сразу Java 7 или старше.

Теперь создаем новый пакет таким образом:

Создание нового пакета в IntelliJ IDEA

В качестве имени пакета указываем «ru.example.helloworld».

Создаем новый класс в только что созданном пакете:

Создание нового класса в Создание нового пакета в IntelliJ IDEA

В качестве имени класса указываем «HelloWorld». Вводим следующий код:

package ru.example.helloworld;

/**
 * Hello world class
 */

public class HelloWorld {
    public static void main(String args[]) {
        System.out.println("Hello!");
    }
}

Компилируем и запускаем программу, нажав Shift+F10. В появившемся терминале должны увидеть сообщение «Hello!».

Если теперь посмотреть на структуру проекта, она окажется примерно такой:

.
+-- HelloWorld.iml
+-- pom.xml
+-- src
|   +-- main
|   |   +-- java
|   |   |   +-- ru
|   |   |       +-- example
|   |   |           +-- helloworld
|   |   |               +-- HelloWorld.java
|   |   +-- resources
|   +-- test
|       +-- java
+-- target
    +-- classes
    |   +-- ru
    |       +-- example
    |           +-- helloworld
    |               +-- HelloWorld.class
    +-- generated-sources
        +-- annotations

В src/main лежат основные исходники, с разбивкой по использованным в проекте языкам программирования. В src/test лежит код тестов. В target/classes лежат скомпилированные классы. Файл pom.xml содержит информацию о проекте и его зависимостях. Это своего рода аналог rebar.config из мира Erlang или .cabal файла из мира Haskell. Аналог Rebar или Cabal здесь называется Maven. Помимо Maven есть и другие аналогичные утилиты, например SBT. Последний заточен под Scala. Но даже скалолазы по привычке часто продолжают пользоваться Maven.

Давайте попробуем поделать что-нибудь из консоли, чтобы лучше понимать, что как работает.

Например, запустить нашу программу можно так:

java -cp ./target/classes ru.example.helloworld.HelloWorld

Вместо -cp можно использовать -classpath. Понятно, что эта опция задает путь до каталогов со скомпилированными классами. Также эти пути можно указать в переменной окружения $CLASSPATH. Последним аргументом в нашей команде указывается имя класса. Этот класс должен иметь метод main, который и будет вызван виртуальной машиной.

Сделаем ужасное. Удалим скомпилированный класс и соберем проект вручную, используя Maven:

rm ./target/classes/ru/example/helloworld/HelloWorld.class
mvn compile

Нетрудно убедиться, что файл .class снова появился и программа запускается, как и раньше.

Это все, конечно, замечательно, но распространять наше приложение в таком виде мы не можем. Сначала нам нужно упаковать его в исполняемый независимый (standalone) jar’ник. Эта задача решается при помощи Assembly Plugin для Maven. Подключается он довольно просто. Открываем в IDEA файл pod.xml и перед закрывающим тэгом </project> дописываем:

<build>
  <plugins>
    <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>ru.example.helloworld.HelloWorld</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </plugin>
  </plugins>
</build>

В консоли говорим:

mvn compile assembly:single

Если все было сделано правильно, мы получим исполняемый jar’ник, который можно запустить так:

java -jar ./target/helloworld-1.0-SNAPSHOT-jar-with-dependencies.jar

Этот jar-файл можно переименовать во что угодно и распространять, как готовое Java-приложение. Ну разве что можно упаковать вместе с ним пару скриптов для Windows и *nix, говорящих java -jar.

За кадром осталось еще много вопросов, например, использование в проекте сторонних библиотек, интеграция IntelliJ IDEA с системой контроля версий, отладка, и так далее. Может быть, когда-нибудь эти вопросы будут освещены в отдельной заметке.

В качестве источников дополнительной информации, насколько я могу судить, можно порекомендовать:

Ну и дальше все зависит от интересующих вас задач — Spring, Hibernate, Swing, Netty или чем там принято решать проблему c10k в Java, разработка мобильных приложений под Android и так далее.

Отмечу, что я далеко не специалист по Java, так что если вы видите неточности в тексте, или у вас есть дополнения, не стесняйтесь пользоваться комментариями.

Дополнение: Функциональщик ботает Java — работа со сторонними библиотеками и хождение в РСУБД через JDBC

Метки: , , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.