Царский путь к Java

Нет царских путей в геометрию,
о великий Птолемей!
Евклид

Технологии Java стремительно набирают популярность. По Интернету ходят легенды о Java-программистах, зарабатывающих более 150 долларов в час... А так ли уж сложно самому начать использовать Java для решения практических задач? Ответ на этот вопрос может дать только эксперимент...

Кто виноват?

Перед многими пользователями Интернета, вероятно, хоть раз да вставала задача отслеживания содержимого изменяющихся страниц. По самым разным причинам: посмотреть новые записи в гостевой книге, скачать пачку свежих анекдотов или отыскать полное собрание сочинений И. Христа и записать все это на диск... да мало ли что может понадобиться просвещенному интернетчику, наделенному, помимо всего прочего, творческим подходом к окружающей действительности?

Конечно, для всего этого существуют самые разнообразные программы, работающие с узкоспециализированными задачами (впрочем, такое состояние имеет место не только в индустрии программного обеспечения. Ни одна американская семья не может даже представить свое существование без специальной машинки для чистки овощей или, скажем, набора для барбекю - но не будем о грустном). Все эти специализированные средства хороши для решения стандартных задач, на которые они и рассчитаны. Скажем, Teleport Pro хорош, если нам надо выкачать сайт целиком, а WatzNew! - для отслеживания обновлений всяческих лент новостей, но если в голову стукнет действительно интересная мысль... В таких случаях более или менее опытные пользователи доступными им способами подогревают свой творческий энтузиазм и приступают (о ужас!) к программированию.

Языков программирования, пригодных для работы с Интернетом, существует великое множество. Но в последнее время с интернет-технологиями, как правило, ассоциируются два из них: Perl и Java. О языке Perl и о том, что он не так уж страшен (если, конечно, не читать чужих программ), мы уже писали в "Мире Internet" (октябрь 2000 года). Настало время поближе познакомиться с Java.

// файл Sample.java
package sample;
import java.io.*;
import java.net.*;
public class Sample {
public static void main(String[] args) {
try {
URL url = new URL("http://www.yandex.ru/last20.html");
BufferedReader in =
new BufferedReader(
new InputStreamReader(url.openStream()));
StringWriter sw = new StringWriter();
int i;
while (true) {
while ((i = in.read()) != -1) {sw.write(i);}
MyParser p = new MyParser(sw.toString());
p.printWords();
}
}
catch (Exception e) { e.printStackTrace(); }
}
}

Что делать?

Задача, которую поставила перед автором статьи его напряженная программистская мысль, достаточно проста и по-своему изящна. Известный поисковик "Яндекс", которому благодаря активной торговле майками и кружками с фирменной символикой приписывают слоган "Продастся всё!", транслирует определенную часть запросов к своему поисковому движку в раздел "Прямой эфир". Требуется получить большой красивый файл, в котором записаны все запросы к "Яндексу" в "Прямом эфире" за последние сутки, собранные с определенной периодичностью. Причем именно сами запросы, а не странички "Прямого эфира", радующие глаз совершенно не нужными для данного замысла дизайнерскими изысками и рекламными фейерверками. Что делать впоследствии с этим файлом - не суть важно. Например, пройтись каким-нибудь статистическим анализатором и выяснить, что в 85,97% случаев запросы "порнография" и "технология ActiveX" делаются в одно и то же время суток... Сейчас важно собрать исходные данные.

Две самые необходимые вещи, без которых программирование на Java является невозможным, - это Java Software Developer Kit (SDK) и документация к нему (вообще, написание на Java программы чуть-чуть посложнее "Hello, World!" без документации крайне затруднительно). Стандартная библиотека содержит несколько тысяч классов и десятки тысяч методов, и запомнить даже самые часто употребляемые из них можно лишь после пары лет работы программистом. Но, к чести разработчиков, документация Java - одна из самых удобных в использовании, и работать с ней - одно удовольствие.

Дистрибутив Sun Java SDK версии 1.3.1 занимает около 30 Мбайт, а документация к нему - еще 40. Найти его можно на официальном сайте java.sun.com (есть версии под Windows, Solaris и Linux). Тем, кто не успел еще обзавестись толстым выделенным каналом в Интернет, можно порекомендовать поискать дистрибутив SDK среди повсеместно продающихся пиратских компакт-дисков. Покупать его можно безо всяких угрызений совести, так как дистрибутив Java SDK распространяется бесплатно.

Установив SDK и документацию, почитайте README, настройте переменные окружения PATH и CLASSPATH. В переменную PATH нужно добавить путь к каталогу с исполняемыми файлами Java, например, C:\jdk1.3.1\bin, а в CLASSPATH - каталог, в котором будут находиться ваши программы и файлы классов (например, C:\work\java). Создайте в последнем каталоге еще один подкаталог - sample. В нем мы и будем работать.

