发现collect(Collectors.toList())和Stream.toList()之间的区别。看
class Animal { }
class Cat extends Animal { }
record House(Cat cat) { }
class Stuff {
public static void function() {
List<House> houses = new ArrayList<>();
List<Animal> animals1 =
houses.stream()
.map(House::cat)
.collect(Collectors.toList()); // ok
List<Animal> animals2 =
houses.stream()
.map(House::cat).toList(); // compile error
List<Animal> animals3 =
houses.stream()
.map(House::cat)
.map(cat -> (Animal) cat).toList(); // ok
}
}
Run Code Online (Sandbox Code Playgroud)
collect(Collectors.toList()) 能够给我一个动物列表或猫列表。但是Stream.toList()只能给出Cat的List。
问题是有什么方法可以让 Stream.toList() 工作。在我的现实世界示例中,我有一个类覆盖 shutdownNow,它返回 Runnable 列表,因此我的类调用了 some.stream().collect(Collectors.toList()),但是 some.stream().toList()返回 MyRunnable 的列表。
我的一部分希望他们将函数声明为而default <U super T> List<U> toList()不是default List<T> toList(),尽管奇怪的是,这在我的机器上是一个编译错误(我的编译器似乎可以使用 U extends T,而不是 U super T)。
这里有一个简单的答案。
从...开始
var stream = houses.stream().map(House::cat)
Run Code Online (Sandbox Code Playgroud)
这里,stream有类型Stream<Cat>。该Stream::toList方法为您提供流元素类型的列表,此处为Cat。stream.toList()类型也是如此List<Cat>。这里别无选择。
Collector有多个类型变量,包括输入元素的类型和输出结果的类型。Collector创建接受Cat并生成List<Cat>、List<Animal>、等的 具有很大的灵活性。Set<Animal>这种灵活性部分地被 的通用性Stream::collect(以及通用方法Collectors::toList)所隐藏;推断此方法的泛型类型参数可以考虑 LHS 上所需的结果类型。因此,语言为您掩盖了Cat和之间的差距Animal,因为流和结果之间存在另一层间接性。
正如@Eugene 指出的,你可以得到一个更通用的类型:
List<? extends Animal> animals2 = houses.stream().map(House::cat).toList()
Run Code Online (Sandbox Code Playgroud)
这与流无关;这只是因为List<? extends Animal>是 的超类型List<Cat>。但还有一个更简单的方法。如果您想要 a List<Animal>,并且想要使用toList(),请将流类型更改为 a Stream<Animal>:
List<Animal> animals = houses.stream().map(h -> (Animal) h.cat()).toList()
Run Code Online (Sandbox Code Playgroud)
Stream::map也是通用的,所以通过让 lambda 的 RHS 为Animal, not Cat,你得到 a Stream<Animal>,然后toList()给你一个List<Animal>。
如果您更喜欢的话,您也可以将其分解:
List<Animal> animals = houses.stream().map(House::cat)
.map(c -> (Animal) c).toList()
Run Code Online (Sandbox Code Playgroud)
让你困惑的是,因为collect是一个泛型方法(等等Collectors::toList),所以有额外的灵活性来推断稍微不同的类型,而在更简单的流中,一切都更加明确,所以如果你想调整类型,你必须在命令式代码中执行此操作。
| 归档时间: |
|
| 查看次数: |
766 次 |
| 最近记录: |