Среди других языков программирования Java выделяется целым набором положительных качеств. Это и кроссплатформенность и широчайшие возможности, как в области написания десктопных приложений, так и в веб, мощный набор встроенных средств проектирования, различные среды IDE, фреймворки и многое другое.
Несмотря на то, что разработка Java начата ещё в 1991 году и предназначался язык тогда для программирования, микроконтроллеров, он вырос в универсальную платформу, которая занимает 21, 5% рынка разработки в мире. В прошлом году Java удостоился титула «язык года» по версии Tiobe Software.
Можно не сомневаться в том, что Java ещё много лет будет оставаться одним из наиболее востребованных средств разработки, хотя бы даже потому, что созданным с его помощью продуктам будет требоваться поддержка и обновление. Поэтому мы и выбрали «язык кофе» темой очередного материала, посвященного программированию.
Немного истории
Как я и писал выше, Java создавался, как средство программирования несложных бытовых устройств, таких, как контроллеры переключения кабельных каналов. Исходя из их скромных возможностей, родились и первые требования к языку. Он должен был быть лаконичным, а программы на его основе — компактными, и платформонезависимыми, поскольку архитектура процессоров бытовых устройств была различной. Поэтому Java получил JVM — виртуальную машину, о ней мы поговорим позже.
Руководили разработкой Джеймс Гослинг (James Gosling), чьи книги по сей день являются лучшими «путеводителями» по Java и Патрик Нортон (Patrick Naughton) из компании Sun. За основу они взяли широко используемый в то время язык программирования С++, так как специалисты Sun много работали с ОС UNIX и неплохо разбирались в С++. Поначалу разработанный энтузиастами язык назывался Green и особого успеха не имел. В 1996 году он получил свое нынешнее название. Одни говорят, что в честь марки кофе, другие считают, что это был намек на то, что язык предназначен для программирования бытовых устройств, вроде кофе-машины. В дальнейшем развитие языка пошло по пути совершенствования и усложнения его инструментария и возможностей.
Почему Java так популярен?
Как бы ни был хорош язык программирования, какими бы совершенными средствами разработки, изящным синтаксисом, набором библиотек он не обладал, в нем всегда будут недостатки. Есть они и у Java.
Виртуальная машина работает достаточно медленно и требует большого объема оперативной памяти. Её надо скачивать и инсталлировать в систему, что является дополнительной задачей для пользователя продуктов Java. «Многословность» синтаксиса, огромное количество стандартных библиотек, фреймворков, технологий вызывает определенные проблемы с освоением языка. Можно даже сказать, что полное и глубокое знание всех «ветвей» и средств разработки Java просто невозможно. Уж слишком их много.
Впрочем, эти же недостатки являются и его достоинствами. Виртуальная машина делает Java кроссплатформенным. Сейчас компиляторы под неё уже созданы для Haskell, Scala, Clojure и разработчики вполне могут писать софт под JVM на этих языках. Java стабилен и безопасен, имеет низкий порог вхождения на начальный уровень (правда, лишь на начальный), огромный выбор стандартных средств проектирования и сборки. JVM стабильно работает на различных платформах, в ней довольно удачно реализована многопоточность. Java имеет встроенную поддержку работы в сетях и открытый исходный код. Кроме того, за годы его широкого использования, как сам язык, так и его инструментарий претерпели множество позитивных изменений и были многократно проверены широкой практикой.
Во многом успех языка программирования или какого-то отдельного программного средства определяется качеством и уровнем его поддержки, динамичностью развития и удобством. В нашем случае, язык Java, быть может, поначалу и не был наиболее оптимальным средством разработки но в итоге оказался более удобным, развивался быстрее других и привлек на свою сторону множество компаний и разработчиков.
Из чего состоит Java и как это работает?
Как я уже упоминал, Java — это серьезная и мощная программная платформа, которая обладает множеством возможностей. Но основные, базовые её элементы — это программы на java, компилятор javac, который переводит программы в байт-код, а также JVM — java-машина, превращающая байт-код в инструкции для конкретной операционной системы. Байт-код одинаков для всех версий JVM. Разработчику не нужно заботиться о том, как будет работать программа в конкретной ОС. Это сделает за него JVM, которая разрабатывается компанией Oracle и предлагается для скачивания под нужную операционную систему.
Изначально программа представляет собой файл с расширением .java. После преобразования в байт-код, это уже файл с другим расширением — .class. Приведу пример самой простой программы на Java и того, как она будет выглядеть в байт-коде.
Стоит отметить, что язык Java — объектно-ориентирован, поэтому любая программа в нем является классом.
Программа:
public class Hello {
public static void main(String[] args) throws Exception {
System.out.println("HelloWorld");
}
}
Байт-код:
const #3 = String #20;
const #20 = Asciz HelloWorld;
3: ldc #3;
5: invokevirtual #4; java/io/PrintStream.println:(Ljava/lang/String;)V
С программой все ясно — в ней имеется, как это и положено, класс Hello, главный метод main (в любом С-подобном языке, запускающим является именно этот метод). Внутри он содержит String[]args — массив строк с произвольным названием. Если передать в этот метод какие-либо аргументы командной строки, то можно заставить его выполнить полезную работу, например, просмотреть содержимое директории. Но обычно он используется просто как обязательная часть синтаксиса. Далее идет метод, который выводит строку HelloWorld и закрывающие скобки, указывающие компилятору, что метод, а затем и класс отработали и программу можно завершить.
С байт-кодом дело обстоит немного сложнее. Это, своего рода, ассмемблер JVM (с ассемблером мы познакомились в предыдущем номере газеты).
Const — это константы, Idc — инструкция их получения из файла. Invokevirtual вызывает метод, печатающий строку и передает ему аргумент Ljava/lang/String
В ассемблере JVM около 200 команд, различными наборами которых описываются все возможные операции в программе.
Немного изучив байт-код, можно наблюдать результаты работы вашей программы и выявлять для себя определенные закономерности. Байт-код можно и модифицировать, использовать для написания кода, для этого есть специальные библиотеки — ASM, BCEL и другие. Но описание их работы выходит за рамки этой статьи.
Структура файлов и программ
Принятая в Java структура, в принципе, обычна для языков программирования. Разрабатываемый код раскладывается по пакетам, которые могут быть вложены друг в друга. В пакетах находятся классы, они содержат методы, обеспечивающие выполнение необходимых действий или операций. В проводнике пакеты видны, как папки с вложенными папками и файлами кода. Их можно создавать вручную но гораздо проще делать это в среде разработки IDE, которая сама предлагает меню для создания проекта, пакетов и классов.
Для того, чтобы аккуратно распределить код по пакетам, не допуская путаницы, существуют модификаторы доступа, которые, в зависимости от необходимости, полностью или частично закрывают доступ к определенным классам либо делают их открытыми так, что они доступны в других пакетах. В Java, как я уже говорил, есть обширный набор инструментов разработчика — это стандартные классы, которые легко встраиваются в любой класс вашей программы с помощью оператора import. Среди них, в том числе и пакеты, предназначенные для создания элементов графического интерфейса — AWT и Swing.
Вся совокупность программного инструментария разработчика обеспечивает реализацию базовых принципов объектно-ориентированного программирования – инкапсуляции, полиморфизма и наследования. Есть в Java и жесткие ограничения. В том числе, в части наследования. Каждый класс (читай, элемент программы), может унаследовать свойства только одного класса. Таким образом удается избежать малопрогнозируемых ошибок и путаницы, возникающих при множественном наследовании, разрешенном, например, в С++.
Впрочем, разработчики языка сразу же предложили возможность обхода этого ограничения. Некий вариант множественного наследования можно реализовать при помощи интерфейсов. Инкапсуляцию можно обойти с помощью специальных методов — геттеров и сеттеров. Конечно, так работать сложнее но подобный подход помогает защититься от ошибок.
Данные
Java — строго типизированный язык. Это означает, что в любой ячейке-переменной может храниться только тот тип данных, который был объявлен для неё заранее. Более того, операции можно производить только над одними и теми же типами данных. Если требуется каким-то образом объединить разнородные данные или произвести с ними какие-либо действия, необходимо выполнить приведение типов. Регистр букв в Java также имеет значение и это необходимо помнить при именовании классов и переменных.
В Java данные делятся на примитивные и ссылочные. Примитивных всего 8.
Максимальный размер чисел, допустимый для различных типов данных в Java никак не зависит от аппаратной платформы, конкретная реализация возложена на Java-машину.
Ссылочные типы включают оболочки для примитивных типов, которые выполняют различные преобразования данных, проверки на соответствие, сравнение и т.д —
. Они имеют те же названия, но пишутся с большой буквы. Кроме того, ссылочные типы включают интерфейсы, классы, массивы, строковый тип String. В Java можно создавать и пользовательские типы данных и эта возможность используется довольно часто.
Отдельно стоит поговорить о массивах. Это ссылочный тип, который содержит однородный набор данных какого-либо одного типа. Массивы объявляются так:
int [] m = new int [9];
Мы объявили массив целого типа int из 9 значений. Его можно заполнить позже или объявить явно, с готовыми значениями:
int [] m = {0,1,2,3,4,5,6,7,8};
Основные операторы, действия, конструкции
Язык Java включает стандартный набор операторов — арифметические, целочисленные битовые, операторы сдвига, отношения, булевы (логические), инкремент и декремент, тернарный оператор. Это, в общем-то, стандартный набор для каждого языка и тот, кто изучал С или С++, Паскаль, С#, прекрасно разберется с операторами Java, приоритетом их выполнения. Поэтому, перечислять все операторы вряд-ли имеет смысл.
То же самое можно сказать и о логических конструкциях. Здесь все достаточно просто. Приведу примитивный пример:
if (i>3) {
j++;
}
else {
j--;
}
Тут все ясно, как день, если переменная i — больше трех, то переменную j мы увеличиваем на 1, иначе — уменьшаем на 1.
Можно усложнить задачу:
int j = 7;
int l = 3;
if (j > 6 && j <8 && l >2 && l <4) {
int v = 0;
v=j+l;
System.out.println (“j+l =” +v);
Здесь мы задали определенные критерии для чисел. При их соответствии выводится сумма этих чисел.
Есть в Java и циклы — конструкции, выполняющие повторяющийся определенное количество раз набор операций. Это может быть, например, перебор данных в массиве:
int [] m = {1, 2, 3, 4, 5, 6};
for (int i = 0; i < m.length; i++) {
System.out.println (m[i]);
}
Здесь мы выводим поочередно каждый элемент заранее созданного массива
Кроме for в Java есть циклы while и do-while. Они используется, когда неизвестно количество шагов цикла. То есть, цикл повторяется до тех пор, пока истинно начальное условие. Второй вариант (do-while), отрабатывает один раз даже в том случае, когда условие изначально ложное.
В Java имеются также операторы switch (выбор значения, соответствующего условию), return (возврат значения или передача управления вызывающему коду), break (завершение блока), continue (выход из текущей итерации цикла).
C помощью описанного инструментария уже можно создавать достаточно серьезные программы. Но это лишь основы работы с языком — дальше все куда сложнее.
Коллекции, «дженерики», исключения
Начнем, пожалуй, с последнего пункта. Исключения — слово с очевидным значением. Исключение выбрасывается, если произошла ошибка в работе программы, например, если нет соединения с сервером, или не найден файл. В таких случаях выводится стандартное сообщение, не всегда подходящее к случаю. Можно вызвать в этом месте заранее подготовленное сообщение, или же подключить к работе другой блок кода.
Синтаксис «поимки» исключения несложен:
try {
В эти скобки заключается весь код, который может привести к ошибке
}
catch (В круглых скобках — класс ошибки) {
В фигурных — действие, которое должно быть выполнено, если возникла ошибка
}
Все классы возможных ошибок наследуются от java.lang.Throwable и содержат два подкласса — Error и Exception. Первый обычно не обрабатывается, так как «ловит» ошибки, не связанные с программой, которые возникают во время её выполнения. Ошибки типа Exception можно обрабатывать.
Теперь поговорим и коллекциях. Их вполне можно было бы назвать «расширением» стандартных массивов. Массивы могут хранить однотипный набор данных, а коллекции могут содержать самые различные данные, объекты и т.д. (кроме примитивных типов). Кроме того, коллекции могут выполнять различные операции, обеспечивают вставку, удаление или быстрый поиск по ним. Например, интерфейс Map позволяет создавать коллекции, которые содержат пары, состоящие из ключа и значения. Каждому значению в такой коллекции соответствует только один ключ.
Интерфейс Collection содержит интерфейсы List, Set, Queue. List позволяет создавать неупорядоченные коллекции с «дублями», Set — неупорядоченные коллекции, в которых элементы не повторяются, а Queue дает возможность разместить все элементы в нужном пользователю порядке.
Коллекция ArrayList позволяет добавлять в себя новые элементы, при этом она автоматически увеличивается (с массивом так не получится — придется каждый раз, когда он заполняется, создавать новый массив и переносить туда все данные). Коллекция LinkedList представляет собой список из узлов, каждый из которых имеет ссылки на соседние. LinkedList обеспечивает наиболее быстрый доступ (за линейное время) к каждому из своих элементов. Таким образом, Java содержит инструменты для создания коллекций под любые пользовательские задачи.
В заключение, скажу несколько слов о «Дженериках» (Generics). Эти конструкции очень похожи на шаблоны в С++. Они позволяют использовать одни и те же алгоритмы для различных ссылочных типов данных.
Инструменты сборки программ, IDE среды
Главный враг и проблема разработчиков программного обеспечения — это время. Его всегда не хватает. Именно поэтому для удобства программистов создаются средства, упрощающие работу. Есть они и в Java. Это Maven и Ant. Эти инструменты обеспечивают компиляцию, создание дистрибутива программы, генерируют документацию.
Если вам необходимо создать библиотеку, причем, часть её классов вы захотите использовать где-то в другом проекте, сборщик сгенерирует (соберет) для вас соответствующий компактный .jar файл. По сути дела, сборщик — это фреймворк, содержащий необходимые средства для объединения частей программы в единый проект. Обычно, сборщики проектов интегрируются в среды разработки IDE, делая работу программиста удобнее.
Для разработки программ на языке Java созданы три широко известные IDE среды. Это Eclipse, Intellij Idea и NetBeanse. Справедливости ради стоит сказать, что эти среды позволяют работать и с другими языками программирования. Примечательно, что IDE Eclipse создавалась компанией IBM и разработка её обошлась в 40 миллионов долларов. Но позже код проекта стал открытым и Eclipse превратилась в постоянно совершенствующуюся платформу для разработчиков, поддерживаемую независимым сообществом. Она позволяет создавать программы на 8 языках, включая С++ и даже 1С.
Что касается Intellij Idea, то это — коммерческий проект компании JetBrains, который поддерживает 19 языков программирования и ещё 10 — через модули сторонних разработчиков.
Ещё одна IDE — NetBeans поддерживается компанией Oracle, которая владеет платформой Java . NetBeanse, тем не менее, разрабатывается под лицензией GPL.
Изучение Java — бесконечный процесс
Язык Java постоянно совершенствуется. Сейчас тестируется уже 9 версия ядра Standard Edition, в котором ещё более глубоко оптимизировано взаимодействие с поддерживаемыми ОС. Java получил «второе дыхание благодаря тому, что он широко применяется и в разработке мобильных приложений для ОС Android. Корпорация Google, чтобы упростить жизнь программистам мобильных устройств специально создала набор инструментария под названием Software Development Kit и среду IDE Android Studio (на основе NetBeanse). Впрочем, плагины для работы с Android теперь уже появились и для всех IDE.
Эдуард ТРОШИН
Компьютерная газета