当前位置: 首页 > 面试题库 >

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

虞高雅
2023-03-14
问题内容

我有一些代码:

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

如果不执行此操作,f则会[error: Error]在for循环中获得类型。


问题答案:

更新: 此问题现在已在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()调用,防止其仿制药的推理过程中出现的bug(这是有点令人费解了该方法的返回类型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,这是制作a的扩展功能Sequence

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

现在,您可以使用forEach许多其他功能,而仍然Stream只能懒惰地消费一次。使用myStream.iterator()是另一种方式,但可能没有的功能Sequence

当然,在Sequence您进行一些处理之后,您可以toList()toSet()可以使用任何其他Kotlin扩展来更改集合类型。

而与此,我想创建一个扩展列表文件,以避免不好的API设计PathsPathFilesFile

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(...),您最初使用的会返回a
Stream,并且没有给您使用传统收藏的机会。此更改通过从返回Array或collection的函数开始避免了这种情况。

一般来说:

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

也可以看看:

  • 标准Kotlin库中提供了哪些Java 8 Stream.collect等效项?-您会发现使用Kotlin stdlib函数和扩展更为简洁。
  • Kotlin集合和扩展功能API文档
  • Kotlin Sequences API文档
  • Kotlin成语

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



 类似资料:
  • 我有一个问题要解决,我应该在哪里从使用Java8 streams的员工列表中找到性别为男性的第n个员工,如果没有找到,则返回可选的空。 下面是接受Employee对象列表和整数n的方法,其中n表示必须返回的第n个男性雇员(如果存在的话)。

  • 如标题所示,在中,是否有方法在延迟(例如1秒)后调用函数?

  • 问题内容: 我在站点的文档上有一些ajax调用,这些调用根据ajax状态显示或隐藏进度条 我想基本上在网站的其他部分覆盖这些方法,这些地方会进行许多快速的小型ajax调用,并且不需要弹出和弹出进度条。我试图将它们附加到其他$ .getJSON和$ .ajax调用中或将其插入。我已经尝试过将它们链接起来,但是显然那不好。 问题答案: 2018注意: 此答案已过时; 您可以随时对这个答案进行修改,以解

  • 这段代码适用于Java。但是在迁移到Kotlin之后,编译器higlits方法出现以下文本错误: Andswer是: 如果希望在另一个类中使用这个本机函数,可以指定包含它的类,如下所示:

  • 当函数声明类型参数时: 我应该如何在kotlin中调用原始的未类型化的类型化函数? 在爪哇中,我有: 因为< code>typedFunction声明了一个名为< code>T的类型,并将它的两个参数绑定到这个声明的类型,并且在调用站点上,我循环了多个确切类型未知的值(但已知是安全的,两个参数符合相同的类型),所以我不能按预期的方式调用typedFunction。我得把它铸造成一种原始类型。 如何

  • 我开玩笑地增加,减少物品数量。我想算数。文本加上“T”字符。当我试图编写这样的代码时。错误代码:java.lang.NumberFormatException:对于输入字符串:“1T”如何解决此问题?有人能帮忙吗??