Java 8 была выпущена 18 марта 2014 года. Это было давно, но до сих пор многие проекты работают на Java 8. Это потому, что это был крупный выпуск с множеством новых функций. Давайте рассмотрим все захватывающие и основные функции Java 8 с примерами кода.
Краткий обзор функций Java 8
Некоторые из важных функций Java 8 включают;
- Метод forEach() в интерфейсе Iterable
- Методы по умолчанию и статические методы в интерфейсах
- Функциональные интерфейсы и лямбда-выражения
- Java Stream API для операций с массивами данных в коллекциях
- API времени в Java
- Улучшения в API коллекций
- Улучшения в API параллелизма
- Улучшения в IO в Java
Давайте кратко рассмотрим эти функции Java 8. Я предоставлю несколько фрагментов кода для лучшего понимания функций в простом виде.
1. Метод forEach() в интерфейсе Iterable
Всякий раз, когда нам нужно пройти через коллекцию, мы должны создать итератор, цель которого – перебирать элементы в коллекции, а затем у нас есть бизнес-логика в цикле для каждого из элементов в коллекции. Мы можем получить ConcurrentModificationException, если итератор используется неправильно.
В Java 8 был введен метод forEach в интерфейсе java.lang.Iterable, чтобы при написании кода мы сосредотачивались на бизнес-логике. Метод forEach принимает объект java.util.function.Consumer в качестве аргумента, поэтому он помогает разместить нашу бизнес-логику в отдельном месте, которое мы можем повторно использовать. Давайте рассмотрим использование forEach на простом примере.
Количество строк может увеличиться, но метод forEach помогает разместить логику итерации и бизнес-логику в отдельном месте, что приводит к более высокому разделению забот и более чистому коду.
2. Методы по умолчанию и статические методы в интерфейсах
Если вы внимательно прочтете детали метода forEach, вы заметите, что он определен в интерфейсе Iterable, но мы знаем, что интерфейсы не могут иметь тела метода. Начиная с Java 8, интерфейсы усовершенствованы для того, чтобы иметь метод с реализацией. Мы можем использовать ключевые слова default
и static
для создания интерфейсов с реализацией метода. Реализация метода forEach в интерфейсе Iterable:
Мы знаем, что Java не предоставляет множественное наследование в классах, потому что это приводит к Проблеме алмаза. Как теперь это будет обрабатываться с интерфейсами, если интерфейсы теперь похожи на абстрактные классы?
Решение в том, что компилятор выдаст исключение в этом сценарии, и нам придется предоставить логику реализации в классе, реализующем интерфейсы.
Обратите внимание, что у обоих интерфейсов есть общий метод log() с логикой реализации.
Как видите, Interface1
имеет статическую реализацию метода, которая используется в реализации метода MyClass.log()
. В Java 8 широко используются методы по умолчанию и статические методы в API коллекций, а методы по умолчанию добавляются для обеспечения обратной совместимости нашего кода.
Если в иерархии какого-либо класса есть метод с тем же именем, методы по умолчанию становятся неактуальными. Объект является базовым классом, поэтому, если у нас есть методы по умолчанию equals() и hashCode() в интерфейсе, они станут неактуальными. Поэтому для большей ясности интерфейсам не разрешается иметь методы по умолчанию Object.
Для полной информации об изменениях интерфейса в Java 8, пожалуйста, прочтите Изменения интерфейса в Java 8.
3. Функциональные интерфейсы и лямбда-выражения
Если вы обратите внимание на приведенный выше код интерфейса, вы заметите аннотацию @FunctionalInterface. Функциональные интерфейсы – это новая концепция, введенная в Java 8. Интерфейс с ровно одним абстрактным методом становится функциональным интерфейсом. Нам не нужно использовать аннотацию @FunctionalInterface для обозначения интерфейса как функционального.
@FunctionalInterface аннотация – это средство избежать случайного добавления абстрактных методов в функциональные интерфейсы. Вы можете рассматривать ее как аннотацию @Override, и лучше всего использовать ее. java.lang.Runnable с единственным абстрактным методом run() – отличный пример функционального интерфейса.
Одно из основных преимуществ функционального интерфейса – возможность использования лямбда-выражений для их создания. Мы можем создать экземпляр интерфейса с анонимным классом, но код выглядит громоздким.
Поскольку у функциональных интерфейсов есть только один метод, лямбда-выражения могут легко предоставить реализацию метода. Мы просто должны предоставить аргументы метода и бизнес-логику. Например, мы можем написать вышеприведенную реализацию, используя лямбда-выражение, как:
Если у вас есть один оператор в реализации метода, вам также не нужны фигурные скобки. Например, анонимный класс Interface1 выше может быть создан с использованием лямбда-выражения следующим образом:
Лямбда-выражения – это средство для создания анонимных классов функциональных интерфейсов с легкостью. Использование лямбда-выражений не приносит преимуществ во время выполнения, поэтому я буду использовать их осторожно, потому что мне не важно написать несколько дополнительных строк кода.
A new package java.util.function
has been added with bunch of functional interfaces to provide target types for lambda expressions and method references. Lambda expressions are a huge topic, I will write a separate article on that in the future.
Вы можете ознакомиться с полным руководством по ссылке Руководство по лямбда-выражениям в Java 8.
4. Java Stream API для массовых операций над коллекциями
A new java.util.stream
has been added in Java 8 to perform filter/map/reduce like operations with the collection. Stream API will allow sequential as well as parallel execution. This is one of the best features for me because I work a lot with Collections and usually with Big Data, we need to filter out them based on some conditions.
Интерфейс Collection был расширен методами stream() и parallelStream() по умолчанию для получения потока для последовательного и параллельного выполнения. Давайте посмотрим на их использование на простом примере.
Если вы запустите приведенный выше пример кода, вы получите вывод, похожий на следующий:
Обратите внимание, что значения параллельной обработки не упорядочены, поэтому параллельная обработка будет очень полезна при работе с огромными коллекциями.
В этом сообщении невозможно охватить все аспекты Stream API, вы можете прочитать обо всём, что касается Stream API, на Примере руководства по использованию Java 8 Stream API.
5. Java Time API
Работа с датой, временем и часовыми поясами в Java всегда была сложной задачей. Не было стандартного подхода или API в Java для работы с датой и временем. Одним из хороших дополнений в Java 8 является пакет java.time
, который упростит процесс работы со временем в Java.
Просматривая пакеты Java Time API, я чувствую, что они будут очень легки в использовании. Он имеет некоторые подпакеты, такие как java.time.format, который предоставляет классы для вывода и разбора дат и времени, и java.time.zone, который обеспечивает поддержку часовых поясов и их правил.
В новом API времени предпочтение отдается перечислениям перед целочисленными константами для месяцев и дней недели. Одним из полезных классов является DateTimeFormatter для преобразования объектов DateTime в строки. Для полного руководства перейдите на Пример использования Java Date Time API.
6. Улучшения в API коллекций
Мы уже видели метод forEach() и API Stream для коллекций. Некоторые новые методы, добавленные в API Collection, включают:
Iterator
метод по умолчаниюforEachRemaining(Consumer action)
для выполнения заданного действия для каждого оставшегося элемента, пока все элементы не будут обработаны или пока действие не вызовет исключение.Collection
метод по умолчаниюremoveIf(Predicate filter)
для удаления всех элементов этой коллекции, удовлетворяющих заданному предикату.Collection
методspliterator()
, возвращающий экземпляр Spliterator, который можно использовать для последовательного или параллельного обхода элементов.- Map методы
replaceAll()
,compute()
,merge()
. - Улучшение производительности для класса HashMap при коллизиях ключей
7. Улучшения API параллелизма
Некоторые важные улучшения API параллелизма включают:
ConcurrentHashMap
методы compute(), forEach(), forEachEntry(), forEachKey(), forEachValue(), merge(), reduce() и search().CompletableFuture
, который может быть явно завершен (установка его значения и статуса).Executors
методnewWorkStealingPool()
для создания пула потоков с алгоритмом украденной работы, используя все доступные процессоры в качестве целевого уровня параллелизма.
8. Улучшения в Java IO
Некоторые из улучшений IO, о которых мне известно:
Files.list(Path dir)
, возвращающий лениво заполняемый поток, элементы которого – это записи в каталоге.Files.lines(Path path)
, читающий все строки из файла как поток.Files.find()
, возвращающий лениво заполняемый поток Path, выполняющий поиск файлов в файловом дереве, начиная с заданного файла.BufferedReader.lines()
, возвращающий поток, элементами которого являются строки, прочитанные из этого BufferedReader.
Различные улучшения ядра Java 8 API
Некоторые другие улучшения API, которые могут пригодиться:
- Статический метод ThreadLocal с методом withInitial(Supplier supplier) для упрощения создания экземпляров.
- Интерфейс Comparator был расширен большим количеством методов по умолчанию и статических методов для естественного упорядочения, обратного порядка и т. д.
- Методы min(), max() и sum() в оболочках Integer, Long и Double.
- Методы logicalAnd(), logicalOr() и logicalXor() в классе Boolean.
- Метод stream() в классе ZipFile для получения упорядоченного потока элементов ZIP-файла. Элементы появляются в потоке в том же порядке, в котором они находятся в центральном каталоге ZIP-файла.
- Несколько вспомогательных методов в классе Math.
jjs
команда добавлена для вызова движка Nashorn.jdeps
команда добавлена для анализа файлов классов.- Мост JDBC-ODBC был удален.
- Пространство памяти PermGen было удалено.
Это все особенности Java 8 с примерами программ. Если я упустил какие-то важные особенности Java 8, пожалуйста, дайте знать через комментарии.
Source:
https://www.digitalocean.com/community/tutorials/java-8-features-with-examples