¿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() 
  • ¿Existe alguna forma clara de utilizar los methods de extensión de Groovy en Kotlin?
  • ¿Cómo usar "Definición funcional de frijoles Kotlin DSL" con Spring Boot y Spring WebFlux?
  • Java Stream con :: nuevo en Kotlin
  • Kotlin - Use Realm Module en android
  • ¿Por qué .map en un mutableList en realidad no cambia los valores dentro de List en Kotlin?
  • ¿Cómo crear una implementación anónima de una interfaz?
  • Cómo restringir kotlin de usar java api que se anuncia arriba de jdk1.6
  • ¿Puedo escribir una function de extensión de Kotlin que use un bean de spring autoconectado?
  • Cómo usar volátiles en Kotlin
  • ¿Qué versión de Dokka va con qué versión de Kotlin?
  • Cómo deshabilitar el button de punto en Android Kotlin