I have a simple snippet as below. I referred this
List<Document> list = new LinkedList<Document>(); FindIterable<Document> itr = collection.find(findQuery) .forEach((Document doc) -> list.add(doc)); return list;
It compiles without any issues.<ol><li>I guess that we are telling compiler that
docis of type
Document. Why is it needed?</li> </ol>
But If I do the below, it throws ambiguous error. I referred this But couldn't relate and understand exactly.
Could anyone please explain why second statement is not working?</li> <li>
is there any better way of writing the first one [working one]?</li> </ol>
Java version: 1.8.0_231
import java.util.List; import java.util.Optional; import com.mongodb.client.FindIterable; import org.bson.Document;
FindIterable inherits two
com.mongodb.client.MongoIterable.forEach(Block<? super TResult>)</li> <li>
java.lang.Iterable.forEach(Consumer<? super T>)</li> </ul>
You could rewrite your paramter with either
Consumer<Document> consumer = documents::add; Block<Document> block = list::add;
And either will work. These too will work:
.forEach((Consumer<Document>) doc -> list.add(doc)) .forEach((Consumer<Document>) list::add);
However, when you call
forEach(doc -> list.add(doc)), the compiler is unable to pick which overload will determine the method reference's target type (because the expression is compatible with both in that context).
Now, I'm not 100% sure why
.forEach((Document doc) -> list.add(doc)) successfully selects/links the signature of
Consumer<Document> instead of the one with
Block<? super Document>, I'm surmizing it has to do with the generic bounds (but I'm still reading on this).
The choice for you should be easy because the
Block<? super Document> version is deprecated.
The problem is that
forEach is just a
Consumer, which has a single method
void accept(T element), and you're trying to return a value.
The "ambiguous" error in the first version was subject to other posts here.
You can do (I'd consider that more idiomatic)
return StreamSupport.stream(collection.find(findQuery).spliterator(), false) .collect(Collectors.toList());
As it is explicited in the lamba target typing<blockquote>
the Java compiler uses the target type of the context or situation in which the lambda expression was found. It follows that you can only use lambda expressions in situations in which the Java compiler can determine a target type</blockquote>
In your second snippet, the compiler cannot determine the target type of the lambda. Why?
Because when you use Method Reference the JRE infers the method type arguments, which in this case are ambiguous (e.g method reference works well only if there is non-ambiguous inference)
The JRE don't know if your using :
com.mongodb.client.MongoIterable.forEach(Block<? super TResult>)
java.lang.Iterable.forEach(Consumer<? super T>)
That's why your first snippet works. By casting your
Object. You get rid of this ambiguity.