gpt4 book ai didi

java - 如何在 Kotlin 的 Java 8 流上调用 collect(Collectors.toList())?

转载 作者:IT老高 更新时间:2023-10-28 13:43:43 27 4
gpt4 key购买 nike

我有一些代码:

directoryChooser.title = "Select the directory"
val file = directoryChooser.showDialog(null)
if (file != null) {
var files = Files.list(file.toPath())
.filter { f ->
f.fileName.endsWith("zip") && f.fileName.endsWith("ZIP")
&& (f.fileName.startsWith("1207") || f.fileName.startsWith("4407") || f.fileName.startsWith("1507") || f.fileName.startsWith("9007") || f.fileName.startsWith("1807"))
}
for (f in files) {
textArea.appendText(f.toString() + "\n")
}
}

如果我在过滤器末尾调用 collect(Collectors.toList()),我会得到:

Error:(22, 13) Kotlin: [Internal Error] org.jetbrains.kotlin.codegen.CompilationException: Back-end (JVM) Internal error: no descriptor for type constructor of ('Captured(in ('Path'..'Path?'))'..'CapturedTypeConstructor(in ('Path'..'Path?'))?')
Cause: no descriptor for type constructor of ('Captured(in ('Path'..'Path?'))'..'CapturedTypeConstructor(in ('Path'..'Path?'))?')
File being compiled and position: (22,13) in D:/My/devel/ListOfReestrs/src/Controller.kt
PsiElement: var files = Files.list(file.toPath())
.filter { f ->
f.fileName.endsWith("zip") && f.fileName.endsWith("ZIP")
&& (f.fileName.startsWith("1207") || f.fileName.startsWith("4407") || f.fileName.startsWith("1507") || f.fileName.startsWith("9007") || f.fileName.startsWith("1807"))
}.collect(Collectors.toList())
The root cause was thrown at: JetTypeMapper.java:430

如果我不这样做,我会在我的 for 循环中获得类型为 [error: Error]f

最佳答案

更新:这个问题现已在 Kotlin 1.0.1 中得到修复(之前是 KT-5190)。不需要变通。


解决方法

解决方法 #1:

创建这个扩展函数,然后将其简单地用作.toList()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() 添加了一个更明确的通用参数。调用,防止在推断泛型期间发生的错误(对于该方法返回类型 Collector<T, ?, List<T>>eeeks!?!,这有点令人费解)。

解决方法 #2:

将正确的类型参数添加到您的调用中,如 Collectors.toList<Path>()避免对该参数的类型推断:

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

但解决方法 #1 中的扩展功能更可重用且更简洁。


保持懒惰

解决此错误的另一种方法是不收集 Stream .你可以保持懒惰,并转换 Stream到 Kotlin SequenceIterator , 这是一个扩展函数,用于制作 Sequence :

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

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

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

有了这个,我将创建一个用于列出文件的扩展,以避免 Paths 的不良 API 设计。 , Path , Files , File :

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

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

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

使用 Java 8 流的替代方案:

我们可以稍微更改您的代码以从 File 获取文件列表相反,您只需使用 toList()最后:

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

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

不幸的是 Files.list(...)您最初使用的返回 Stream并且不给您使用传统 Collection 的机会。此更改通过从返回数组或集合的函数开始来避免这种情况。

一般:

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

另请参阅:

您应该查看 API reference了解标准库中可用的内容。

关于java - 如何在 Kotlin 的 Java 8 流上调用 collect(Collectors.toList())?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35721528/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com