I am looking at this code and trying to understand the following piece of code.
public static <T> Predicate<T> distinctByKey(Function<? super T,Object> keyExtractor) {
Map<Object,Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
BigDecimal totalShare = orders.stream()
.filter(distinctByKey(o -> o.getCompany().getId()))
.map(Order::getShare)
.reduce(BigDecimal.ZERO, BigDecimal::add);
My question here is everytime distinctByKey will be called and resulting new ConcurrentHashMap. how it is maintaining the state using new ConcurrentHashMap<>(); ?
What is the Predicate in Java 8? In Java 8 Predicate interface is defined in the java.util.function package. It contains one abstract method that is called test () method. This interface provides functionality to test/evaluate any condition. This interface is used in a lambda expression and method reference to evaluate the condition.
In Java 8 Predicate interface is defined in the java.util.function package. It contains one abstract method that is called test () method. This interface provides functionality to test/evaluate any condition. This interface is used in a lambda expression and method reference to evaluate the condition. Where T, The type of input of Predicate.
You don't need to create a new class to create a Predicate. This is because Java 8 added a lambda syntax, which you can think of as a shorthand for anonymous inner classes implementing an interface with only one method. Here is an example:
The filter method of Stream takes Predicate as an argument. 1. By use of Java Predicate, you can move the conditional code in one place. 2. It improves code maintenance because if you want to make any change in condition then you have to make it in a central place.
Since this is a capturing lambda, indeed a new Predicate
instance will be returned all the time on each call to distinctByKey
; but this will happen per entire stream, not per each individual element.
If you are willing to run your example with:
Djdk.internal.lambda.dumpProxyClasses=/Your/Path/Here
you would see that a class
is generated for your the implementation of the Predicate
. Because this is a stateful lambda - it captures the CHM
and Function
, it will have a private
constructor and a static factory method
that returns an instance.
Each call of distinctByKey
will produce a different instance, but that instance will be reused for each element of the Stream. Things might be a bit more obvious if you run this example:
public static <T> Predicate<T> distinctByKey(Function<? super T,Object> keyExtractor) {
Map<Object,Boolean> seen = new ConcurrentHashMap<>();
Predicate<T> predicate = t -> {
Object obj = keyExtractor.apply(t);
System.out.println("stream element : " + obj);
return seen.putIfAbsent(obj, Boolean.TRUE) == null;
};
System.out.println("Predicate with hash :" + predicate.hashCode());
return predicate;
}
@Getter
@AllArgsConstructor
static class User {
private final String name;
}
public static void main(String[] args) {
Stream.of(new User("a"), new User("b"))
.filter(distinctByKey(User::getName))
.collect(Collectors.toList());
}
This will output:
Predicate with hash :1259475182
stream element : a
stream element : b
A single Predicate
for both elements of the Stream.
If you add another filter
:
Stream.of(new User("a"), new User("b"))
.filter(distinctByKey(User::getName))
.filter(distinctByKey(User::getName))
.collect(Collectors.toList());
There will be two Predicate
s:
Predicate with hash :1259475182
Predicate with hash :1072591677
stream element : a
stream element : a
stream element : b
stream element : b
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With