// файл MyParser.java
package sample;
public class MyParser {
private String theSource;
public MyParser (String s) {
theSource = s;
}
public void printWords() {
String begin = "target=_blank>";
String end = "</a></td></tr>";
int startIndex = 0;
while (true) {
startIndex = theSource.indexOf(begin, startIndex);
int endIndex = theSource.indexOf(end, startIndex);
if (startIndex == -1) break;
System.out.println(theSource.substring(startIndex
+ begin.length(), endIndex));
startIndex = endIndex + 1;
}
}
}

К делу!

Рассмотрим для начала самую простую программу на Java - классический пример "Hello, world!". Если кто-то до сих пор не знает, задача этой программы - вывести на экран фразу "Hello, world!". И всё.

public class Hello {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
} // файл Hello.java

Основная структурная единица программы на Java - класс. Класс может представлять какую-то реальную или абстрактную категорию объектов (например, класс Apple имеет дело с яблоками, точнее - с их представлениями в программе). В данном случае конструкция public class Hello делает две вещи. Во-первых, создается новый класс с названием "Hello" (который и будет отвечать за вывод на экран фразы), а во-вторых, этому классу присваивается модификатор public, который делает его открытым и позволяет обращаться к нему из других классов, - таким образом, при начале выполнения программы Java-машина сможет передать ему управление.

Тем, кто уже знаком с C++, может показаться странной следующая конструкция - public static void main(String[] args). Дело в том, что в Java выполнение программы всегда начинается с метода main() открытого класса, принимающего массив строковых аргументов, представляющих командную строку (String[] args), и возвращающего пустое значение (void). Третий модификатор (static) в данном случае тоже обязателен. Он показывает, что метод main() относится не к объекту класса, а непосредственно к самому классу. Если бы этого модификатора не было, вызов метода main() был бы возможен только при условии, что создан конкретный объект - экземпляр класса Hello. Так как в данном случае создание объекта не требуется, метод main() объявляется статическим и может быть вызван непосредственно из самого класса.

Строка System.out.println ("Hello, world!"), как видно, и выводит на экран данную фразу. Объект "System" содержит основные системные объекты, включая стандартные потоки ввода и вывода in и out соответственно. В поток out методом println() как раз и выводится строка "Hello, world!".

Решение же поставленной в начале статьи задачи выглядит удивительно компактным. Оно уложилось всего в два небольших класса!

Первый класс, описанный в файле Sample.java, с которого и начинается выполнение программы, как положено, начинается с метода main(). Но сначала объявляется, что этот класс принадлежит к пакету sample (помните каталог sample, который мы создали? Имя этого каталога должно совпадать с именем пакета, а имя файла - с именем класса). Кроме того, прежде чем начинать работу, следует загрузить классы сетевой библиотеки и библиотеки ввода/вывода Java (это действие выполняется оператором import).

Блок try/catch, который мы видим в начале, служит для перехвата исключительных ситуаций. Если какая-либо инструкция в пределах этого блока вызовет ошибку и сгенерирует исключительную ситуацию (например, если ваша любимая кошка запнется о модемный шнур и тот выскочит из гнезда, связь с "Яндексом" будет потеряна, метод url.openStream() не сможет получить данные из Интернета, программа на этом месте прервет работу и, обратившись к методу printStackTrace() в блоке catch, распечатает причину ошибки).

Далее создается объект url класса URL, который инициализируется строкой, содержащей адрес страницы "Прямой эфир" "Яндекса". Метод url.openStream() возвращает объект класса InputStream, представляющий собой поток данных с содержимым этой страницы. Но "в чистом виде" этот поток пока еще не слишком полезен. Во-первых, из потока байтов его следует преобразовать в поток символов (в отличие от многих других языков программирования, в Java байт и символ - далеко не одно и то же; в японском языке, к примеру, один символ занимает два байта, да и у нас символы могут существовать в разных кодировках). Во-вторых, непосредственное чтение символов из потока - весьма неэффективная процедура, и умные программисты добавляют к этому потоку буфер, который увеличивает производительность на целый порядок. Чтобы добавить к потоку данных необходимые свойства, на базе объекта класса InputStream последовательно строятся объекты InputStreamReader и BufferedReader. Надо сказать, что подобное "навешивание" на простой класс дополнительных свойств, расширяющих его возможности, - один из традиционных приемов работы с библиотекой ввода/вывода Java.

Далее мы создаем объект sw класса StringWriter. Он предназначен для хранения данных в строковом буфере, куда в цикле символ за символом мы записываем всю информацию, которую удалось прочитать из недавно созданного объекта in класса BufferedReader. Теперь нам остаются сущие пустяки: извлечь из объекта sw методом toString() строку, содержащую весь HTML-код страницы, создать объект класса MyParser (это второй класс программы, используемый для извлечения запросов из HTML-страницы) и "скормить" ему эту строку.

