java - Stream.findFirst 与 Optional.of 不同?
问题描述
假设我有两个类和两个方法:
class Scratch {
private class A{}
private class B extends A{}
public Optional<A> getItems(List<String> items){
return items.stream()
.map(s -> new B())
.findFirst();
}
public Optional<A> getItems2(List<String> items){
return Optional.of(
items.stream()
.map(s -> new B())
.findFirst()
.get()
);
}
}
为什么getItems2
编译时getItems
会给出编译器错误
incompatible types: java.util.Optional<Scratch.B> cannot be converted to java.util.Optional<Scratch.A>
因此,当我返回get
的值并用编译器再次包装它时,它会识别继承,但如果我直接使用.Optional
findFirst
Optional.of
findFirst
解决方案
AnOptional<B>
不是 的子类型Optional<A>
。与其他编程语言不同,Java 的泛型类型系统不知道“只读类型”或“输出类型参数”,因此它不理解Optional<B>
只提供一个实例B
并且可以在需要的地方工作Optional<A>
。
当我们写一个像
Optional<A> o = Optional.of(new B());
Java的类型推断使用目标类型来确定我们想要的
Optional<A> o = Optional.<A>of(new B());
这是有效的,new B()
可以在需要实例的地方A
使用。
这同样适用于
return Optional.of(
items.stream()
.map(s -> new B())
.findFirst()
.get()
);
其中方法声明的返回类型用于推断Optional.of
调用的类型参数并传递 的结果,其中需要get()
的实例是有效的。B
A
不幸的是,这种目标类型推断不适用于链式调用,因此对于
return items.stream()
.map(s -> new B())
.findFirst();
它不用于map
通话。因此对于map
调用,类型推断使用的类型,new B()
其结果类型将是Stream<B>
. 第二个问题是它findFirst()
不是泛型的,在 a 上调用它Stream<T>
总是会产生 a Optional<T>
(并且 Java 的泛型不允许声明像 那样的类型变量<R super T>
,因此在这里甚至不可能产生Optional<R>
具有所需类型的 a )。
→ 解决方案是为map
调用提供显式类型:
public Optional<A> getItems(List<String> items){
return items.stream()
.<A>map(s -> new B())
.findFirst();
}
如前所述,仅出于完整性考虑,findFirst()
它不是通用的,因此不能使用目标类型。链接允许类型更改的通用方法也可以解决问题:
public Optional<A> getItems(List<String> items){
return items.stream()
.map(s -> new B())
.findFirst()
.map(Function.identity());
}
但我建议使用为map
调用提供显式类型的解决方案。
推荐阅读
- security - 我可以利用外部访问管理系统在 Amazon Elastic Search 中使用细粒度访问控制吗?
- c# - 登录到基于相同基本模板开发的系统时出现“防伪令牌意味着基于声明的用户与当前用户不同”的错误
- dart - 为什么我不能从 Flutter Web 中的响应标头中读出 cookie 而 chrome 可以?
- json - 来自 Nginx 服务器的截断响应
- php - 事件列表显示 - API 数据和自定义帖子类型数据合并 Wordpress
- spring - 如何使用spring集成在文件夹谷歌云存储中上传和下载文件
- php - 从另一个编辑 php 文件数组变量
- scala - gatling 和弹性:无效的基本身份验证标头编码
- oracle - PL SQL 新手,需要更新游标和 2 个表的帮助
- python - 银行系统的账户使用字典来存储它,但它只读取第一个账户