Я изучил следующий фрагмент:
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"));
Я вижу, что тело метода действительно вызывается в каждой строке. Что заставляет тело фильтра вызываться только один раз?
эй, приятель, я нашел этот код в проекте, над которым я работаю, возможно, он был скопирован тогда
И честно: рассмотрите возможность переписать свой вопрос вокруг темы минимальный воспроизводимый пример. Типа: какой смысл в том, чтобы метод test()
печатал что-то ... пошел, что распечатка нигде не отображается. И что еще хуже: наличие этого метода с именем test ... что немного сбивает с толку, учитывая, что вы также вызываете предикатные test()
методы).
Что вы имеете в виду, когда говорите: «Я знаю, что использование ConcurrentMap
— неправильный выбор в этом примере, и я должен использовать ConcurrentMap
…»? Это не имеет никакого смысла. Кроме того, t -> {return computed.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;}
излишне сложен. Можно просто написать t -> computed.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null
.
distinctByKey
возвращает экземпляр ОдинPredicate
, который кэширует ConcurrentHashMap
. Вы можете добиться почти того же самого, если замените создание Predicate
через лямбду, например, анонимным внутренним классом.
Когда вы вызываете .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"));
да, я так и думал, что это работает. но я столкнулся с этим фрагментом, и я сказал, что карта является экземпляром каждого хода, но я был неправ.
I thought that the distinctByKey method is called or interpreted in each iteration of the Stream i mean the Map being instance in each turn but it's not! my question is the body of the Predicate method call only one time? in the Stream iteration is this a assertion?
Нет. Потоки — это не волшебство, и они не нарушают стандартную семантику 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
, который он использует и модифицирует при выполнении своей работы.
Я думаю, вы взяли свой код из здесь, и при чтении его другого связанный ответ он, вероятно, должен проясниться.
distinctByKey()
называется только однажды. Но возвращаемый им предикат вызывается для элемента каждый.