Java 8 имеет лямбды , которые похожи на конструкцию, которую Groovy уже некоторое время использует: замыкания .
В Groovy мы уже могли сделать это:
1
2
3
|
def list = [ 'a' , 'b' , 'c' ] print list.collect { it.toUpperCase() } // [A, B, C] |
где { it.toUpperCase() }
— это закрытие.
В Java 8 мы можем достичь той же функциональности теперь в сжатой форме.
1
|
list.stream().map( s -> s.toUpperCase() ) |
Хотя вы могли бы поспорить, что при правильном использовании нового Stream API, массовых операций и ссылок на методы, по крайней мере, теперь смысл кода передается более четко — многословность Java все еще может вызывать воспаление.
Вот еще несколько примеров.
Некоторые заводные животные
01
02
03
04
05
06
07
08
09
10
11
|
class Animal { String name BigDecimal price String farmer String toString() { name } } def animals = [] animals << new Animal(name: "Buttercup" , price: 2 , farmer: "john" ) animals << new Animal(name: "Carmella" , price: 5 , farmer: "dick" ) animals << new Animal(name: "Cinnamon" , price: 2 , farmer: "dick" ) |
Пример 1: Суммирование общей стоимости всех животных
Groovy
1
2
|
assert 9 == animals.sum { it.price } // or animals.price.sum() |
Что Groovy вы видите здесь:
-
sum
можно вызвать в List и, необязательно, передать замыкание, определяющее свойство «it» — итерируемого животного — для сортировки. - или
sum
можно вызывать в List без каких-либо аргументов, что эквивалентно вызову метода « plus » для всех элементов в коллекции.
Java 8
1
2
3
4
5
6
|
Optional<BigDecimal> sum = animals. stream(). map(Animal::getPrice). reduce((l, r) -> l.add(r)); assert BigDecimal.valueOf( 9 ) == sum.get(); |
Какую Java вы видите здесь:
- С помощью метода Stream API
stream
мы можем создать конвейер операций, таких какmap
иreduce
- Аргументом операции
map
является ссылка на методgetPrice()
текущего итерированного животного. Мы могли бы также заменить эту часть выражениемa -> a.getPrice()
-
reduce
— это общая операция сокращения (также называемая сгибанием ), в которой суммируютсяBigDecimals
значения цен. Это также дает намOptional
с общей суммой. - Кстати, если бы мы использовали удвоение цены — что мы не делаем, потому что я хочу привести хороший пример — мы могли бы использовать существующий DoubleStream с
sum()
на нем, например1double
sum = animals.stream().mapToDouble(Animal::getPrice).sum();
Пример 2: Группировка всех животных по фермеру
Groovy
1
2
|
def animalsByFarmer = animals.groupBy { it.farmer } // [john:[Buttercup], dick:[Carmella, Cinnamon]] |
Java 8
1
2
3
4
5
6
|
Map<String, List<Animal>> animalsByFarmer = animals .stream() .collect( Collectors.groupingBy(Animal::getFarmer)); // {dick=[Carmella, Cinnamon], john=[Buttercup]} |
Пример 3: Суммирование общей стоимости всех животных, сгруппированных по фермеру
Groovy
1
2
3
4
5
|
def totalPriceByFarmer = animals .groupBy { it.farmer } .collectEntries { k, v -> [k, v.price.sum()] } // [john:2, dick:7] |
Что Groovy вы видите здесь:
-
collectEntries
перебирает карту «groupBy», преобразуя каждую запись карты, используя закрытиеk, v -> ...
возвращая карту преобразованных записей.v.price
самом делеv.price
— это список цен (на одного фермера), например, в примере 1, по которому мы можем вызватьsum()
.
Java 8
01
02
03
04
05
06
07
08
09
10
11
|
Map<String, BigDecimal> totalPriceByFarmer = animals .stream() .collect( Collectors.groupingBy( Animal::getFarmer, Collectors.reducing( BigDecimal.ZERO, Animal::getPrice, BigDecimal::add))); // {dick=7, john=2} |
Этот код Java снова дает те же результаты. Поскольку IDE, по крайней мере, Eclipse, не форматируют это должным образом, вам придется самим создавать отступы для такого рода конструкций для удобства чтения.
Ссылка: | Java 8 Lambdas vs Groovy Компактность замыканий: группировка и подведение итогов от нашего партнера по JCG Теда Винке в блоге Теда Винке в блоге. |