且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在Kotlin中的Java 8 Stream上调用collect(Collectors.toList())?

更新时间:2023-10-06 13:12:43

UPDATE:此问题现已在Kotlin 1.0.1中修复(以前是 KT -5190 )。无需解决问题。

UPDATE: This issue is now fixed in Kotlin 1.0.1 (previously was KT-5190). No work around is needed.

解决方法#1:

创建此扩展函数,然后将其简单地用作 .toList()上的code>流:

Create this extension function, then use it simply as .toList() on the Stream:

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

用法:

Files.list(Paths.get(file)).filter { /* filter clause */ }.toList()

这为 Collectors.toList()添加了更明确的泛型参数调用,防止在推理泛型期间发生的错误(对于该方法返回类型有点复杂收集器< T,?,列表< T>> eeeks!?!)。

This adds a more explicit generic parameter to the Collectors.toList() call, preventing the bug which occurs during inference of the generics (which are somewhat convoluted for that method return type Collector<T, ?, List<T>>, eeeks!?!).

解决方法#2:

为您的调用添加正确的类型参数 Collectors.toList< Path>()以避免该参数的类型推断:

Add the correct type parameter to your call as Collectors.toList<Path>() to avoid type inference of that parameter:

Files.list(Paths.get(file)).filter { /* filter clause */ }.collect(Collectors.toList<Path>())

但是变通方法#1中的扩展功能更易于使用且更简洁。

But the extension function in workaround #1 is more re-usable and more concise.

另一种解决方法是不收集 Stream 。您可以保持懒惰,并将 Stream 转换为Kotlin 序列 Iterator ,这是一个扩展函数,用于制作序列

Another way around the bug is to not collect the Stream. You can stay lazy, and convert the Stream to a Kotlin Sequence or Iterator, here is an extension function for making a Sequence:

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

现在你有 forEach 以及许多其他可用的功能,同时仍然懒得只消耗 Stream 一次。使用 myStream.iterator()是另一种方式,但可能没有 Sequence 那么多的功能。

Now you have forEach and many other functions available to you while still consuming the Stream lazily and only once. Using myStream.iterator() is another way but may not have as much functionality as a Sequence.

当然,在序列的某些处理结束时,您可以 toList() toSet()或使用任何其他Kotlin扩展来更改集合类型。

And of course at the end of some processing on the Sequence you can toList() or toSet() or use any other of the Kotlin extensions for changing collection types.

和有了这个,我会为列出文件创建一个扩展,以避免错误的API设计路径路径文件文件

And with this, I would create an extensions for listing files to avoid the bad API design of Paths, Path, Files, File:

fun Path.list(): Sequence<Path> = Files.list(this).iterator().asSequence()

这至少会很好地流动从左到右:

which would at least flow nicely from left to right:

File(someDir).toPath().list().forEach { println(it) }
Paths.get(dirname).list().forEach { println(it) }






使用Java 8 Streams的替代方法:



我们可以稍微更改您的代码以从文件,而你最后只需使用 toList()


Alternatives to using Java 8 Streams:

We can change your code slightly to get the file list from File instead, and you would just use toList() at the end:

file.listFiles().filter { /* filter clause */ }.toList()

file.listFiles { file, name ->  /* filter clause */ }.toList()

不幸的是文件。您最初使用的list(...)会返回 Stream ,并且不会让您有机会使用传统的集合。此更改通过启动返回数组或集合的函数来避免这种情况。

Unfortunately the Files.list(...) that you originally used returns a Stream and doesn't give you the opportunity to use a traditional collection. This change avoids that by starting with a function that returns an Array or collection.

一般情况:

在大多数情况下,您可以避免使用Java 8流,并使用本机Kotlin stdlib函数和Java集合的扩展。 Kotlin确实使用Java集合,通过编译时只读和可变接口。但随后它添加了扩展功能以提供更多功能。因此,您具有相同的性能,但具有更多功能。

In most cases you can avoid Java 8 streams, and use native Kotlin stdlib functions and extensions to Java collections. Kotlin does indeed use Java collections, via compile-time readonly and mutable interfaces. But then it adds extension functions to provide more functionality. Therefore you have the same performance but with many more capabilities.

另见:

  • What Java 8 Stream.collect equivalents are available in the standard Kotlin library? - You will see it is more concise to use Kotlin stdlib functions and extensions.
  • Kotlin Collections, and Extension Functions API docs
  • Kotlin Sequences API docs
  • Kotlin idioms

您应该查看 API参考,了解stdlib中可用的内容。

You should review the API reference for knowing what is available in the stdlib.