Перейдем теперь к классу MyParser, который описан в файле MyParser.java. Объект-экземпляр этого класса рождается на свет с трудной задачей: разобрать по кусочкам полученный HTML-код и вытащить из него вожделенные запросы. При создании объекта строка, содержащая этот HTML-код, передаваемая в качестве параметра конструктору объекта MyParser, первым делом присваивается строковой переменной theSource, и уже с ней ведется дальнейшая работа. Поскольку все запросы в странице "Прямого эфира" расположены между фрагментами HTML-кода "target=_blank<" и "</a></td></tr>", дальнейшее тянет на задачку по информатике для девятого класса средней школы. Решается она путем последовательного определения позиций (индексов), начиная с которых на странице встречаются эти фрагменты. Обнаруженный между ними текст выводится на экран.

Скомпилировав эту программу командами javac MyParser.java и javac Sample.java (эти файлы должны находиться в поддиректории sample относительно базового каталога, указанного в переменной окружения CLASSPATH!) и запустив ее командой java sample.Sample, можно очень долго наслаждаться непрерывной чередой идущих к "Яндексу" запросов, многие из которых могут служить источником великого вдохновения...

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

Начинать освоение Java лучше всего с официального сайта Java - java.sun.com. Объем информации на этом сайте поражает воображение, но, тем не менее, - все очень четко структурировано, разбито на категории и разложено по полочкам. Любой уважающий себя программист на Java хотя бы раз в месяц заходит на java.sun.com, так как Java - язык, развивающийся очень быстро. Правда, у официального сайта Java есть один недостаток (или достоинство - это уж кому как): он целиком и полностью на английском языке. А тем, кто больше уважает родной, великий и могучий, можно порекомендовать прекрасные русскоязычные сайты www.javable.com и www.javapower.ru.

Далее. Библией, Кораном, а иногда - и Кама-Сутрой Java-разработчика является книга Брюса Эккеля "Thinking in Java". В ней очень доступным языком изложены основы объектно-ориентированного мышления, приемы программирования на Java, основные способы использования классов стандартной библиотеки и еще многое, многое другое. Владеющие английским могут скачать оригинал с сайта автора www.bruceeckel.com, а для всех остальных издательство "Питер" подготовило русское издание этой книги под названием "Философия Java". А вообще, ресурсов, посвященных Java, - неисчислимое множество. Достаточно набрать это слово в любом поисковике, чтобы воочию убедиться - это действительно один из самых популярных языков программирования!

Язык Java (правильно произносить "джава" с характерным английским выговором, хотя отдельные личности до сих пор не могут отказаться от вредной привычки произносить это слово как "ява" или даже "жаба") изначально задумывался как универсальный язык для программирования различных бытовых электронных устройств и назывался Oak. Воодушевляющее видение будущего дивного нового мира от компании Sun Microsystems, в котором каждый холодильник подключен к продуктовому магазину и умеет сам заказывать на дом молоко, а любая кофеварка варит кофе в многозадачном режиме и даже оповещает своего владельца о готовности напитка по электронной почте (ICQ, SMS, голосовой почте - нужное подчеркнуть), было весьма заразительным. Но вот язык был создан, шли годы, а светлое будущее все никак не наступало. Зато активно развивался Интернет. И именно по этой причине Билл Джой, руководитель отдела научных разработок Sun, принял решение о срочной переориентации проекта Oak в сторону как можно более тесной интеграции с интернет-технологиями. Язык переименовали в Java, снабдили очень неплохой сетевой библиотекой, договорились с Netscape и Microsoft об интеграции Java-машины в их браузеры (что дало возможность веб-мастерам украшать свои страницы полезными и не очень апплетами), придумали ему эмблему в виде чашечки кофе (в память о несбывшейся мечте об интернет-кофеварке) и выпустили на мировой рынок. И довольно успешно: за прошедшие 6 лет язык Java стал вторым по популярности после C++, проник в самые различные области, включая разработку крупномасштабных проектов, и вообще очень даже неплохо себя чувствует.

Java - это объектно-ориентированный язык наподобие C++, только более близкий к истинной объектно-ориентированной парадигме. И программисту, которому уже довелось писать программы на традиционных процедурных языках вроде Паскаля или C, придется кардинальным образом менять свой образ мышления. Зато человеку, еще не искушенному в тонкостях согласования списков аргументов, алгоритмической декомпозиции и прочих особенностях процедурного программирования, освоение Java не должно показаться чрезмерно сложным (уж во всяком случае, этот язык значительно проще C++).

Александр Темерев
Впервые статья была опубликована в журнале "Мир Internet" (www.iworld.ru)