Современный язык Java. Лямбда-выражения, потоки и функциональное программирование

This document was uploaded by one of our users. The uploader already confirmed that they had the permission to publish it. If you are author/publisher or own the copyright of this documents, please report to us by using this DMCA report form.

Simply click on the Download Book button.

Yes, Book downloads on Ebookily are 100% Free.

Sometimes the book is free on Amazon As well, so go ahead and hit "Search on Amazon"

Преимущество современных приложений — в передовых решениях, включающих микросервисы, реактивные архитектуры и потоковую обработку данных. Лямбда-выражения, потоки данных и долгожданная система модулей платформы Java значительно упрощают их реализацию. Пришло время повысить свою квалификацию и встретить любой вызов во всеоружии! Книга поможет вам овладеть новыми возможностями современных дополнений, таких как API Streams и система модулей платформы Java. Откройте для себя новые подходы к конкурентности и узнайте, как концепции функциональности улучшают работу с кодом. В этой книге: • Новые возможности Java. • Потоковые данные и реактивное программирование. • Система модулей платформы Java.

Author(s): Рауль-Габриэль Урма, Марио Фуско, Алан Майкрофт
Series: Для профессионалов
Edition: 1
Publisher: Питер
Year: 2020

Language: Russian
Commentary: Vector PDF
Pages: 592
City: СПб.
Tags: Programming; Debugging; Java; Concurrency; Functional Programming; Asynchronous Programming; Parallel Programming; Stream Processing; Lambda Functions; Refactoring; Reactive Programming; Testing; Domain-Specific Languages

