¿Cómo puedo llamar a collect (Collectors.toList ()) en un Java 8 Stream en Kotlin?

Tengo el código:

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") } } 

Si llamo a collect(Collectors.toList()) al final del filter, obtengo:

 Error:(22, 13) Kotlin: [Internal Error] org.jetbrains.kotlin.codegen.ComstacktionException: Back-end (JVM) Internal error: no descriptor for type constructor of ('Captunetworking(in ('Path'..'Path?'))'..'CaptunetworkingTypeConstructor(in ('Path'..'Path?'))?') Cause: no descriptor for type constructor of ('Captunetworking(in ('Path'..'Path?'))'..'CaptunetworkingTypeConstructor(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 

Si no hago esto, obtengo la f con el tipo [error: Error] en mi for-loop.

ACTUALIZACIÓN: Este problema ahora está solucionado en Kotlin 1.0.1 (anteriormente era KT-5190 ). No se necesita ninguna solución.


Soluciones provisionales

Solución # 1:

Crea esta function de extensión, luego .toList() simplemente como .toList() en la .toList() :

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

uso:

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

Esto agrega un parámetro genérico más explícito a la llamada a Collectors.toList() , evitando el error que ocurre durante la inferencia de los generics (que son un tanto intrincados para ese tipo de retorno de método Collector<T, ?, List<T>> , eeeks! ?! ).

Solución 2:

Agregue el parámetro de tipo correcto a su llamada como Collectors.toList<Path>() para evitar la inferencia tipo de ese parámetro:

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

Pero la function de extensión en la solución # 1 es más reutilizable y más conciso.


Manteniéndose perezoso

Otra forma de evitar el error es no recostackr el Stream . Puedes mantenerte vago y convertir Stream a Kotlin Sequence o Iterator , aquí hay una function de extensión para hacer una Sequence :

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

Ahora tiene para forEach y muchas otras funciones disponibles para usted mientras sigue consumiendo el Stream perezosa y solo una vez. Usar myStream.iterator() es otra forma, pero puede que no tenga tanta funcionalidad como una Sequence .

Y, por supuesto, al final de algunos procesamientos en la Sequence , puede toList() o toSet() o usar cualquier otra extensión de Kotlin para cambiar los types de colección.

Y con esto, crearía extensiones para listr files para evitar el mal layout de API de Paths , Path , Files , File :

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

que al less fluiría bien de izquierda a derecha:

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

Alternativas al uso de Java 8 Streams:

Podemos cambiar su código ligeramente para get la list de File de File lugar, y usted simplemente usaría toList() al final:

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

o

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

Lamentablemente, Files.list(...) que Files.list(...) originalmente devuelve un Stream y no te da la oportunidad de usar una colección tradicional. Este cambio lo evita comenzando con una function que devuelve una matriz o colección.

En general:

En la mayoría de los casos, puede evitar las secuencias de Java 8 y usar las funciones y extensiones nativas de Kotlin stdlib para las collections de Java. Kotlin sí utiliza collections de Java, a través de interfaces read-one y mutables en time de compilation. Pero luego agrega funciones de extensión para proporcionar más funcionalidad. Por lo tanto, tiene el mismo performance pero con muchas más capacidades.

Ver también:

  • ¿Qué equivalentes de Java 8 Stream.collect están disponibles en la biblioteca estándar de Kotlin? – Verá que es más conciso usar las funciones y extensiones de Kotlin stdlib.
  • Colecciones de Kotlin y Documentos de API de funciones de extensión
  • Kotlin Sequences API docs
  • Kotlin modismos

Debe revisar la reference de la API para saber qué hay disponible en el file stdlib.

Este es otro trabajo si estás por alguna razón atrapado en la versión beta más antigua de Kotlin que requiere una solución más brutal …

Solución # 3: (feo, una solución anterior SOLAMENTE para versiones antiguas de Kotlin)

Agregue esta class de Java a su proyecto:

 import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class CollectFix { public static <T> List<T> streamToList(Stream<T> s) { return s.collect(Collectors.toList()); } } 

Y esta function de extensión de Kotlin :

 fun <T: Any> Stream<T>.toList(): List<T> = CollectFix.streamToList(this) 

Y luego, cada vez que tenga este caso, use esta nueva extensión:

 Files.list(Paths.get(file)).filter { /* filter clause */ }.toList() 
  • Renderiza la respuesta json en Kotlin
  • ¿Qué es el equivalente java de los types de funciones de Kotlin?
  • ¿Puedo get una KFunction de una variable del tipo de function en Kotlin?
  • Prueba mónada por kotlin
  • Cómo agregar class kotlin a gradle tarea JavaCompile
  • ¿Cómo funcionan el argumento pnetworkingeterminado y @JvmOverloads en Kotlin?
  • Cómo configurar NDK con Kotlin en Android Studio 3.0
  • Android Studio 3.0 Proguard con kotlin y greendao devuelve ClassLookupException
  • ¿Se puede utilizar javascript generado a partir de fonts de Kotlin en JVM?
  • ¿Cómo puedo agregar TeaVM a mi proyecto libGDX existente?
  • PubNub suscribe Android Kotlin