Статьи

Сравнение Java-лямбда-потоков и Groovy Clouses

В этом блоге мы рассмотрим некоторые общеизвестные операции над структурой данных List и проведем некоторое сравнение между Java 8/9 и синтаксисом Groovy.

Итак, во-первых, структура данных. Это просто игрок в регби, у которого есть имя и рейтинг.

Ява

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class RugbyPlayer {
    private String name;
    private Integer rating;
     
    RugbyPlayer(String name, Integer rating) {
        this.name = name;
        this.rating = rating;
    }
 
    public String toString() {
        return name + "," + rating;
    }
         
    public String getName() {
        return name;
    }
         
    public Integer getRating() {
        return rating;
    }
}
 
//...
//...
List<RugbyPlayer> players = Arrays.asList(
    new RugbyPlayer("Tadgh Furlong", 9),
    new RugbyPlayer("Bundee AKi", 7),
    new RugbyPlayer("Rory Best", 8),
    new RugbyPlayer("Jacob StockDale", 8)
);

Groovy

01
02
03
04
05
06
07
08
09
10
11
12
13
@ToString
class RugbyPlayer {
    String name
    Integer rating
}
//...
//...
List<RugbyPlayer> players = [
    new RugbyPlayer(name: "Tadgh Furlong", rating: 9),
    new RugbyPlayer(name: "Bundee AKi", rating: 7),
    new RugbyPlayer(name: "Rory Best", rating: 8),
    new RugbyPlayer(name: "Jacob StockDale", rating: 8)
]

Найти конкретную запись

Ява

1
2
3
4
5
6
// Find Tadgh Furlong
Optional<RugbyPlayer> result = players.stream()
    .filter(player -> player.getName().indexOf("Tadgh")  >= 0)
    .findFirst();     
String outputMessage = result.isPresent() ? result.get().toString() : "not found";
System.out.println(outputMessage);

Groovy

1
println players.find{it.name.indexOf("Tadgh") >= 0}

Комментарии

  • У лямбды Java есть только один параметр в плеере. Это не должно быть напечатано, так как его тип может быть выведен. Примечание: эта лямбда использует только один параметр. Если бы в списке параметров было два параметра, вокруг списка параметров потребовалась бы скобка.
  • В Java поток должен быть сначала создан из списка. Затем используется лямбда перед выполнением функции, которая возвращает необязательный
  • Лямбда-определение не нуждается в выражении возврата. Ему также не нужны {} фигурные скобки или одна из этих точек с запятой для завершения оператора Java. Однако вы можете использовать {}, если хотите, и если хотите, вы должны включить; и ответное заявление. Примечание: если у вас лямбда больше одной строки, у вас нет выбора, вы должны использовать {}. Рекомендуется использовать короткую лямбду и одну строчку.
  • Java 8 поддерживает плавные API для конвейерных потоковых операций. Это также поддерживается в операциях Groovy Collection.
  • В Java указана переменная проигрывателя для лямбды. Закрытие Groovy не нужно указывать переменную. Он может просто использовать «оно», которое является неявной ссылкой на параметр (аналогично _ в Scala).
  • API фильтра Java принимает параметры типа Predicate . Функциональный интерфейс означает: может использоваться в качестве цели назначения для лямбда-выражения или ссылки на метод. Предикат, это тип функционального интерфейса. Это один абстрактный метод: булев тест (T t). В этом случае в лямде игрок соответствует t. Определение тела должно иметь значение true или false, в нашем случае player.getName (). IndexOf («Tadgh») всегда будет иметь значение true или false. True соответствует совпадению.
  • Java 8 имеет другие типы функциональных интерфейсов:
    • Функция — принимает один аргумент и возвращает результат
    • Потребитель — принимает один аргумент и не возвращает результата (представляет побочный эффект)
    • Поставщик — не принимает аргументов и возвращает результат
    • Предикат — он принимает один аргумент и возвращает логическое значение
    • BiFunction — принимает два аргумента и возвращает результат
    • BinaryOperator — это аналог BiFunction , принимающий два аргумента и возвращающий результат. Два аргумента и результат имеют одинаковые типы
    • UnaryOperator — это похоже на функцию , принимая один аргумент и возвращая результат того же типа
  • Java 8 может определить тип входных параметров лямбды. Обратите внимание, что если вам нужно указать тип параметра, объявление должно быть в скобках, что добавляет дополнительную детализацию.
  • Groovy может печатать напрямую. Не требуется System.out и не требуется последующих скобок.
  • Как и Java, Groovy не нуждается в выражении return. Однако это не только для замыканий, в Groovy это распространяется на все методы. Все, что оценивается как последняя строка, автоматически возвращается.
  • Groovy не имеет понятия о функциональном интерфейсе. Это может означать, что если вы забудете убедиться, что ваше последнее выражение является подходящим логическим выражением, вы получите неожиданные результаты и ошибки во время выполнения.
  • Оператор стрелки используется в Groovy и Java для эффективного обозначения одного и того же — отделения списка параметров от определения тела. В Groovy это нужно только вам, вам нужно объявить параметры (по умолчанию это не достаточно). Примечание: в Scala используется =>.

