Java. Новое поколение разработки

Java. Новое поколение разработки
Автор: Б. Эванс, М. Вербург
Год: 2014
ISBN: 978-5-496-00544-9
Страниц: 560
Язык: Русский
Формат: PDF
Размер: 24 Мб

Download

В этой книге представлен оригинальный и практичный взгляд на новые возможности Java 7 и новые языки для виртуальной машины Java (JVM), а также рассмотрены некоторые вспомогательные технологии, необходимые для создания Java-программ завтрашнего дня.
Книга начинается с подробного описания новшеств Java 7, таких как работа с ресурсами в блоке try (конструкция try-with-resources) и новый неблокирующий ввод-вывод (NIO.2). Далее вас ждет экспресс-обзор трех сравнительно новых языков для виртуальной машины Java — Groovy, Scala и Clojure. Вы увидите четкие понятные примеры, которые помогут вам ознакомиться с десятками удобных и практичных приемов. Вы изучите современные методы разработки, обеспечения параллелизма, производительности, а также многие другие интересные темы.
В этой книге:
— новые возможности Java 7;
— вводный курс по работе с языками Groovy, Scala и Clojure;
— обсуждение проблем многоядерной обработки и параллелизма;
— функциональное программирование на новых языках для JVM;
— современные подходы к тестированию, сборке и непрерывной интеграции

+

Многоязычное программирование на виртуальной машине Java

Глава 7. Альтернативные языки для виртуальной машины Java
Глава 8. Groovy — динамический приятель Java
Глава 9. Язык Scala — мощный и лаконичный
Глава 10. Clojure: программирование повышенной надежности

Эта часть книги посвящена исследованию новых языковых парадигм и многоязычному программированию на виртуальной машине Java.
Виртуальная машина Java — замечательная среда времени исполнения. Она не только обеспечивает производительность и мощность, но и дает программисту удивительную гибкость в работе. На самом деле виртуальная машина Java позволяет сделать первый шаг к исследованию других языков, а не только Java. На ней вы можете опробовать совершенно новые для вас подходы к программированию.
Если до сих пор вы программировали только на Java, то можете спросить: «А зачем мне учить другие языки?» Как мы говорили в главе 1, профессиональный Java-разработчик старается постоянно совершенствоваться во всех тонкостях языка Java, полнее осваивать платформу и экосистему. Для этого необходимо вникать в темы, которые пока только вырисовываются на горизонте, но в ближайшем будущем станут неотъемлемыми частями технологической среды.

Оказывается, что многие новые идеи, которые будут востребованы в будущем, уже сегодня присутствуют в других языках виртуальной машины Java. Это касается, например, функционального программирования. Изучив новый язык для виртуальной машины Java, вы можете украдкой заглянуть в другой мир, напоминающий мир будущего, в котором вам доведется реализовывать новые проекты. Исследуя незнакомую точку зрения на проблему, вы сможете применить уже имеющиеся знания под новым углом. Таким образом, изучая новый язык, вы можете обнаружить у себя новые таланты и освоить навыки, которые пригодятся вам в дальнейшем.
Эта часть начинается с главы, объясняющей, почему Java не всегда идеально подходит для решения любых проблем, чем полезны концепции функционального программирования и почему для конкретного проекта может понадобиться не Java, а другой язык.
В последнее время появилось много книг и статей, в которых продвигается мысль о том, что в ближайшем будущем функциональное программирование будет основным рабочим навыком любого практикующего разработчика. Во многих подобных статьях функциональное программирование описано так, что непросто понять, с чем его едят. Не более понятно и то, как функциональное программирование может проявляться в таком языке, как Java.
На самом деле функциональное программирование вообще не является чем-то единым целым. Это скорее стиль и постепенное изменение общих принципов мышления разработчика. В главе 8 мы покажем примеры, которые слегка напоминают функциональное программирование. Но они сводятся всего лишь к тому, чтобы обрабатывать код коллекций в более чистом и безошибочном стиле. Для этого мы применим язык Groovy. В главе 9 мы поговорим об «объектно-функциональном» стиле, взяв для примера язык Scala. Более чистый подход к функциональному программированию (который полностью избавлен от объектной ориентации) мы обсудим в главе 10, посвященной языку Clojure.
В части 4 мы рассмотрим несколько практических случаев, в которых можно написать превосходные решения на альтернативных языках. Если хотите убедиться в этом, то прямо сейчас загляните в часть 4, а потом возвращайтесь сюда и познакомьтесь с языками, необходимыми для реализации таких приемов.

 

Язык Scala — мощный и лаконичный

