Java 8 Stream 等价物
关于懒惰
如果你想延迟处理一个链,你可以在链之前使用 asSequence()
转换为 Sequence
。在功能链的末尾,你通常也会得到一个 Sequence
。然后你可以使用 toList()
,toSet()
,toMap()
或其他一些功能在最后实现 Sequence
。
// switch to and from lazy
val someList = items.asSequence().filter { ... }.take(10).map { ... }.toList()
// switch to lazy, but sorted() brings us out again at the end
val someList = items.asSequence().filter { ... }.take(10).map { ... }.sorted()
为什么没有类型?!?
你会注意到 Kotlin 示例未指定类型。这是因为 Kotlin 具有完整的类型推断并且在编译时完全是类型安全的。比 Java 更多,因为它也有可空类型,可以帮助防止可怕的 NPE。所以这在 Kotlin:
val someList = people.filter { it.age <= 30 }.map { it.name }
是相同的:
val someList: List<String> = people.filter { it.age <= 30 }.map { it.name }
因为 Kotlin 知道 people
是什么,并且 people.age
是 Int
因此过滤器表达式只允许与 Int
进行比较,并且 people.name
是 String
因此 map
步骤产生 List<String>
(读取 List
of String
)。
现在,如果 people
可能是 null
,那么在一个 List<People>?
然后:
val someList = people?.filter { it.age <= 30 }?.map { it.name }
返回需要进行空检查的 List<String>?
( 或使用其他 Kotlin 运算符之一获取可空值,请参阅此 Kotlin 惯用方法来处理可空值以及处理可空或空列表的 惯用方法 )
重用流
在 Kotlin 中,它取决于收集的类型是否可以不止一次消费。Sequence
每次都会生成一个新的迭代器,除非它断言只使用一次,否则它每次执行时都会重置为开始。因此,虽然以下在 Java 8 流中失败,但在 Kotlin 中工作:
// Java:
Stream<String> stream =
Stream.of("d2", "a2", "b1", "b3", "c").filter(s -> s.startsWith("b"));
stream.anyMatch(s -> true); // ok
stream.noneMatch(s -> true); // exception
// Kotlin:
val stream = listOf("d2", "a2", "b1", "b3", "c").asSequence().filter { it.startsWith('b' ) }
stream.forEach(::println) // b1, b2
println("Any B ${stream.any { it.startsWith('b') }}") // Any B true
println("Any C ${stream.any { it.startsWith('c') }}") // Any C false
stream.forEach(::println) // b1, b2
并在 Java 中获得相同的行为:
// Java:
Supplier<Stream<String>> streamSupplier =
() -> Stream.of("d2", "a2", "b1", "b3", "c")
.filter(s -> s.startsWith("a"));
streamSupplier.get().anyMatch(s -> true); // ok
streamSupplier.get().noneMatch(s -> true); // ok
因此,在 Kotlin 中,数据提供者决定它是否可以重置并提供新的迭代器。但是如果你想故意将 Sequence
约束到一次迭代,你可以使用 constrainOnce()
函数为 Sequence
,如下所示:
val stream = listOf("d2", "a2", "b1", "b3", "c").asSequence().filter { it.startsWith('b' ) }
.constrainOnce()
stream.forEach(::println) // b1, b2
stream.forEach(::println) // Error:java.lang.IllegalStateException: This sequence can be consumed only once.
也可以看看:
- Iterable 扩展函数的 API 参考
- Array 的扩展函数的 API 参考
- List 的扩展函数的 API 参考
- 扩展函数到 Map 的 API 参考