Найти конкретные записи

Ява

1
2
3
4
5
// Find all players with a rating over 8
List<RugbyPlayer> ratedPlayers = players.stream()
    .filter(player -> player.getRating() >= 8)
    .collect(Collectors.toList());
ratedPlayers.forEach(System.out::println);

Groovy

1
println players.findAll{it.rating >= 8}

Комментарии

  • В Java-версии вызывается метод forEach для Iterable Object RatingPlayers. Этот метод принимает FunctionalInterface типа Consumer (см. Jdoc здесь ). Потребитель, метод функция, которая принимает входной параметр, но ничего не возвращает, это void.
  • System.out :: println — это ссылка на метод — новая функция в Java 8. Это синтаксический сахар для уменьшения многословия некоторых лямбд. По сути, это означает, что для каждого элемента в figurePlayers выполните System.out.println, передав текущий элемент в качестве параметра.
  • Опять меньше синтаксиса от Groovy. Функция может работать с коллекцией, нет необходимости создавать Stream.
  • Мы могли бы просто напечатать весь список в примере Java, но, черт возьми, я хотел показать демо forEach и ссылку на метод.

Карта от типа объекта к другому

Ява

1
2
3
4
5
// Map the Rugby players to just names.
// Note, the way we convert the list to a stream and then back again to a to a list using the collect API.
System.out.println("Names only...");
List<String> playerNames = players.stream().map(player -> player.getName()).collect(Collectors.toList());
playerNames.forEach(System.out::println);

Groovy

1
println players.collect{it.name}

Комментарии

  • Поток должен быть создан в первую очередь перед выполнением лямбды. Затем метод Stream () вызывается в потоке — это необходимо для преобразования его обратно в список. Это делает код более многословным.

Выполнить расчет сокращения

Ява

1
2
3
4
System.out.println("Max player rating only...");
Optional<Integer> maxRatingOptional = players.stream().map(RugbyPlayer::getRating).reduce(Integer::max);
String maxRating = maxRatingOptional.isPresent() ? maxRatingOptional.get().toString() : "No max";
System.out.println("Max rating=" + maxRating);

Groovy

1
2
3
4
def here = players.inject(null){
    max, it ->
        it.rating > max?.rating ? it : max
}

Комментарии

  1. Нулевой безопасный оператор используется в закрытии инъекции Groovy — так что первое сравнение будет работать

Резюме

  1. Groovy все еще гораздо более лаконичен
  2. Однако некоторые операции в Java выполняются лениво. Например, map (), filter (), которые считаются промежуточными. Они не будут выполняться, если в потоке не вызывается терминальная функция, например, forEach, collect, redu. Это может сделать код более многословным в случаях, но это также означает, что он может быть более производительным.
  3. Groovy также предлагает некоторые ленивые функции.

Полный код Java здесь . Полный Groovy код здесь .

Опубликовано на Java Code Geeks с разрешения Алекса Стейвли, партнера нашей программы JCG . Посмотрите оригинальную статью здесь: Java Lambda Streams и Groovy Clouses Сравнения

Мнения, высказанные участниками Java Code Geeks, являются их собственными.