¿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:
- Definición de la function: fun vs val
- Configuración de Kotlin vía gradle en eclipse
- Algunos errores ocurrieron al procesar las annotations
- Función de extensión Kotlin en propiedad mutable
- conectar entre Grid View y List Veiw en kotlin
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.
- Tengo una request de Vertx y necesito calcular una URL externa visible (pública)
- Gradle compileKotlin includeRuntime no agrega time de ejecución para jar
- No se puede instalar el gradle para android studio 3.0
- Validar files XML grandes contra grandes XSD, ¿hay alguna manera rápida de hacerlo?
- Anotaciones de Android con Kotlin y herramientas de compilation 2.3.0
- Protocolo Buffer de soporte gradle para Android Kotlin no funciona?
- Cómo crear una list con un argumento genérico en Kotlin
- Pruebas unitarias Rxjava observables que tienen un retraso
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()
- La mejor manera de manejar ese escenario donde "smart cast es imposible"
- Función de límite en Kotlin