在Java 8中,类java.util.Optional
(javadoc)类提供"Maybe" Monad或Option Type的功能。
更直接:
公共最终类java.util.Optional< T> extends Object
容器对象,可能包含也可能不包含非null值。如果一个 值存在,isPresent()将返回true,get()将返回 价值。
< U>可选< U> map(函数<?super T,?extends U> mapper)
如果存在值,请将提供的映射函数应用于它,如果存在 结果为非null,返回描述结果的Optional。
问题在于map()
为什么在U
类型上使用类型通配符。
我对类型通配符的理解很简单:
? super T
指定从Object
到T
(包括Object
和T
的子类路径)给出的类集合中的某些类型。在任何子接口路径上找到的接口集"作为一个侧面的"通过implements
。
而? extends U
只是从扩展U
(包含U
)的类集合中指定某种类型。
所以可以写一下:
< U>可选< U> map(函数<?super T,U> mapper)
不丢失信息。
或不?
答案 0 :(得分:7)
不完全。
Function<? super T, U>
与Function<? super T, ? extends U>
不同。
例如,即使我将Optional<CharSequence>
传递给该方法,我仍然可以获得Function<Object, String>
。如果该方法被定义为<U> Optional<U> map(Function<? super T, U> mapper)
,那么这是不可能的。
这是因为泛型不变:<T>
与<? extends T>
不同。这是用Java语言实现的设计决策。
让我们看看Jon Skeet explains what would happen如果泛型不会是不变的:
class Animal { }
class Dog extends Animal { }
class Cat extends Animal { }
public void ouch() {
List<Dog> dogs = Arrays.asList(new Dog(), new Dog());
List<Animal> animals;
// This would be legal, right? Because a list of dogs is a list of animals.
List<Animal> animals = dogs;
// This would be legal, right? Because a cat could be added to a
// list of animals, because a cat is an animal.
animals.add(new Cat());
// Unfortunately, we have a confused cat.
}
虽然我不完全确定你在评论中的意思,但我会尝试详细说明。
如果您可以完全控制自己提供的Function
,那么该方法的签名是Function<? super T, U>
还是Function<? super T, ? extends U>
并不重要。我会相应调整你的Function
。但是该方法的作者可能希望该方法尽可能灵活,允许提供Function
的第二个参数也是U
的子类,而不只是U
本身。实际上,您将其下限从U
扩展到U
的某个子类型。
因此该函数应该真正读取
<U> Optional<? the-most-general-but-fixed-supertype-of U> map(Function<? super T, U> mapper)
,但以这种方式表达会很尴尬。
我确实很尴尬。此外,您提出的符号与map()
的实际方法签名之间存在差异,其中涉及下限和上限的含义。
了解更多: