С момента появления языка программирования Java прошло уже почти двадцать лет. За это время Java пророчили смерть и забвение, программисты на сях смеялись над ее тормознутостью и жадностью к ресурсам. Но были и те, кто поверил в Java, они разрабатывали всевозможные библиотеки, развивали сообщество, упорно доказывали, что для Java нет пределов: realtime, embedded, ИИ — возможно все. Мы решили не оставаться в стороне и сделать в этой рубрике небольшой цикл статей по Java. Поехали!
Ваш чайник выбирает Java
По заверениям самой Oracle, на сегодняшний день виртуальная машина Java установлена на более чем трех миллиардах устройств. И это не только компьютеры и смартфоны, но и фотоаппараты, телевизоры, Blue-ray-проигрыватели, принтеры, сим-карты, банковские автоматы и даже автомобили. Этот список будет неуклонно расти, а вместе с ним и предложения от работодателей для Java-программистов. Даже сейчас количество вакансий для программистов Java превышает остальные. И компании готовы платить все больше и больше, переманивая сотрудников и организуя более выгодные условия труда.
А чем же она хороша?
Программистов Java привлекает минимализмом синтаксиса. Никаких лишних модификаторов и служебных слов. Даже отсутствие множественного наследования, которое поначалу несколько смущало программистов на С++, в итоге оказывается разумным и оправданным. Простая логика, автоматическая работа с памятью, подробная документация, форумы с ответами на всевозможные вопросы, открытый код — все это позволяет быстро вникнуть в процесс разработки и значительно уменьшает количество потенциальных ошибок. Даже индийские крестьяне осваивают Java за пару месяцев, по крайней мере так говорится в их дипломах :). Кроме того, Java — интерпретируемый язык. Исходный код компилятор переводит в так называемый байт-код, который несложно преобразовать обратно, что делает Java особенно привлекательным для реверс-инжиниринга.
Ну-с, приступим
Java — объектно-ориентированный язык, это значит, что все переменные, методы, константы объявляются в рамках какого-либо класса. Кроме классов, есть еще интерфейсы — особая абстрактная конструкция, которая позволяет описать поведение объекта, не указывая конкретную реализацию. И если множественного наследования классов в Java нет, то интерфейсов класс может реализовывать любое количество, что позволяет одному объекту обладать множеством функций, но предоставлять только часть из них.
Типы данных можно разделить на две группы: простые (int, long, char и так далее) и объектные: классы, интерфейсы, массивы. Простые типы всегда и везде фиксированной размерности. К примеру, на любой архитектуре и любом устройстве int занимает четыре байта памяти. Это довольно удобно при вычислениях. Массив данных содержит специальный атрибут length, который хранит размер массива, за что отдельное спасибо разработчикам. Данные разных типов по-разному передаются в методы. Простые типы всегда передаются по значению. Объектные — всегда по ссылке для экономии памяти. Это значит, что если мы передаемint a = 10
и изменяем его значение на 5 в вызываемом методе, то в исходном методе a
по-прежнему будет равно 10. Но если мы изменим свойство объекта, то оно изменится и в исходном методе.
Помни о памяти
Хотя программист Java и освобожден от необходимости выделять и освобождать память, незнание некоторых особенностей работы виртуальной машины и сборщика мусора может запросто превратить твою программу в ненасытного монстра, пожирающего процессорное время и всю доступную память.
Создавая новый массив, всегда помни, что гораздо проще создать много маленьких кусочков памяти, чем один огромный. Иначе рискуешь нарваться на ошибку Out of memory, что примерно означает, что память у тебя была, да вся вышла.
Многие программисты, когда переходят на Java и узнают об автоматической очистке памяти, начинают создавать объекты в огромных количествах, надеясь, что все это уберется само. Между тем сборщик мусора подобен машине, которая может убрать мусор, только выброшенный в урну возле дома. Если какие-то данные тебе больше не нужны, не стоит хранить их на всякий случай, как ворох старых открыток, — присвой указателю на данные null, помоги уборщику прибраться :). Также хорошим тоном будет сделать clear для списка, если он тебе уже не понадобится. Помни, объект будет храниться в памяти, пока в коде на него есть ссылки. Даже если твоя программа работает на 16 гигах памяти и вылететь с Out of memory ей не грозит, от переизбытка используемой памяти она будет становиться все более неповоротливой и тормознутой. 99% жалоб пользователей на медленную работу Java-программ связано с неэффективно написанным исходным кодом. Если тебе требуется постоянно создавать объекты, которые используются быстро и больше не нужны, например много мелких сообщений, задумайся о создании пула, в котором будет храниться некоторое количество экземпляров для многократного использования. Помни, создание и удаление объекта — операция дорогостоящая.
За дело, господа
Один пример лучше тысячи слов. Пролистать мануал и посмотреть на стандартные хеллоуворды ты можешь и без нас, поэтому будем считать, что ты это уже сделал и готов к реализации более интересного примера.
Мы с тобой займемся серверным применением Java и напишем небольшую программу для «слежки» за пользователями социальных сетей. Для этого даже не придется трудоустраиваться в АНБ — пользователи сами про себя все выкладывают, а нам останется только эту информацию получить, систематизировать и красивенько отобразить. Возьмем один из популярных социальных сервисов, к примеру foursquare, и нарисуем на карте перемещения наших друзей.
Для начала посмотрим, что мы можем вытянуть из foursquare. Пробежавшись по страничкам для разработчиков, мы обращаем свое внимание на два метода:
- https://developer.foursquare.com/docs/users/checkins — места, которые посетил пользователь. К сожалению, пока поддерживается только для зарегистрированного в программе пользователя, и ходят слухи, что из-за ограничений в реализации так оно и останется;
- https://developer.foursquare.com/docs/checkins/recent — места, которые посетили друзья зарегистрированного пользователя. Если немного поиграть с этой функцией, то выясняется печальный факт: для каждого друга возвращается ровно одно место — последнее, где он отметился.
Чтобы пользоваться foursquare API, необходимо зарегистрировать наше будущее приложение, идем по этому адресу: https://ru.foursquare.com/developers/register и заполняем поля (да, в самом foursquare тоже придется зарегистрироваться, но с этим ты прекрасно справишься и без меня).
Из важных полей тут можно отметить только «Название приложения», «Download / welcome page url» (впиши сюда произвольный веб-адрес) и «Redirect URI(s)» — это адрес, на который нас отправит сервер после регистрации. Сюда мы позже впишем нужное значение, а пока можешь просто вписать любой веб-адрес. Жмем «Сохранить», и наше приложение tracker успешно зарегистрировано.
Поднимаемся в облака
Капитан Очевидность передает, что любому серверному приложению для работы требуется сервер. Поднимать сервер самостоятельно геморройно, поэтому воспользуемся популярными сейчас облачными решениями. Спонсором облака выступит корпорация Google, потому что их Google App Engine бесплатен, довольно легок в настройке и использовании. Для начала идем сюда и скачиваем Google App Engine SDK for Java.
Теперь можно приступать к созданию проекта. Для разработки на Java я пользуюсь IntelliJ IDEA, но ты можешь воспользоваться бесплатной и не менее известной средой Eclipse.
Выберем новый проект Java. Назовем его nsa_tracker.
На следующей вкладке отметим слева Web Application и Google App Engine и укажем путь к скачанной ранее и распакованной App Engine SDK.
А теперь откинься в кресле и позволь IDE сделать свое дело. Если ты выбрал IDEA и все сделал правильно, то в результате увидишь готовый проект, который при запуске открывает окно браузера с пустым содержимым. Можно приступать к кодингу.
Начинаем искать
Итак, у нас есть папка с проектом, в которой лежит папка src. Туда мы будем складывать исходники. Исходники в Java группируются по пакетам. Пакет — это папка на диске. Пакеты нужны, чтобы не сваливать все исходники в кучу, а разделять их, руководствуясь принципами логики. Например, код, связанный с пользовательским интерфейсом, логично поместить в пакет ui, сетевые взаимодействия — в пакет network. Это значительно облегчает развитие и поддержку проекта впоследствии. Исторически сложилась практика начинать структуру пакетов с названия компании, за которым следует название программы. Это поможет легко идентифицировать наши исходники среди кучи таких же в дальнейшем. Для нашей программы мы создадим пакет org.nsa.tracker. В нем мы и будем создавать классы.
Для обработки запросов пользователей на сервере используются сервлеты. Сервлет — это класс, который наследует, как правило, HttpServlet и работает по принципу запрос — ответ. Все, что нужно, — это переопределить метод doGet. По запросу от пользователя нам нужно авторизоваться в foursquare, загрузить список чекинов друзей и перенаправить запрос на страницу с картой.
Для работы с foursquare API воспользуемся бесплатной библиотекой foursquare-api-java, которую можно взять отсюда. Библиотека Java представляет собой ZIP-архив с расширением jar, содержащий откомпилированные Java-классы, которые реализуют определенную функциональность. Для авторизации нам понадобятся ClientId и ClientSecret, полученные на этапе регистрации приложения в foursquare. Так как эти параметры не меняются в процессе выполнения программы, объявим их как константы.
private static final String CLIENT_ID = "FAKE_CLIENT_ID";
private static final String CLIENT_SECRET = "FAKE_CLIENT_SECRET";
Final означает, что данной переменной присвоено окончательное значение, которое не дано изменить. Static делает переменную доступной для всех экземпляров данного класса. Воспользовавшись примером авторизации из библиотеки foursquare-api-java, получим примерно следующий код:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
FoursquareApi foursquareApi = new FoursquareApi(CLIENT_ID, CLIENT_SECRET, CALLBACK_URL);
String code = req.getParameter("code");
if (code == null) {
// Отправляемся на страницу регистрации
resp.sendRedirect(foursquareApi.getAuthenticationUrl());
} else {
try {
foursquareApi.authenticateCode(code);
// Регистрация успешна, загрузим-ка данных
Result<Checkin[]> result = foursquareApi.checkinsRecent("0.0,0.0", 100, 0l);
} catch (FoursquareApiException e) {
e.printStackTrace();
}
}
}
Обрати внимание на «throws ServletException, IOException» в объявлении метода. Эта строка означает, что метод потенциально может бросить одно из этих исключений. Исключение в Java — это объект, который сигнализирует о возникновении исключительной ситуации. Они бывают проверяемые и непроверяемые. Проверяемые исключения нужно обрабатывать, окружив часть кода блоком try-catch, или же передавать выше. Непроверяемые исключения, как правило, не обрабатываются, потому что возникают в случаях, когда программа не в состоянии восстановить свое состояние. В данном методе мы обрабатываем только исключение FoursquareApiException.
Когда веб-сервер получает запрос для приложения, он использует дескриптор развертывания, чтобы сопоставить URL запроса с кодом, который должен обработать запрос. Дескриптор развертывания представляет собой XML-файл c названием web.xml. Добавим описание сервлета слежения.
<servlet>
<servlet-name>track</servlet-name>
<servlet-class>org.nsa.tracker.TrackerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>track</servlet-name>
<url-pattern>/track</url-pattern>
</servlet-mapping>
Теперь запросы по адресу /track будет обрабатывать наш сервлет с именем TrackerServlet. Можно присвоить параметру Callback Url верное значение http://localhost:8080/track.
Для вывода результатов можно воспользоваться Static Maps API, любезно предоставленным все той же корпорацией Google (https://developers.google.com/maps/documentation/staticmaps/). Наш сервлет будет генерировать простую HTML-страницу и возвращать ее в ответ на запрос пользователя.
StringBuilder sb = new StringBuilder("<html><head><title>NSA Tracker</title></head><body>");
sb.append("<img src='").append("http://maps.googleapis.com/maps/api/staticmap?zoom=14&size=600x600&maptype=roadmap&sensor=false");
int index = 1;
for (Checkin checkin : result.getResult()) {
sb.append("&markers=label:").append(index++).append("%7C");
Location location = checkin.getLocation();
if (location == null) {
location = checkin.getVenue().getLocation();
}
sb.append(location.getLat()).append(',').append(location.getLng());
}
sb.append("' align='left'/>");
sb.append("<ul>");
index = 1;
for (Checkin checkin : result.getResult()) {
sb.append("<il>").append(index++).append(" - ").append(checkin.getUser().getFirstName())
.append(' ').append(checkin.getUser().getLastName()).append("</li>");
}
sb.append("</ul>");
sb.append("</body></html>");
Для генерации страницы используется класс StringBuilder, это обусловлено тем, что строки в Java являются неизменяемыми объектами. При конкатенации строк с помощью оператора +. создается новая строка в памяти. StringBuilder позволяет экономить память, так как использует массив char для хранения соединяемых строк. Передаем ответ пользователю:
byte[] resultBytes = sb.toString().getBytes("utf-8");
resp.setContentLength(resultBytes.length);
resp.getOutputStream().write(resultBytes);
…И все готово. Запускаем и видим что-то похожее на картинку с говорящей подписью «Результат работы программы».
Что дальше?
Приложение можно улучшить, например разделить сбор данных и отображение. Вынести сбор данных в отдельный сервис, который будет работать постоянно и запоминать все перемещения пользователей в базе данных. Тогда отображать можно будет уже не отдельные точки, а связный маршрут. Покопавшись немного в foursquare API, можно извлечь даже больше информации об активности пользователя.
Но надеюсь, мне удалось главное: убедить тебя в том, что Java — это просто и круто. До встречи через месяц!
Что почитать начинающему: онлайн
- Вопросы установки Java на русском: www.java.com/ru
- Официальная документация от Oracle: docs.oracle.com/javase/tutorial
- Лучший форум с кучей вопросов и ответов по Java в том числе: stackoverflow.com
- Хороший форум на русском: javatalks.ru
- Множество примеров кода по любой теме: www.java2s.com
Книги для Java-программера
Начать изучать язык мы советуем с книги «Java. Руководство для начинающих» (Java: A Beginner’s Guide) Герберта Шилдта. Следующий уровень — «Java. Полное руководство» от него же, а больше о сервлетах ты можешь узнать из книги «Java сервлеты и JSP : сборник рецептов» (Java Servlet and JSP Cookbook) Брюса У. Перри.