Предикаты Java 8, использующие тела методов, вызываются только один раз - PullRequest
2 голосов
/ 27 мая 2019

Я изучил следующий фрагмент:

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Map<Object, Boolean> computed = new ConcurrentHashMap<>();/*IS THIS LINE CALLED ONCE ON STREAM->FILTER NOT MATTER HOW LONG THE STREAM IS*/
    return t -> {return computed.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;};
}

private void test(){
    final long d = Stream.of("JOHN","STEPHEN","ORTIZ","RONDON")
            .filter(distinctByKey(Function.identity()))
            .count();
    System.out.println("d = " + d);
}

Этот код не мой. Я знаю, что использование ConcurrentMap не является правильным выбором в этом примере, и я должен использовать ConcurrentMap вместо Map в этом случае, но сейчас это не моя проблема.

Я думал, что метод distinctByKey вызывается или интерпретируется в каждой итерации Stream. Я имею в виду, что Map создается в каждом ходу, но это не так!

Тело Predicate метода вызывается только один раз?

В итерации Stream это утверждение?

Потому что, когда я попробую следующий код:

final Function<String,Integer>a = (name)->name.length();
System.out.println(distinctByKey(a).test("JOHN"));
System.out.println(distinctByKey(a).test("STEPHEN"));
System.out.println(distinctByKey(a).test("ORTIZ"));
System.out.println(distinctByKey(a).test("RONDON"));

Я вижу, что тело метода действительно вызывается в каждой строке. Что заставляет тело фильтра вызываться только один раз?

Ответы [ 3 ]

4 голосов
/ 27 мая 2019

Когда вы вызываете .filter(distinctByKey(Function.identity())), аргумент, переданный filter(), оценивается. Это единственный раз, когда distinctByKey(Function.identity()) выполняется и возвращает экземпляр Predicate<String>.

То, что Predicate затем оценивается (то есть выполняется test() метод) несколько раз, каждый раз для другого элемента Stream.

Чтобы ваш последний фрагмент работал подобно конвейеру Stream, он должен выглядеть следующим образом:

final Function<String,Integer> a = (name)->name.length();
Predicate<String> pred = distinctByKey(a);
System.out.println(pred.test("JOHN"));
System.out.println(pred.test("STEPHEN"));
System.out.println(pred.test("ORTIZ"));
System.out.println(pred.test("RONDON"));
4 голосов
/ 27 мая 2019

Я думал, что метод DifferentByKey вызывается или интерпретируется в каждая итерация потока я имею в виду, что карта является экземпляром в каждом включай но это не так! мой вопрос - тело метода Predicate звонить только один раз? в итерации потока это утверждение?

Нет. Потоки не волшебны, и они не опровергают стандартную семантику Java. Рассмотрим представленный код:

    final long d = Stream.of("JOHN","STEPHEN","ORTIZ","RONDON")
            .filter(distinctByKey(Function.identity()))
            .count();

Извлечение определенных типов и методов из картинки, которая имеет такую ​​общую форму:

long x = A.b(y).c(z).d(w);

Нет оснований ожидать, что какой-либо из a(), b() или c() будет вызываться более одного раза в этой цепочке, или что их аргументы оцениваются более одного раза каждый. На это не влияют некоторые типы: Stream.

В вашем случае вместо этого происходит то, что Predicate, возвращаемый (единственный вызов) вашим distinctByKey() методом, используется более одного раза, поскольку поток, в который он встроен, обрабатывается. Predicate содержит ссылку на Map, которую он использует и изменяет при выполнении своей работы.

4 голосов
/ 27 мая 2019

distinctByKey возвращает один экземпляр Predicate, который кэширует ConcurrentHashMap.Вы можете достичь почти того же самого, если замените создание Predicate через лямбду, например, на анонимный внутренний класс.

...