简体   繁体   English

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

[英]Unexpected type difference between equivalent Java and Kotlin Stream code

EDIT March 1 2016: Fair warning: this question was asked about Kotlin before 1.0.0. 编辑2016年3月1日:合理警告:在1.0.0之前,有人问过有关Kotlin的问题。 Things are different since Kotlin 1.0.0. 自Kotlin 1.0.0起,情况有所不同。 See @Jayson Minard's writing below for a Kotlin 1.0.0 answer. 有关Kotlin 1.0.0的答案,请参见下面的@Jayson Minard的文章。

In Java 8 code that uses Stream, I write things like 在使用Stream的Java 8代码中,我编写了类似

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

But in similar code written in Kotlin, I get unexpected results. 但是在用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())
}

Why would the return value of the Stream#collect expression be of a different list type in the Kotlin code than in the Java code? 为什么Kotlin代码中的Stream#collect表达式的返回值与Java代码中的列表类型不同? (I'm guessing it is because of some Java Collections-specific magic in Kotlin) (我猜这是由于Kotlin中某些Java集合特有的魔术)

I think it is because List in Java are mutable be default, where as in Kotlin they are immutable. 我认为这是因为默认情况下Java中的List是可变的,而Kotlin中它们是不可变的。 In the code you are using a Java specific utility, Collectors.toList which returns a Java List , which to Kotlin translates as a MutableList , so in effect you are writing the same code, just the type names are different. 在代码中,您使用的是Java特定实用程序Collectors.toList ,它返回一个Java List ,Kotlin将其转换为MutableList ,因此实际上您在编写相同的代码,只是类型名称不同。

You can do this in Kotlin 1.0: 您可以在Kotlin 1.0中执行以下操作:

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

or 要么

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

or not care, and let inference decide: 或不在乎,让推断来决定:

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

NOTE: I changed your toList() call into toList<Int>() to work around the issue mentioned in https://stackoverflow.com/a/35722167/3679676 注意:我将您的toList()调用更改为toList<Int>()以解决https://stackoverflow.com/a/35722167/3679676中提到的问题

You can also create an extension function: 您还可以创建扩展功能:

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

And then use it for any Stream<T> to List<T> conversion: 然后将其用于任何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()

And this last example is already returning the read only interface of List instead of MutableList . 最后一个示例已经返回List的只读接口,而不是MutableList For the difference between these and other mapped interfaces in Kotlin, see the docs for Java Interop, mapped types . 有关Kotlin中这些映射接口与其他映射接口之间的区别,请参阅Java Interop映射类型的文档。

Lastly, one other variant is to convert to a Sequence and stay lazy, since it is the Kotlin equivalent of a Stream . 最后,另一种变体是转换为Sequence并保持惰性,因为它与Stream的Kotlin等效。

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

Or Stream.iterator() is similar, but not the same. Stream.iterator()相似,但不相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM