Java8 - 显式类型如何匹配一种变体 - 而不是其他类型?
Java8 - How does explicit type matches one variant - not other type?
我有一个简单的片段如下。我提到了 this
List<Document> list = new LinkedList<Document>();
FindIterable<Document> itr = collection.find(findQuery)
.forEach((Document doc) -> list.add(doc));
return list;
编译没有任何问题。
- 我想我们是在告诉编译器
doc
是 Document
类型。 为什么需要它?
但是如果我执行下面的操作,它会抛出不明确的错误。我提到了 但无法准确联系和理解。
collection.find(findQuery).forEach(list::add);
谁能解释为什么第二个语句不起作用?
有没有更好的方法来写第一个[working one]?
Java版本:1.8.0_231
导入语句:
import java.util.List;
import java.util.Optional;
import com.mongodb.client.FindIterable;
import org.bson.Document;
问题是 forEach
只是一个 Consumer
,它只有一个方法 void accept(T element)
,而您正在尝试 return 一个值。
第一个版本中的 "ambiguous" 错误是 subject to other posts here。
你可以做到(我认为这更符合地道)
return StreamSupport.stream(collection.find(findQuery).spliterator(), false)
.collect(Collectors.toList());
FindIterable
继承两个forEach
方法:
您可以使用任一方法重写您的参数
Consumer<Document> consumer = documents::add;
Block<Document> block = list::add;
两者都行。这些也将起作用:
.forEach((Consumer<Document>) doc -> list.add(doc))
.forEach((Consumer<Document>) list::add);
但是,当您调用 forEach(list::add)
或 forEach(doc -> list.add(doc))
时,编译器无法选择哪个重载将确定方法引用的目标类型(因为表达式在该上下文中与两者兼容)。
现在,我不是 100% 确定为什么 .forEach((Document doc) -> list.add(doc))
成功 selects/links Consumer<Document>
的签名而不是带有 Block<? super Document>
的签名,我正在推测与通用边界有关(但我仍在阅读此内容)。
您的选择应该很容易,因为 Block<? super Document>
版本已弃用。
因为它在 lamba 中明确表示 target typing
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
在您的第二个代码段中,编译器无法确定 lambda 的目标类型。为什么?
因为当您使用 Method Reference 时,JRE 会推断出方法类型参数,在这种情况下是不明确的(例如,方法引用仅在没有明确的推断时才有效)
JRE 不知道您是否使用:
com.mongodb.client.MongoIterable.forEach(Block<? super TResult>)
或
java.lang.Iterable.forEach(Consumer<? super T>)
这就是您的第一个代码段有效的原因。通过投射你的 Object
。你摆脱了这种歧义。
我有一个简单的片段如下。我提到了 this
List<Document> list = new LinkedList<Document>();
FindIterable<Document> itr = collection.find(findQuery)
.forEach((Document doc) -> list.add(doc));
return list;
编译没有任何问题。
- 我想我们是在告诉编译器
doc
是Document
类型。 为什么需要它?
但是如果我执行下面的操作,它会抛出不明确的错误。我提到了
collection.find(findQuery).forEach(list::add);
谁能解释为什么第二个语句不起作用?
有没有更好的方法来写第一个[working one]?
Java版本:1.8.0_231
导入语句:
import java.util.List;
import java.util.Optional;
import com.mongodb.client.FindIterable;
import org.bson.Document;
问题是 forEach
只是一个 Consumer
,它只有一个方法 void accept(T element)
,而您正在尝试 return 一个值。
第一个版本中的 "ambiguous" 错误是 subject to other posts here。
你可以做到(我认为这更符合地道)
return StreamSupport.stream(collection.find(findQuery).spliterator(), false)
.collect(Collectors.toList());
FindIterable
继承两个forEach
方法:
您可以使用任一方法重写您的参数
Consumer<Document> consumer = documents::add;
Block<Document> block = list::add;
两者都行。这些也将起作用:
.forEach((Consumer<Document>) doc -> list.add(doc))
.forEach((Consumer<Document>) list::add);
但是,当您调用 forEach(list::add)
或 forEach(doc -> list.add(doc))
时,编译器无法选择哪个重载将确定方法引用的目标类型(因为表达式在该上下文中与两者兼容)。
现在,我不是 100% 确定为什么 .forEach((Document doc) -> list.add(doc))
成功 selects/links Consumer<Document>
的签名而不是带有 Block<? super Document>
的签名,我正在推测与通用边界有关(但我仍在阅读此内容)。
您的选择应该很容易,因为 Block<? super Document>
版本已弃用。
因为它在 lamba 中明确表示 target typing
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
在您的第二个代码段中,编译器无法确定 lambda 的目标类型。为什么?
因为当您使用 Method Reference 时,JRE 会推断出方法类型参数,在这种情况下是不明确的(例如,方法引用仅在没有明确的推断时才有效)
JRE 不知道您是否使用:
com.mongodb.client.MongoIterable.forEach(Block<? super TResult>)
或
java.lang.Iterable.forEach(Consumer<? super T>)
这就是您的第一个代码段有效的原因。通过投射你的 Object
。你摆脱了这种歧义。