Как использовать ссылку на метод в Java 8 для слияния карт? - PullRequest
0 голосов
/ 20 сентября 2018

У меня есть следующие 2 формы вызова операции сбора, оба возвращают один и тот же результат, но я все еще не могу полностью зависеть от ссылок на методы и нуждаюсь в лямбда-выражении.

<R> R collect(Supplier<R> supplier,
          BiConsumer<R,? super T> accumulator,
          BiConsumer<R,R> combiner)

Для этого рассмотрим следующий поток, состоящий из 100 случайных чисел

List<Double> dataList = new Random().doubles().limit(100).boxed()
            .collect(Collectors.toList());

1) В следующем примере используются чистые лямбды

Map<Boolean, Integer> partition = dataList.stream()
            .collect(() -> new ConcurrentHashMap<Boolean, Integer>(),
(map, x) ->
{
    map.merge(x < 0.5 ? Boolean.TRUE : Boolean.FALSE, 1, Integer::sum);
}, (map, map2) ->
{
    map2.putAll(map);
});

2) Следующие попыткииспользовать ссылки на методы, но для 2-го аргумента по-прежнему требуется лямбда

Map<Boolean, Integer> partition2 = dataList.stream()
            .collect(ConcurrentHashMap<Boolean, Integer>::new, 
(map, x) ->
{
    map.merge(x < 0.5 ? Boolean.TRUE : Boolean.FALSE, 1, Integer::sum);
}, Map::putAll);

Как переписать 2-й аргумент метода сбора в java 8, чтобы использовать ссылку на метод вместо лямбда-выражения в этом примере?

System.out.println(partition.toString());
System.out.println(partition2.toString());
{false=55, true=45}
{false=55, true=45}

1 Ответ

0 голосов
/ 21 сентября 2018

Ссылка на метод - это удобный инструмент, если у вас есть существующий метод, который делает именно то, что задумано.Если вам нужны адаптации или дополнительные операции, не существует специального синтаксиса для ссылок на методы, чтобы поддержать это, за исключением случаев, когда вы рассматриваете лямбда-выражения в качестве этого синтаксиса.

Конечно, вы можете создать новый метод в своем классевыполняя нужную вещь и создавая ссылку на метод, и это правильный путь, когда повышается сложность кода, так как тогда он получит осмысленное имя и станет тестируемым.Но для простых фрагментов кода вы можете использовать лямбда-выражения, которые являются просто более простым синтаксисом для того же результата.Технически нет никакой разницы, за исключением того, что сгенерированный компилятором метод, содержащий тело лямбда-выражения, будет помечен как «синтетический».

В вашем примере вы даже не можете использовать Map::putAll в качестве функции слияния, так какэто переписало бы все существующие отображения первой карты вместо слияния значений.

Правильная реализация выглядела бы как

Map<Boolean, Integer> partition2 = dataList.stream()
    .collect(HashMap::new, 
             (map, x) -> map.merge(x < 0.5, 1, Integer::sum),
             (m1, m2) -> m2.forEach((k, v) -> m1.merge(k, v, Integer::sum)));

, но вам не нужно реализовывать ее самостоятельно.В классе Collectors уже предлагаются соответствующие встроенные коллекторы:

Map<Boolean, Long> partition2 = dataList.stream()
    .collect(Collectors.partitioningBy(x -> x < 0.5, Collectors.counting()));
...