等效 Java 和 Kotlin Stream 代码之间的意外类型差异

Unexpected type difference between equivalent Java and Kotlin Stream code

编辑 2016 年 3 月 1 日:公平警告:这个问题是关于 1.0.0 之前的 Kotlin 的。自 Kotlin 1.0.0 以来,情况有所不同。有关 Kotlin 1.0.0 的答案,请参阅下面@Jayson Minard 的文章。

在使用Stream的Java8代码中,我写的是

public static void main(String... args) {
    Stream<Integer> integerStream = Stream.of(1,2,3);
    List<Integer> integerList = integerStream.collect(Collectors.toList());
}

但是在用 Kotlin 编写的类似代码中,我得到了意想不到的结果。

public fun main(args: Array<String>) {
    val integerStream : Stream<Int> = Stream.of(1, 2, 3)

    // this is what I expect to write, like the Java 8 code, but is a compilation error: 
    // "required: java.util.List<in kotlin.Int> found: kotlin.MutableList<in kotlin.Int!"
    // val list : java.util.List<in Int> = integerStream.collect(Collectors.toList()) 

    // I must instead write this
    val list : MutableList<in Int> = integerStream.collect(Collectors.toList())
}

为什么 Stream#collect 表达式的 return 值在 Kotlin 代码中与 Java 代码中的列表类型不同? (我猜这是因为 Kotlin 中的一些 Java 特定于集合的魔法)

我认为这是因为 Java 中的 List 默认是可变的,而在 Kotlin 中它们是不可变的。 在您使用 Java 特定实用程序的代码中,Collectors.toList 其中 returns 一个 Java List,Kotlin 将其翻译为 MutableList,所以实际上您正在编写相同的代码,只是类型名称不同。

您可以在 Kotlin 1.0 中执行此操作:

val integerStream : Stream<Int> = Stream.of(1, 2, 3)
val list : List<Int> = integerStream.collect(Collectors.toList<Int>())

val integerStream : Stream<Int> = Stream.of(1, 2, 3)
val list : MutableList<Int> = integerStream.collect(Collectors.toList<Int>())

或不关心,让推理决定:

val integerStream = Stream.of(1, 2, 3)
val list = integerStream.collect(Collectors.toList<Int>())

注意: 我将您的 toList() 调用更改为 toList<Int>() 以解决

中提到的问题

您还可以创建一个扩展函数:

fun <T: Any> Stream<T>.toList(): List<T> = this.collect(Collectors.toList<T>())

然后将其用于任何 Stream<T>List<T> 的转换:

val integerStream = Stream.of(1, 2, 3)
val list = integerStream.toList()

val stringStream = Stream.of("a", "b", "c")
val stringList = stringStream.toList()

最后一个示例已经返回 List 的只读接口,而不是 MutableList。有关这些接口与 Kotlin 中其他映射接口之间的区别,请参阅 Java Interop, mapped types.

的文档

最后,另一种变体是转换为 Sequence 并保持惰性,因为它是 Stream 的 Kotlin 等价物。

fun <T: Any> Stream<T>.asSequence(): Sequence<T> = this.iterator().asSequence()

Stream.iterator()类似,但不相同。