Java 22: изменения в Stream API (с плохим API)
19 марта выйдет Java 22. Там появится интересная превью фича Stream Gatherers. Коротко расскажу, что это, зачем нужно, и что с ней не так.
Начнём. Код со Stream API делится на 3 части:
▫️ источник данных
▫️ промежуточные операции: map, filter, flatMap
▫️ терминальная операция: collect, count, findAny
Промежуточных операций немного, но они легко покрывают большую часть задач.
Иногда их недостаточно. Например, хочется сделать distinct по какому-то признаку и дальше работать с исходными объектами:
Но это невозможно, distinct работает только по equals. В итоге надо либо извращаться, либо переписывать на for.
В Java 22 в Stream API появится универсальный метод gather. Туда можно передать логику преобразований с любыми отношениями - 1:1, 1:N, N:1, N:N. Синтаксис сложный, но круто, что такая возможность появилась.
Второе нововведение. Для collect есть готовые статические методы в классе Collectors, а для gather появится Gatherers с новыми методами. Самое полезное — два метода по работе с окнами:
🪟 windowFixed — поделить стрим на подмножества заданного размера
🪟 windowSliding — подмножества с пересечением одного элемента
Что не так c методом gather?
1️⃣ Многословность
Та же ситуация, что и с collect. Чтобы разбить список на окна, придётся написать
Даже со статическим импортом выглядит не очень. Хочется писать без лишних слов:
Да, исходный код Stream API сложный, и его тяжело расширять. Да, через статические методы реализация получится проще. Но не вижу ничего невозможного, чтобы сделать новые методы лаконичными, без приставки "
2️⃣ Странные новые методы
Начнём с оконных. windowSliding делает пересечение только по одному элементу. Зачем нужно это ограничение — непонятно. Так же непонятно, зачем делать два отдельных метода windowFixed и windowSliding.
За образец можно взять Kotlin:
Первый параметр задаёт размер окна, второй — шаг, с которым идём по списку. Удобно и понятно.
Ещё в Gatherers появятся три странных метода: fold, mapConcurrent и scan. С первого взгляда непонятно, зачем они нужны, очень уж специфичны.
В целом криминала в gather/Gatherers нет, жить можно. Но важный навык разработчика — замечать слабые места в своих и чужих решениях. Этот навык нужно развивать, для этого и нужен этот пост:)
Что ещё почитать:
🔥 Серия постов про коллекторы. Там же я рассказала, почему в стримах используется отдельный метод collect, а не просто toList()
🔥 Новые методы Stream API в Java 16
🔥 Критикую метод HashMap в Java 20. Хотя сам метод маленький, он показывает серьёзную ошибку проектирования API
19 марта выйдет Java 22. Там появится интересная превью фича Stream Gatherers. Коротко расскажу, что это, зачем нужно, и что с ней не так.
Начнём. Код со Stream API делится на 3 части:
▫️ источник данных
▫️ промежуточные операции: map, filter, flatMap
▫️ терминальная операция: collect, count, findAny
Промежуточных операций немного, но они легко покрывают большую часть задач.
Иногда их недостаточно. Например, хочется сделать distinct по какому-то признаку и дальше работать с исходными объектами:
clients.stream()
.distinct(Client::getBonusType)
.map(Client::getId).forEach(…)
Но это невозможно, distinct работает только по equals. В итоге надо либо извращаться, либо переписывать на for.
В Java 22 в Stream API появится универсальный метод gather. Туда можно передать логику преобразований с любыми отношениями - 1:1, 1:N, N:1, N:N. Синтаксис сложный, но круто, что такая возможность появилась.
Второе нововведение. Для collect есть готовые статические методы в классе Collectors, а для gather появится Gatherers с новыми методами. Самое полезное — два метода по работе с окнами:
🪟 windowFixed — поделить стрим на подмножества заданного размера
[1,2,3,4,5,6] → windowFixed(3) → [1,2,3], [4,5,6]
🪟 windowSliding — подмножества с пересечением одного элемента
[1,2,3,4,5,6,7] → windowSliding(3) → [1,2,3], [3,4,5], [5,6,7]
Что не так c методом gather?
1️⃣ Многословность
Та же ситуация, что и с collect. Чтобы разбить список на окна, придётся написать
list.stream()
.gather(Gatherers.windowFixed(2))
.collect(Collectors.toList())
Даже со статическим импортом выглядит не очень. Хочется писать без лишних слов:
list.stream()
.windowFixed(2)
.toList()
Да, исходный код Stream API сложный, и его тяжело расширять. Да, через статические методы реализация получится проще. Но не вижу ничего невозможного, чтобы сделать новые методы лаконичными, без приставки "
gather(Gatherers
"2️⃣ Странные новые методы
Начнём с оконных. windowSliding делает пересечение только по одному элементу. Зачем нужно это ограничение — непонятно. Так же непонятно, зачем делать два отдельных метода windowFixed и windowSliding.
За образец можно взять Kotlin:
list.windowed(5,2)
Первый параметр задаёт размер окна, второй — шаг, с которым идём по списку. Удобно и понятно.
Ещё в Gatherers появятся три странных метода: fold, mapConcurrent и scan. С первого взгляда непонятно, зачем они нужны, очень уж специфичны.
В целом криминала в gather/Gatherers нет, жить можно. Но важный навык разработчика — замечать слабые места в своих и чужих решениях. Этот навык нужно развивать, для этого и нужен этот пост:)
Что ещё почитать:
🔥 Серия постов про коллекторы. Там же я рассказала, почему в стримах используется отдельный метод collect, а не просто toList()
🔥 Новые методы Stream API в Java 16
🔥 Критикую метод HashMap в Java 20. Хотя сам метод маленький, он показывает серьёзную ошибку проектирования API