过滤流会改变它的通配符边界吗?
filtering a stream changes its wildcard bounds?
下面的方法编译没有问题:
static Stream<Optional<? extends Number>> getNumbers(Stream<Number> numbers) {
return numbers.map(Optional::of);
}
然而,如果我像这样添加一个简单的过滤:
static Stream<Optional<? extends Number>> getNumbers2(Stream<Number> numbers) {
return numbers.map(Optional::of).filter(number -> true);
}
它生成以下错误:
incompatible types:
java.util.stream.Stream<java.util.Optional<java.lang.Number>> cannot be converted to
java.util.stream.Stream<java.util.Optional<? extends java.lang.Number>>
已在 openJdk-11 和 openJdk-17 上测试。
我希望他们都做同样的事情(要么都编译正常,要么都产生相同的编译错误),所以我真的很困惑:这里解释为什么第一种方法的一般规则是什么编译好但第二个没有?
谢谢!
在第一种情况下与 return 类型 Stream<Optional<? extends Number>>
的兼容性不是通过 numbers.map(Optional::of)
return 自身 Stream<Optional<? extends Number>>
获得的;这是编译器推断 numbers.map(...)
的 return 类型,因为它是一个通用方法:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
而 Stream.filter()
不是:
Stream<T> filter(Predicate<? super T> predicate);
因此,在第一种情况下,编译器在推断 numbers.map(...)
.
的类型时可以考虑 return 语句的上下文(getNumbers
的类型)
在第二种情况下,编译器不能对 numbers.map(...)
做同样的事情,因为有后续的链式调用,这可能会进一步改变类型,所以在这个阶段很难猜测正确的推断应该是什么。因此,最具体的可能类型被假定为 numbers.map(...)
(Stream<Optional<Number>>
) 并进一步由 filter(...)
.
进行
作为一个不同的例子来说明这一点,请弄清楚为什么这两个编译(List.of()
毕竟是相同的代码):
static List<String> stringList() {
return List.of();
}
static List<Integer> intList() {
return List.of();
}
现在,为什么会失败:
static List<String> stringList() {
return List.of().subList(0, 0);
}
那是因为List.subList(...)
不推断returned列表的E
上下文类型(即方法不是通用的),它携带List
实例的E
类型,在这种情况下,List.of()
默认为 Object
(是的,当你有 return List.of();
、return 类型推断时,强制编译器找出其目的是使 E
匹配 String
,方法的 return 类型中的类型参数)。 请注意,这比那更复杂,有些地方推理不起作用,因为 wished/expected。
简答:return numbers.map(Optional::of)
利用了类型推断,因为map()
是通用的,而filter()
不是,期望E
of Stream<E>
被携带。对于 numbers.map(Optional::of)
,E
是 Optional<Number>
,而不是 Optional<? extends Number>
,而 filter
是
。
下面的方法编译没有问题:
static Stream<Optional<? extends Number>> getNumbers(Stream<Number> numbers) {
return numbers.map(Optional::of);
}
然而,如果我像这样添加一个简单的过滤:
static Stream<Optional<? extends Number>> getNumbers2(Stream<Number> numbers) {
return numbers.map(Optional::of).filter(number -> true);
}
它生成以下错误:
incompatible types:
java.util.stream.Stream<java.util.Optional<java.lang.Number>> cannot be converted to
java.util.stream.Stream<java.util.Optional<? extends java.lang.Number>>
已在 openJdk-11 和 openJdk-17 上测试。
我希望他们都做同样的事情(要么都编译正常,要么都产生相同的编译错误),所以我真的很困惑:这里解释为什么第一种方法的一般规则是什么编译好但第二个没有? 谢谢!
在第一种情况下与 return 类型 Stream<Optional<? extends Number>>
的兼容性不是通过 numbers.map(Optional::of)
return 自身 Stream<Optional<? extends Number>>
获得的;这是编译器推断 numbers.map(...)
的 return 类型,因为它是一个通用方法:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
而 Stream.filter()
不是:
Stream<T> filter(Predicate<? super T> predicate);
因此,在第一种情况下,编译器在推断 numbers.map(...)
.
的类型时可以考虑 return 语句的上下文(getNumbers
的类型)
在第二种情况下,编译器不能对 numbers.map(...)
做同样的事情,因为有后续的链式调用,这可能会进一步改变类型,所以在这个阶段很难猜测正确的推断应该是什么。因此,最具体的可能类型被假定为 numbers.map(...)
(Stream<Optional<Number>>
) 并进一步由 filter(...)
.
作为一个不同的例子来说明这一点,请弄清楚为什么这两个编译(List.of()
毕竟是相同的代码):
static List<String> stringList() {
return List.of();
}
static List<Integer> intList() {
return List.of();
}
现在,为什么会失败:
static List<String> stringList() {
return List.of().subList(0, 0);
}
那是因为List.subList(...)
不推断returned列表的E
上下文类型(即方法不是通用的),它携带List
实例的E
类型,在这种情况下,List.of()
默认为 Object
(是的,当你有 return List.of();
、return 类型推断时,强制编译器找出其目的是使 E
匹配 String
,方法的 return 类型中的类型参数)。 请注意,这比那更复杂,有些地方推理不起作用,因为 wished/expected。
简答:return numbers.map(Optional::of)
利用了类型推断,因为map()
是通用的,而filter()
不是,期望E
of Stream<E>
被携带。对于 numbers.map(Optional::of)
,E
是 Optional<Number>
,而不是 Optional<? extends Number>
,而 filter
是