В этой главе:

  • Scala — не Java;
  • синтаксис Scala и более функциональный стиль;
  • сопоставимые выражения и паттерны;
  • система типов и коллекции Scala;
  • параллельное программирование на Scala с помощью акторов.

Scala — это язык, созданный в среде ученых-информатиков и исследователей языков программирования. Он уже получил определенное распространение, так как обладает очень мощной системой типов и продвинутыми возможностями, которые
оказались очень полезны для элитных команд.
В настоящее время Scala вызывает большой интерес, но пока рано говорить, сможет ли этот язык полностью пронизать экосистему Java и составить Java конкуренцию в качестве основного языка для разработки.
Мы полагаем, что в Scala будут появляться новые команды и некоторые проекты будут писаться именно на нем. Мы также предполагаем, что множество разработчиков будут вплетать Scala в какие-нибудь проекты в течение ближайших 3–4 лет. Это означает, что основательный Java-разработчик должен иметь представление о Scala и уметь определять, подходит ли этот язык для его проектов.
Разработчик, переходящий с Java к работе со Scala, должен иметь в виду некоторые особенности. Самое главное, что нужно помнить: Scala — это не Java.
Ну да, это очевидно, скажете вы. В конце концов, все языки разные, поэтому, разумеется, Scala отличается от Java. Но, как было указано в главе 7, некоторые языки имеют больше общих черт, другие — меньше. Когда мы знакомили вас с языком Groovy в главе 8, мы подчеркивали сходство между Groovy и Java. Возможно, это пригодилось вам при изучении вашего первого языка для JVM, не являющегося Java.
В этой главе мы будем действовать иначе — для начала подчеркнем те черты Scala, которые составляют его специфику. Считайте это небольшой экскурсией под названием «Scala в естественной среде обитания» — в ходе нее мы покажем, как писать на Scala, а не на построчном переводе с Java на Scala. Далее мы обсудим характеристики проектов, то есть покажем, как определить, подходит ли Scala для вашего проекта. Затем мы рассмотрим некоторые синтаксические инновации Scala, позволяющие писать на Scala красивый и лаконичный код. Потом поговорим о том, как в Scala организована объектная ориентация, после чего изучим раздел о коллекциях и структурах данных. Завершим главу разделом о том, как в Scala организован параллелизм, и изучим мощную модель акторов, действующую в этом языке.
Изучая наиболее замечательные свойства Scala, мы постепенно расскажем о синтаксисе (и обо всех других необходимых концепциях). Scala — довольно большой язык по сравнению с Java. Здесь больше базовых концепций, а также синтаксических тонкостей, которые необходимо учитывать. Это означает, что чем больше кода на Scala вы будете просматривать, тем больше языковых свойств у вас получится усвоить самостоятельно.
Сделаем краткий обзор тем, с которыми предстоит плотнее познакомиться по ходу этой главы. Это поможет вам привыкнуть к характерному синтаксису Scala и подготовиться к дальнейшему чтению.

Быстрый обзор Scala

Вот основные моменты, которые мы хотели бы предвосхитить:

  • краткость языка Scala и действующая в нем мощная система выведения типов;
  • сопоставимые выражения и связанные с ними концепции — паттерны и case-классы;
  • параллелизм в Scala, основанный на системе сообщений и акторов, а не на блокировках, как в классическом коде на Java.

Эти темы еще не позволяют получить представление обо всем языке или стать профессиональным Scala-разработчиком. Мы просто подогреем ваше любопытство и покажем несколько конкретных примеров, в которых удобно применять Scala. Чтобы пойти дальше и исследовать язык более подробно, можете почитать специализированные онлайн-ресурсы или книгу, в которой подробно рассматривается язык Scala. В качестве примера такой книги можем порекомендовать труд Scala in Depth Джошуа Сьюреса (Joshua Suereth) (издательство Manning, 2012).
Важнейшая и наиболее заметная особенность Scala, о которой мы хотели упомянуть, — это лаконичность синтаксиса. Поговорим об этом.

Резюме

Язык Scalaсущественно отличается от Java:

  • в Scala можно пользоваться функциональными приемами, обеспечивая более гибкий стиль программирования;
  • благодаря выведению типов можно заставить статически типизированный язык действовать в более динамическом духе;
  • продвинутая система типов Scala позволяет существенно расширить концепцию объектной ориентации, известную вам из Java.

В следующей главе мы поговорим о последнем из упомянутых выше альтернативных языков для виртуальной машины Java. Речь пойдет о Clojure, представляющем собой диалект Lisp. Этот язык во многих отношениях очень не похож на Java.
В ходе работы мы будем опираться на концепции неизменяемости, функционального программирования и альтернативного параллелизма, которые затрагивались в этой главе. Мы покажем, как Clojure воплощает все эти идеи и выстраивает невероятно мощную и красивую программную экосистему.

