[JAVA-2010] Support the use of Java 8 lambdas and MongoIterable.forEach() Created: 07/Oct/15  Updated: 22/Oct/18  Resolved: 22/Oct/18

Status: Closed
Project: Java Driver
Component/s: API
Affects Version/s: None
Fix Version/s: 3.9.0

Type: New Feature Priority: Major - P3
Reporter: Andre de Frere Assignee: Jeffrey Yemin
Resolution: Done Votes: 3
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
related to JAVA-3046 Deprecate MongoIterable#forEach Closed

 Description   

The drivers forEach method makes the use of lambda forEach ambiguous:

            collection.find(filterBson).forEach(doc -> {
                // do something here
            });

results in the following compile error

   "The method forEach(Block<? super Document>) is ambiguous for the type FindIterable<Document>"

Update

JAVA-3046 addresses the compiler error described above by deprecating MongoIterable#forEach(Block<T> block) so that it can be removed in the next major release. Once it's gone the compiler error will no longer occur. Under this ticket, we address the cursor leak that can occur when using Iterable#forEach(Consumer<T> consumer by overriding that method in every MongoIterable implementation to properly close the MongoCursor even when an exception occurs during the internal iteration of the method.



 Comments   
Comment by Githook User [ 22/Oct/18 ]

Author:

{'name': 'Jeff Yemin', 'email': 'jeff.yemin@10gen.com', 'username': 'jyemin'}

Message: Override forEach(Consumer<T>) in MongoIterable implementations

The implementations of this method now all properly close the
MongoCursor<T> so that cursors are not leaked when the forEach
method doesn't complete normally.

JAVA-2010
Branch: master
https://github.com/mongodb/mongo-java-driver/commit/ef1c166c8efb940febccd331c3348c29191560ec

Comment by Liu Bo [ 20/Jan/16 ]

Hi Jeff,

my first thought is exactly the same as yours, but experiment passed, and this confuses me. Here is the full code that can compile and run:
MongoClient mongoClient;
MongoDatabase db;
mongoClient = new MongoClient(host);
db = mongoClient.getDatabase(dbName);
FindIterable<Document> it = db.getCollection("data").find(queryDoc);
it.forEach((Document document) -> System.out.println(document.get("_id")));

My environment:
OS: max os 10, JDK: 1.8U66, mongo driver:3.2.1, mongo server: 3.0.4

Comment by Jeffrey Yemin [ 19/Jan/16 ]

The first (give doc a type) will not work, as it's still an ambiguous method call. But either of the casts will, as that disambiguates the call.

Comment by Liu Bo [ 19/Jan/16 ]

I think this breaks the target typing of java lambda expression.
ref: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#target-typing

I've also met this issue and here is what I've found after trying around:
let 'it' be a FindIterable:
FindIterable<Document> it = db.getCollection(tableName).find(queryDoc);
Both of these three ways can work
give doc a type:
it.forEach((Document doc) -> ret.add(converter.convert(doc)));
casting:
it.forEach((Block<Document>) doc -> ret.add(converter.convert(doc)));
it.forEach((Consumer<Document>) doc -> ret.add(converter.convert(doc)));

The first one seems using java Iterable's foreach(not the one from MongoIterable), I'm quite new to lambda, hope someone can explain this behavior. My only guess is java native interfaces comes in a higher priority somehow.

Generated at Thu Feb 08 08:56:06 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.