Java 8 произвела революцию в Java. Это, пожалуй, самый значительный выпуск Java за последние 10 лет . Существует множество новых функций, включая методы по умолчанию, ссылки на методы и конструкторы и лямбда-выражения, и это лишь некоторые из них .
Одной из наиболее интересных функций является новый API java.util.stream
, который, как утверждает Javadoc, позволяет
операции в функциональном стиле над потоками элементов, такие как преобразования карты-сокращения в коллекциях
Объедините этот новый API с лямбда-выражениями, и вы получите краткий, но мощный синтаксис, который значительно упрощает код за счет применения проекций.
Взять, к примеру, якобы простую задачу фильтрации коллекции. В этом случае простая Collection
типов Message
, созданная так:
Создание коллекции сообщений
1
2
3
4
5
|
List<Message> messages = new ArrayList<>(); messages.add( new Message( "aglover" , "foo" , 56854 )); messages.add( new Message( "aglover" , "foo" , 85 )); messages.add( new Message( "aglover" , "bar" , 9999 )); messages.add( new Message( "rsmith" , "foo" , 4564 )); |
В этой коллекции я бы хотел отфильтровать Message
с delay
(3-й параметр конструктора), превышающей 3000 секунд.
До Java 8 вы могли вручную заклинить такую логику следующим образом:
Фильтрация стиля старой школы
1
2
3
4
5
|
for (Message message : messages) { if (message.delay > 3000 ) { System.out.println(message); } } |
Однако в Java 8 эта работа становится намного более лаконичной. Коллекции теперь поддерживают stream
метод, который преобразует базовую структуру данных в stream
объектов, способный к итерации, и, таким образом, разрешает новое поколение функциональных операций, использующих лямбда-выражения. Большинство из этих операций также могут быть связаны. Эти цепочечные методы называются промежуточными , а методы, которые не могут быть связаны, обозначаются как терминальные .
Вкратце, лямбда-выражения во многом похожи на анонимные классы, но с гораздо меньшим синтаксисом. Например, если вы посмотрите на Javadoc для параметра метода Stream
, вы увидите, что он принимает тип Predicate
. Тем не менее, вам не нужно реализовывать этот интерфейс, как, скажем, до Java 8 с анонимным классом. Следовательно, лямбда-выражение Predicate
для фильтрации всех значений delay
больше 3000 будет:
Лямбда-выражение
1
|
x -> x.delay > 3000 |
Где x
— параметр, передаваемый для каждого значения в потоке, и все, что находится справа от ->
является оцененным выражением.
Объединение всего этого в Java 8 дает:
Потоковые лямбды!
1
|
messages.stream().filter(m -> m.delay > 3000 ).forEach(item -> System.out.println(item)); |
Интересно, что благодаря некоторым другим новым функциям Java 8, лямбда forEach
может быть упрощена до:
Потоковые лямбды еще короче!
1
|
messages.stream().filter(m -> m.delay > 3000 ).forEach(System.out::println); |
Поскольку параметр forEach
lambda просто используется println
, Java 8 теперь позволяет вам полностью удалить этот параметр.
Ранее я упоминал, что потоки позволяют вам связывать лямбды — в приведенном выше случае метод filter
является промежуточным, а forEach
— терминальным. Другими промежуточными методами, которые сразу распознаются функциональными программистами, являются: map
, flatMap
и flatMap
, если назвать несколько.
Чтобы уточнить, я хотел бы найти все Message
с задержкой более 3000 секунд и суммировать общее время задержки. Без функциональной магии я мог бы написать:
Прозаическая Ява
1
2
3
4
5
6
|
long totalWaitTime = 0 ; for (Message message : messages) { if (message.delay > 3000 ) { totalWaitTime += message.delay; } } |
Тем не менее, с Java 8 и немного функционала, вы можете получить более элегантную конструкцию кода, например:
Java 8 элегантность
1
|
long totWaitTime = messages.stream().filter(m -> m.delay > 3000 ).mapToLong(m -> m.delay).sum(); |
Обратите внимание, как я могу mapToLong
методы filter
и mapToLong
вместе с терминальной sum
. Кстати, для метода sum
требуется определенный метод стиля карты, который выдает коллекцию примитивных типов, таких как mapToLong
, mapToInt
и т. Д.
Функциональное программирование стиля как ключевая особенность языка — поразительно мощная конструкция. И хотя многие из этих методов были доступны в различных сторонних библиотеках, таких как языки Guava и JVM, таких как Scala и Groovy, включение этих функций в ядро языка, несомненно, охватит более широкую аудиторию разработчиков и окажет наибольшее влияние на ландшафт развития.
Java 8, без сомнения, радикально меняет язык Java в лучшую сторону.
Ссылка: | Функциональная разжигание Java 8 от нашего партнера JCG Эндрю Гловера в блоге The Disco Blog . |