Clojure: программирование повышенной надежности

В этой главе:

  • концепция тождественности и состояния в Clojure;
  • модель REPL в Clojure;
  • синтаксис Clojure, структуры данных и последовательности;
  • взаимодействие Clojure с Java;
  • многопоточная разработка на языке Clojure;
  • программная транзакционная память.

Язык Clojure весьма отличается по стилю от Java и других языков, рассмотренных нами выше. Clojure — это адаптированный для виртуальной машины Java вариант одного из старейших языков программирования — Lisp. Если вы не знаете Lisp — не волнуйтесь. Мы расскажем вам все необходимое о семействе языков Lisp, чтобы вы могли начать работать с Clojure.
Кроме большого багажа мощных приемов программирования, взятых из классического Lisp, Clojure предлагает и интереснейшие ультрасовременные технологии, важные для профессионального Java-разработчика. Благодаря такой комбинации качеств Clojure оказывается выдающимся языком для виртуальной машины Java, очень привлекательным для разработки приложений.
В качестве примеров из нового арсенала Clojure можно привести инструментарии для параллельного программирования на этом языке, а также структуры данных. Параллельные абстракции позволяют программистам писать гораздо более безопасный многопоточный код. Их можно комбинировать с присутствующей в Clojure абстракцией seq(это новый подход к работе с коллекциями и структурами данных), чтобы разработчик приобретал очень широкие возможности.
Для обеспечения всех этих возможностей Clojure организует некоторые языковые концепции принципиально иначе, нежели Java. Благодаря этой разнице Clojure интересен для изучения. Возможно, освоив этот язык, вы станете по-другому представлять себе программирование. Изучив Clojure, вы сможете более качественно программировать на любом языке.

Взаимодействие между Clojure и Java

Язык Clojure с самого начала проектировался для работы на виртуальной машине Java, и он не пытается полностью скрыть характер JVM от программиста. Такие конкретные дизайнерские решения очевидны в нескольких случаях. Например, на уровне системы типов и списки и векторы Clojure реализуют List — стандартный интерфейс из библиотеки коллекций Java. Кроме того, мы с легкостью можем использовать в Clojure библиотеки Java и наоборот.
Эти свойства исключительно полезны, поскольку программистам Clojure открывается доступ к разнообразнейшим библиотекам и инструментарию Java. Кроме того, разработчик Clojure может опираться на поддержку производительности, действующую в JVM, и на другие возможности. В этом разделе мы обсудим несколько функций, связанных с таким взаимодействием, в частности:

  • вызов Java из Clojure;
  • способ, которым Java трактует тип функций Clojure;
  • посредников Clojure;
  • исследовательское программирование в среде REPL;
  • вызов Clojure из Java.

Изучим такую интеграцию и для начала рассмотрим, как получать доступ к методам Java из Clojure.

Использование посредников Clojure

В Clojure есть мощный макрос, называемый (proxy). Он позволяет создавать полноценный объект Clojure, строящийся на основе класса Java (либо реализующий интерфейс). Например, в листинге 10.7 мы возвращаемся к более раннему примеру (см. листинг 4.13), но основная часть самого выполнения теперь осуществляется в совсем кратком коде, что объясняется компактностью синтаксиса Clojure.

Первый векторный аргумент содержит интерфейсы, которые должен реализовывать класс-посредник. Если посредник также должен строиться на основе класса Java (а он, конечно же, может служить расширением лишь одного класса Java), то имя этого класса должно быть первым элементом вектора.
Второй векторный аргумент включает в себя параметры, которые должны быть переданы конструктору суперкласса. Зачастую этот вектор является пустым, и он определенно будет пуст во всех случаях, когда форма (proxy)просто реализует интерфейсы Java.
После двух этих аргументов идут формы, представляющие реализации отдельных методов, требуемые указанными интерфейсами или суперклассами.
Форма (proxy)обеспечивает простую реализацию любого интерфейса Java. В результате возникает интересная возможность: можно использовать среду REPL из Clojure как полигон для экспериментов с кодом Java и JVM.

Исследовательское программирование в среде REPL

Суть исследовательского программирования заключается в том, что, во-первых, благодаря синтаксису Clojure мы можем писать меньше кода, а во-вторых, система REPL предоставляет «живую» интерактивную рабочую среду. По этим причинам REPL оказывается великолепным полигоном не только для исследования программирования на Clojure, но и для подробного изучения библиотек Java.
Вспомним, как в Java реализуются списки. В них есть метод iterator(), возвращающий объект типа Iterator. Но Iterator — это интерфейс, поэтому может возникнуть вопрос: а каков же реальный тип его реализации? Это легко узнать с помощью REPL:

