I do have a problem regarding the behaviour of jdk11 (and later) in terms of stream and the collect method.
I do want to get the values of a parameterized container streaming the resource and collect the values in the end with .collect(Collectors.toSet())
.
When i compile my code with the jdk8
it works perfectly fine. But as we also have to support jdk11
, i ran the compilation and it fails because Error:(136, 17) java: incompatible types: java.lang.Object cannot be converted to java.util.Set<org.bson.types.ObjectId>
(same applies for openJdk11)
Imagine the following situation. I have a class which is basically a data container. This container can hold single values or lists of values.
Im some parts of my application, i do have lists of this container class (which can contain lists as values as well) and i do want to stream through the lists to get all the values in the containers as a flat list.
For this example i chose to use Lists of objectIds.
// preparation
List<ObjectId> innerObjects = new ArrayList<>();
innerObjects.add(new ObjectId());
innerObjects.add(new ObjectId());
List<Diamond<Object>> diamonds = new ArrayList<>();
diamonds.add(new Diamond<Object>().value(innerObjects));
public static class Diamond<T> {
private T value;
public Diamond<T> value(T value) {
this.value = value;
return this;
}
public T getValue() {
return this.value;
}
}
Set<ObjectId> objectIdSet = diamonds
.stream()
.filter(diamond -> diamond.getValue() instanceof List)
.map(Diamond::getValue)
.map(List.class::cast)
.flatMap(Collection::stream)
.map(ObjectId.class::cast)
.collect(Collectors.toSet());
Stream<ObjectId> idStream = diamonds
.stream()
.filter(diamond -> diamond.getValue() instanceof List)
.map(Diamond::getValue)
.map(List.class::cast)
.flatMap(Collection::stream)
.map(ObjectId.class::cast);
Set<ObjectId> objectIds = idStream.collect(Collectors.toSet());
But i do not get why this is wrong.
<deleted as of to be inacurate>
EDIT: I changed the set up code to reflect my current issue a bit more.
Anyone an idea what i am doing wrong?
There are several reasons why one should upgrade from Java 8 to Java 11. Applications written in Java 9, 10, and 11 are significantly faster and more secure than previous versions of the language. ZGC and Epsilon garbage collectors have improved Garbage Collection.
There are a lot of benefits to using streams in Java, such as the ability to write functions at a more abstract level which can reduce code bugs, compact functions into fewer and more readable lines of code, and the ease they offer for parallelization.
Java 8 introduced streams. Not to be confused with input/output streams, these Java 8+ streams can also process data that goes through them. It was hailed as a great new feature that allowed coders to write algorithms in a more readable (and therefore more maintainable) way.
This could be related to JDK-8199234 Code compiles in java8 but not in java9 : "incompatible types: java.lang.Object cannot be converted ..." which was resolved as "Not an Issue" and affects Java 9+.
The root cause is that in your example map(List.class::cast)
performs a cast to a raw type List
messing up the information about generics. You are trying to rectify this later with map(ObjectId.class::cast)
but it's not a good idea. Streams are heavily based on the generics and you should avoid manual casts and let the compiler infer the types.
Your code can be simplified to below, which works on Java 11:
Set<ObjectId> objectIdSet = diamonds.stream()
.filter(Objects::nonNull) // potentially redundant but instanceof was doing it
.map(Diamond::getValue)
.flatMap(Collection::stream)
.collect(Collectors.toSet());
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