Иллюстрация на обложке
Об авторах
Благодарности
Рауль-Габриэль Урма
Марио Фуско
Алан Майкрофт
Предисловие
Об этой книге
Структура издания
О коде
Форум для обсуждения книги
От издательства
Часть I. Основы
Глава 1. Java 8, 9, 10 и 11:
что происходит?
1.1. Итак, о чем вообще речь?
1.2. Почему Java все еще меняется
1.2.1. Место языка Java в экосистеме языков программирования
1.2.2. Потоковая обработка
1.2.3. Передача кода в методы и параметризация поведения
1.2.4. Параллелизм и разделяемые изменяемые данные
1.2.5. Язык Java должен развиваться
1.3. Функции в Java
1.3.1. Методы и лямбда-выражения как полноправные граждане
1.3.2. Передача кода: пример
1.3.3. От передачи методов к лямбда-выражениям
1.4. Потоки данных
1.4.1. Многопоточность — трудная задача
1.5. Методы с реализацией по умолчанию и модули Java
1.6. Другие удачные идеи, заимствованные из функционального программирования
Резюме
Глава 2. Передача кода и параметризация поведения
2.1. Как адаптироваться к меняющимся требованиям
2.1.1. Первая попытка: фильтрация зеленых яблок
2.1.2. Вторая попытка: параметризация цвета
2.1.3. Третья попытка: фильтрация по всем возможным атрибутам
2.2. Параметризация поведения
2.2.1. Четвертая попытка: фильтрация по абстрактному критерию
2.3. Делаем код лаконичнее
2.3.1. Анонимные классы
2.3.2. Пятая попытка: использование анонимного класса
2.3.3. Шестая попытка: использование лямбда-выражения
2.3.4. Седьмая попытка: абстрагирование по типу значений списка
2.4. Примеры из практики
2.4.1. Сортировка с помощью интерфейса Comparator
2.4.2. Выполнение блока кода с помощью интерфейса Runnable
2.4.3. Возвращение результатов выполнения задачи с помощью интерфейса Callable
2.4.4. Обработка событий графического интерфейса
Резюме
Глава 3. Лямбда-выражения
3.1. Главное о лямбда-выражениях
3.2. Где и как использовать лямбда-выражения
3.2.1. Функциональный интерфейс
3.2.2. Функциональные дескрипторы
3.3. Практическое использование лямбда-выражений: паттерн охватывающего выполнения
3.3.1. Шаг 1: вспоминаем параметризацию поведения
3.3.2. Шаг 2: используем функциональный интерфейс для передачи поведения
3.3.3. Шаг 3: выполняем нужный вариант поведения!
3.3.4. Шаг 4: передаем лямбда-выражения
3.4. Использование функциональных интерфейсов
3.4.1. Интерфейс Predicate
3.4.2. Интерфейс Consumer
3.4.3. Интерфейс Function
3.5. Проверка типов, вывод типов и ограничения
3.5.1. Проверка типов
3.5.2. То же лямбда-выражение, другие функциональные интерфейсы
3.5.3. Вывод типов
3.5.4. Использование локальных переменных
3.6. Ссылки на методы
3.6.1. В общих чертах
3.6.2. Ссылки на конструкторы
3.7. Практическое использование лямбда-выражений и ссылок на методы
3.7.1. Шаг 1: передаем код
3.7.2. Шаг 2: используем анонимный класс
3.7.3. Шаг 3: используем лямбда-выражения
3.7.4. Шаг 4: используем ссылки на методы
3.8. Методы, удобные для композиции лямбда-выражений
3.8.1. Композиция объектов Comparator
3.8.2. Композиция предикатов
3.8.3. Композиция функций
3.9. Схожие математические идеи
3.9.1. Интегрирование
3.9.2. Переводим на язык лямбда-выражений Java 8
Резюме
Часть II. Функциональное программирование с помощью потоков
Глава 4. Знакомство с потоками данных
4.1. Что такое потоки данных
4.2. Знакомимся с потоками данных
4.3. Потоки данных и коллекции
4.3.1. Строго однократный проход
4.3.2. Внутренняя и внешняя итерация
4.4. Потоковые операции
4.4.1. Промежуточные операции
4.4.2. Завершающие операции
4.4.3. Работа с потоками данных
Резюме
Глава 5. Работа с потоками данных
5.1. Фильтрация
5.1.1. Фильтрация с помощью предиката
5.1.2. Фильтрация уникальных элементов
5.2. Срез потока данных
5.2.1. Срез с помощью предиката
5.2.2. Усечение потока данных
5.2.3. Пропуск элементов
5.3. Отображение
5.3.1. Применение функции к каждому из элементов потока данных
5.3.2. Схлопывание потоков данных
5.4. Поиск и сопоставление с шаблоном
5.4.1. Проверяем, удовлетворяет ли предикату хоть один элемент
5.4.2. Проверяем, удовлетворяют ли предикату все элементы
5.4.3. Поиск элемента в потоке
5.4.4. Поиск первого элемента
5.5. Свертка
5.5.1. Суммирование элементов
5.5.2. Максимум и минимум
5.6. Переходим к практике
5.6.1. Предметная область: трейдеры и транзакции
5.6.2. Решения
5.7. Числовые потоки данных
5.7.1. Версии потоков для простых типов данных
5.7.2. Числовые диапазоны
5.7.3. Применяем числовые потоки данных на практике: пифагоровы тройки
5.8. Создание потоков данных
5.8.1. Создание потока данных из перечня значений
5.8.2. Создание потока данных из объекта, допускающего неопределенное значение
5.8.3. Создание потоков данных из массивов
5.8.4. Создание потоков данных из файлов
5.8.5. Потоки на основе функций: создание бесконечных потоков
Резюме
Глава 6. Сбор данных с помощью потоков
6.1. Главное о коллекторах
6.1.1. Коллекторы как продвинутые средства свертки
6.1.2. Встроенные коллекторы
6.2. Свертка и вычисление сводных показателей
6.2.1. Поиск максимума и минимума в потоке данных
6.2.2. Вычисление сводных показателей
6.2.3. Объединение строк
6.2.4. Обобщение вычисления сводных показателей с помощью свертки
6.3. Группировка
6.3.1. Дальнейшие операции со сгруппированными элементами
6.3.2. Многоуровневая группировка
6.3.3. Сбор данных в подгруппы
6.4. Секционирование
6.4.1. Преимущества секционирования
6.4.2. Секционирование чисел на простые и составные
6.5. Интерфейс Collector
6.5.1. Разбираемся с объявленными в интерфейсе Collector методами
6.5.2. Собираем все вместе
6.6. Разрабатываем собственный, более производительный коллектор
6.6.1. Деление только на простые числа
6.6.2. Сравнение производительности коллекторов
Резюме
Глава 7. Параллельная обработка данных и производительность
7.1. Параллельные потоки данных
7.1.1. Превращаем последовательный поток данных в параллельный
7.1.2. Измерение быстродействия потока данных
7.1.3. Правильное применение параллельных потоков данных
7.1.4. Эффективное использование параллельных потоков данных
7.2. Фреймворк ветвления-объединения
7.2.1. Работа с классом RecursiveTask
7.2.2. Рекомендуемые практики применения фреймворка ветвления-объединения
7.2.3. Перехват работы
7.3. Интерфейс Spliterator
7.3.1. Процесс разбиения
7.3.2. Реализация собственного сплитератора
Резюме
Часть III. Эффективное программирование с помощью потоков и лямбда-выражений
Глава 8. Расширения Collection API
8.1. Фабрики коллекций
8.1.1. Фабрика списков
8.1.2. Фабрика множеств
8.1.3. Фабрики ассоциативных массивов
8.2. Работа со списками и множествами
8.2.1. Метод removeIf
8.2.2. Метод replaceAll
8.3. Работа с ассоциативными массивами
8.3.1. Метод forEach
8.3.2. Сортировка
8.3.3. Метод getOrDefault
8.3.4. Паттерны вычисления
8.3.5. Паттерны удаления
8.3.6. Способы замены элементов
8.3.7. Метод merge
8.4. Усовершенствованный класс ConcurrentHashMap
8.4.1. Свертка и поиск
8.4.2. Счетчики
8.4.3. Представление в виде множества
Резюме
Глава 9. Рефакторинг, тестирование и отладка
9.1. Рефакторинг с целью повышения удобочитаемости и гибкости кода
9.1.1. Повышаем удобочитаемость кода
9.1.2. Из анонимных классов — в лямбда-выражения
9.1.3. Из лямбда-выражений — в ссылки на методы
9.1.4. От императивной обработки данных до потоков
9.1.5. Повышаем гибкость кода
9.2. Рефакторинг объектно-ориентированных паттернов проектирования с помощью лямбда-выражений
9.2.1. Стратегия
9.2.2. Шаблонный метод
9.2.3. Наблюдатель
9.2.4. Цепочка обязанностей
9.2.5. Фабрика
9.3. Тестирование лямбда-выражений
9.3.1. Тестирование поведения видимого лямбда-выражения
9.3.2. Делаем упор на поведение метода, использующего лямбда-выражение
9.3.3. Разносим сложные лямбда-выражения по отдельным методам
9.3.4. Тестирование функций высшего порядка
9.4. Отладка
9.4.1. Изучаем трассу вызовов в стеке
9.4.2. Журналирование информации
Резюме
Глава 10. Предметно-ориентированные языки и лямбда-выражения
10.1. Специальный язык для конкретной предметной области
10.1.1. За и против предметно-ориентированных языков
10.1.2. Доступные на JVM решения, подходящие для создания DSL
10.2. Малые DSL в современных API Java
10.2.1. Stream API как DSL для работы с коллекциями
10.2.2. Коллекторы как предметно-ориентированный язык агрегирования данных
10.3. Паттерны и методики создания DSL на языке Java
10.3.1. Связывание методов цепочкой
10.3.2. Вложенные функции
10.3.3. Задание последовательности функций с помощью лямбда-выражений
10.3.4. Собираем все воедино
10.3.5. Использование ссылок на методы в DSL
10.4. Реальные примеры DSL Java 8
10.4.1. jOOQ
10.4.2. Cucumber
10.4.3. Фреймворк Spring Integration
Резюме
Часть IV. Java на каждый день
11
Класс Optional как лучшая альтернатива null
11.1. Как смоделировать отсутствие значения
11.1.1. Снижение количества исключений NullPointerException с помощью проверки на безопасность
11.1.2. Проблемы, возникающие с null
11.1.3. Альтернативы null в других языках программирования
11.2. Знакомство с классом Optional
11.3. Паттерны для внедрения в базу кода опционалов
11.3.1. Создание объектов Optional
11.3.2. Извлечение и преобразование значений опционалов с помощью метода map
11.3.3. Связывание цепочкой объектов Optional с помощью метода flatMap
11.3.4. Операции над потоком опционалов
11.3.5. Действия по умолчанию и распаковка опционалов
11.3.6. Сочетание двух опционалов
11.3.7. Отбрасывание определенных значений с помощью метода filter
11.4. Примеры использования опционалов на практике
11.4.1. Обертывание потенциально пустого значения в опционал
11.4.2. Исключения или опционалы?
11.4.3. Версии опционалов для простых типов данных и почему их лучше не использовать
11.4.4. Собираем все воедино
Резюме
12
Новый API для работы с датой и временем
12.1. Классы LocalDate, LocalTime, LocalDateTime, Instant, Duration и Period
12.1.1. Работа с классами LocalDate и LocalTime
12.1.2. Сочетание даты и времени
12.1.3. Класс Instant: дата и время для компьютеров
12.1.4. Описание продолжительности и промежутков времени
12.2. Операции над датами, синтаксический разбор и форматирование дат
12.2.1. Работа с классом TemporalAdjusters
12.2.2. Вывод в консоль и синтаксический разбор объектов даты/времени
12.3. Различные часовые пояса и системы летоисчисления
12.3.1. Использование часовых поясов
12.3.2. Фиксированное смещение от UTC/времени по Гринвичу
12.3.3. Использование альтернативных систем летоисчисления
Резюме
13
Методы с реализацией по умолчанию
13.1. Эволюция API
13.1.1. Версия 1 API
13.1.2. Версия 2 API
13.2. Коротко о методах с реализацией по умолчанию
13.3. Примеры использования методов с реализацией по умолчанию
13.3.1. Необязательные методы
13.3.2. Множественное наследование поведения
13.4. Правила разрешения конфликтов
13.4.1. Три важных правила разрешения неоднозначностей
13.4.2. Преимущество — у самого конкретного интерфейса из числа содержащих реализацию по умолчанию
13.4.3. Конфликты и разрешение неоднозначностей явным образом
13.4.4. Проблема ромбовидного наследования
Резюме
14
Система модулей Java
14.1. Движущая сила появления системы модулей Java: размышления о ПО
14.1.1. Разделение ответственности
14.1.2. Скрытие информации
14.1.3. Программное обеспечение на языке Java
14.2. Причины создания системы модулей Java
14.2.1. Ограничения модульной организации
14.2.2. Монолитный JDK
14.2.3. Сравнение с OSGi
14.3. Модули Java: общая картина
14.4. Разработка приложения с помощью системы модулей Java
14.4.1. Подготовка приложения
14.4.2. Мелкоблочная и крупноблочная модуляризация
14.4.3. Основы системы модулей Java
14.5. Работа с несколькими модулями
14.5.1. Выражение exports
14.5.1. Выражение requires
14.5.3. Именование
14.6. Компиляция и компоновка
14.7. Автоматические модули
14.8. Объявление модуля и выражения
14.8.1. Выражение requires
14.8.2. Выражение exports
14.8.3. Выражение requires transitive
14.8.4. Выражение exports ... to
14.8.5. Выражения open и opens
14.8.6. uses и provides
14.9. Пример побольше и дополнительные источники информации
Резюме
Часть V. Расширенная конкурентность в языке Java
15
Основные концепции класса CompletableFuture и реактивное программирование
15.1. Эволюция поддержки конкурентности в Java
15.1.1. Потоки выполнения и высокоуровневые абстракции
15.1.2. Исполнители и пулы потоков выполнения
15.1.3. Другие абстракции потоков выполнения: (не) вложенность в вызовы методов
15.1.4. Что нам нужно от потоков выполнения
15.2. Синхронные и асинхронные API
15.2.1. Фьючерсный API
15.2.2. Реактивный API
15.2.3. Приостановка и другие блокирующие операции вредны
15.2.4. Смотрим правде в глаза
15.2.5. Исключения и асинхронные API
15.3. Модель блоков и каналов
15.4. Реализация конкурентности с помощью класса CompletableFuture и комбинаторов
15.5. Публикация/подписка и реактивное программирование
15.5.1. Пример использования для суммирования двух потоков сообщений
15.5.2. Противодавление
15.5.3. Простой вариант реализации противодавления на практике
15.6. Реактивные системы и реактивное программирование
Резюме
16
Класс CompletableFuture: композиция асинхронных компонентов
16.1. Простые применения фьючерсов
16.1.1. Разбираемся в работе фьючерсов и их ограничениях
16.1.2. Построение асинхронного приложения с помощью завершаемых фьючерсов
16.2. Реализация асинхронного API
16.2.1. Преобразование синхронного метода в асинхронный
16.2.2. Обработка ошибок
16.3. Делаем код неблокирующим
16.3.1. Распараллеливание запросов с помощью параллельного потока данных
16.3.2. Выполнение асинхронных запросов с помощью завершаемых фьючерсов
16.3.3. Поиск лучше масштабируемого решения
16.3.4. Пользовательский исполнитель
16.4. Конвейерная организация асинхронных задач
16.4.1. Реализация сервиса скидок
16.4.2. Использование скидочного сервиса
16.4.3. Композиция синхронных и асинхронных операций
16.4.4. Сочетание двух завершаемых фьючерсов: зависимого и независимого
16.4.5. Сравниваем фьючерсы с завершаемыми фьючерсами
16.4.6. Эффективное использование тайм-аутов
16.5. Реагирование на завершение CompletableFuture
16.5.1. Рефакторинг приложения для поиска наилучшей цены
16.5.2. Собираем все вместе
Резюме
17
Реактивное программирование
17.1. Манифест реактивности
17.1.1. Реактивность на прикладном уровне
17.1.2. Реактивность на системном уровне
17.2. Реактивные потоки данных и Flow API
17.2.1. Знакомство с классом Flow
17.2.2. Создаем ваше первое реактивное приложение
17.2.3. Преобразование данных с помощью интерфейса Processor
17.2.4. Почему Java не предоставляет реализации Flow API
17.3. Реактивная библиотека RxJava
17.3.1. Создание и использование наблюдаемых объектов
17.3.2. Преобразование и группировка наблюдаемых объектов
Резюме
Часть VI. Функциональное программирование и эволюция языка Java
18
Мыслим функционально
18.1. Создание и сопровождение систем
18.1.1. Разделяемые изменяемые данные
18.1.2. Декларативное программирование
18.1.3. Почему функциональное программирование?
18.2. Что такое функциональное программирование
18.2.1. Функциональное программирование на языке Java
18.2.2. Функциональная прозрачность
18.2.3. Объектно-ориентированное и функциональное программирование
18.2.4. Функциональное программирование в действии
18.3. Рекурсия и итерация
Резюме
19
Методики функционального программирования
19.1. Повсюду функции
19.1.1. Функции высшего порядка
19.1.2. Каррирование
19.2. Персистентные структуры данных
19.2.1. Деструктивные и функциональные обновления
19.2.2. Другой пример, с деревьями
19.2.3. Функциональный подход
19.3. Отложенное вычисление с помощью потоков данных
19.3.1. Самоопределяющиеся потоки данных
19.3.2. Наш собственный отложенный список
19.4. Сопоставление с шаблоном
19.4.1. Паттерн проектирования «Посетитель»
19.4.2. На помощь приходит сопоставление с шаблоном
19.5. Разное
19.5.1. Кэширование или мемоизация
19.5.2. Что значит «вернуть тот же самый объект»?
19.5.3. Комбинаторы
Резюме
20
Смесь ООП и ФП: сравнение Java и Scala
20.1. Введение в Scala
20.1.1. Приложение Hello beer
20.1.2. Основные структуры данных Scala: List, Set, Map, Stream, Tuple и Option
20.2. Функции
20.2.1. Полноправные функции
20.2.2. Анонимные функции и замыкания
20.2.3. Каррирование
20.3. Классы и типажи
20.3.1. Код с классами Scala становится лаконичнее
20.3.2. Типажи Scala и интерфейсы Java
Резюме
21
Заключение и дальнейшие перспективы Java
21.1. Обзор возможностей Java 8
21.1.1. Параметризация поведения (лямбда-выражения и ссылки на методы)
21.1.2. Потоки данных
21.1.3. Класс CompletableFuture
21.1.4. Класс Optional
21.1.5. Flow API
21.1.6. Методы с реализацией по умолчанию
21.2. Система модулей Java 9
21.3. Вывод типов локальных переменных в Java 10
21.4. Что ждет Java в будущем?
21.4.1. Вариантность по месту объявления
21.4.2. Сопоставление с шаблоном
21.4.3. Более полнофункциональные формы обобщенных типов
21.4.4. Расширение поддержки неизменяемости
21.4.5. Типы-значения
21.5. Ускорение развития Java
21.6. Заключительное слово
Приложения
А. Прочие изменения языка
A.1. Аннотации
A.1.1. Повторяющиеся аннотации
A.1.2. Аннотации типов
A.2. Обобщенный вывод целевых типов
Б. Прочие изменения в библиотеках
Б.1. Коллекции
Б.1.1. Добавленные методы
Б.1.2. Класс Collections
Б.1.3. Интерфейс Comparator
Б.2. Конкурентность
Б.2.1. Пакет Atomic
Б.2.2. ConcurrentHashMap
Б.3. Массивы
Б.3.1. Использование метода parallelSort
Б.3.2. Использование методов setAll и parallelSetAll
Б.3.3. Использование метода parallelPrefix
Б.4. Классы Number и Math
Б.4.1. Класс Number
Б.4.2. Класс Math
Б.5. Класс Files
Б.6. Рефлексия
Б.7. Класс String
В. Параллельное выполнение нескольких операций над потоком данных
В.1. Ветвление потока данных
В.1.1. Реализация интерфейса Results на основе класса ForkingStreamConsumer
В.1.2. Разработка классов ForkingStreamConsumer и BlockingQueueSpliterator
В.1.3. Применяем StreamForker на практике
В.2. Вопросы производительности
Г. Лямбда-выражения и байт-код JVM
Г.1. Анонимные классы
Г.2. Генерация байт-кода
Г.3. Invokedynamic спешит на помощь
Г.4. Стратегии генерации кода