Использование Clojure из Java

Как вы помните, система типов Clojure тесно связана с системой типов Java. Структуры данных из Clojure — практически те же коллекции Java, и они реализуют многие обязательные интерфейсы Java. Необязательные интерфейсы обычно не реализуются, поскольку зачастую предназначены для изменения структур данных, а такие изменения в Clojure не поддерживаются.
Корреляция между системами типов позволяет использовать структуры данных Clojure в программе, написанной на Java. Более того, к этому располагает сама организация Clojure — ведь это компилируемый язык с механизмом вызовов, соответствующим требованиям JVM. Таким образом, сводится к минимуму притирка во время исполнения, и с классом, полученным из Clojure, можно обращаться практически так же, как и с любым классом Java. Интерпретируемым языкам было бы гораздо сложнее взаимодействовать с Java, как правило, им требовалась бы хотя бы минимальная не Java-поддержка во время исполнения.
В следующем примере показано, как последовательность из Clojure может применяться к обычной строке Java. Чтобы запустить этот код, необходимо включить в путь к классу файл clojure.jar:

Параллелизм в Clojure

Модель состояния, действующая в Java, целиком завязана на идее изменяемых объектов. Как было продемонстрировано в главе 4, это прямо приводит к проблемам с безопасностью параллельного кода. Приходится задействовать достаточно сложные стратегии блокировки, чтобы не позволить другим потокам видеть обрабатываемые в данный момент (а значит, несогласованные) состояния объектов, над которыми трудится конкретный поток. Эти стратегии сложны в реализации, отладке и тестировании.
Абстракции Clojure для обеспечения параллелизма в некоторых отношениях не являются настолько низкоуровневыми, как в Java. Например, может показаться странным использование пулов потоков, управляемых средой времени исполнения Clojure (сам разработчик практически не контролирует эти потоки). Но достоинство этой модели заключается в том, что платформа (в данном случае — среда времени исполнения Clojure) получает возможность тщательно вести за вас весь учет, и вы можете сосредоточиться на решении более важных задач, например на общем дизайне.
Clojure работает по принципу, в соответствии с которым потоки изначально по умолчанию изолируются друг от друга. Таким образом, в языке по определению не может быть нарушена безопасность типов при параллельной обработке. Исходя из предпосылки «ничего не требуется совместно использовать» и имея неизменяемые значения, Clojure избегает многих проблем, присущих Java, и может сосредоточиться на поиске способов безопасного разделения состояния для параллельного программирования.
На самом деле Clojure использует несколько различных методов для реализации ряда разновидностей моделей параллелизма. Это, во-первых, функции futureи pcall, во-вторых — ссылки, в-третьих — агенты. Рассмотрим все три способа, начиная с наиболее простого.

Резюме

Пожалуй, из всех языков, рассмотренных нами в этой части, Clojure наиболее сильно отличается от Java. Наследие, полученное от Lisp, неизменяемость и своеобразные подходы создают впечатление, что это совершенно не родственный Java язык. Но тесная интеграция между Clojure и виртуальной машиной Java, соответствие систем типов двух языков (даже при наличии альтернативных сущностей, например последовательностей), а также потенциал исследовательского программирования делают Clojure отличным дополнением Java.
Синергия двух языков особенно ярко проявляется в том, как Clojure делегирует многие низкоуровневые методы работы с потоками и управления параллелизмом в среде времени исполнения. Таким образом, программист освобождается от довольно кропотливой работы и может сосредоточиться на общем проектировании многопоточности и более высокоуровневых проблемах. Ситуацию можно сравнить с тем, как механизм сборки мусора в Java позволяет вам не задумываться о тонкостях управления памятью.
Различия между языками, изученными в этой части книги, красноречиво демонстрируют, как активно продолжает развиваться платформа Java и каким перспективным полем для разработки приложений она остается. Кроме того, здесь мы можем убедиться в гибкости и многофункциональности виртуальной машины Java.
В последней части книги мы продемонстрируем, как три рассмотренных выше новых языка обеспечивают новые подходы к практике разработки ПО. В следующей главе мы поговорим о разработке через тестирование — возможно, вы уже сталкивались с этой темой при программировании на Java. Но Groovy, Scala и Clojure позволяют взглянуть на эту проблему под совершенно новым углом. Надеемся, что эти языки помогут вам закрепить и расширить уже имеющиеся знания.