KotlinJava 8 équivalents de flux


Introduction

Kotlin fournit de nombreuses méthodes d'extension sur les collections et les itérables pour appliquer des opérations de style fonctionnel. Un type de Sequence dédié permet la composition paresseuse de plusieurs de ces opérations.

Remarques

À propos de la paresse

Si vous voulez traiter une chaîne paresseuse, vous pouvez convertir en une Sequence utilisant asSequence() avant la chaîne. À la fin de la chaîne de fonctions, vous vous retrouvez généralement avec une Sequence . Ensuite, vous pouvez utiliser toList() , toSet() , toMap() ou une autre fonction pour matérialiser la Sequence à la fin.

// switch to and from lazy
val someList = items.asSequence().filter { ... }.take(10).map { ... }.toList()

// switch to lazy, but sorted() brings us out again at the end
val someList = items.asSequence().filter { ... }.take(10).map { ... }.sorted()

Pourquoi n'y a-t-il pas de types?

Vous remarquerez que les exemples Kotlin ne spécifient pas les types. Ceci est dû au fait que Kotlin a une inférence de type complète et est complètement de type sécurisé au moment de la compilation. Plus que Java, car il a également des types nullables et peut aider à empêcher le NPE redouté. Donc ceci à Kotlin:

val someList = people.filter { it.age <= 30 }.map { it.name }

est le même que:

val someList: List<String> = people.filter { it.age <= 30 }.map { it.name }

Comme Kotlin sait ce que sont les people et que people.age est Int l'expression de filtre permet uniquement la comparaison avec un Int , et que people.name est une String conséquent, l'étape map génère une List<String> (Listonly List of String ).

Maintenant, si les people étaient peut-être null , comme dans une List<People>? puis:

val someList = people?.filter { it.age <= 30 }?.map { it.name }

Retourne une List<String>? cela devrait être vérifié par la valeur null ( ou utiliser l'un des autres opérateurs Kotlin pour les valeurs nullables, voir cette méthode idiomatique de Kotlin pour traiter les valeurs nulles et également la manière idiomatique de gérer les listes nullables ou vides dans Kotlin )

Réutiliser les flux

Dans Kotlin, cela dépend du type de collection si elle peut être consommée plus d'une fois. Une Sequence génère un nouvel itérateur à chaque fois, et à moins qu'elle n'utilise "une seule fois", elle peut être réinitialisée à chaque fois qu'elle est utilisée. Par conséquent, alors que le suivant échoue dans le flux Java 8, mais fonctionne dans Kotlin:

// Java:
Stream<String> stream =
Stream.of("d2", "a2", "b1", "b3", "c").filter(s -> s.startsWith("b"));

stream.anyMatch(s -> true);    // ok
stream.noneMatch(s -> true);   // exception
// Kotlin:  
val stream = listOf("d2", "a2", "b1", "b3", "c").asSequence().filter { it.startsWith('b' ) }

stream.forEach(::println) // b1, b2

println("Any B ${stream.any { it.startsWith('b') }}") // Any B true
println("Any C ${stream.any { it.startsWith('c') }}") // Any C false

stream.forEach(::println) // b1, b2

Et en Java pour obtenir le même comportement:

// Java:
Supplier<Stream<String>> streamSupplier =
    () -> Stream.of("d2", "a2", "b1", "b3", "c")
          .filter(s -> s.startsWith("a"));

streamSupplier.get().anyMatch(s -> true);   // ok
streamSupplier.get().noneMatch(s -> true);  // ok

Par conséquent, dans Kotlin, le fournisseur des données décide s'il peut réinitialiser et fournir un nouvel itérateur ou non. Mais si vous souhaitez contraindre intentionnellement une Sequence à une itération unique, vous pouvez utiliser la fonction constrainOnce() pour la Sequence comme suit:

val stream = listOf("d2", "a2", "b1", "b3", "c").asSequence().filter { it.startsWith('b' ) }
        .constrainOnce()

stream.forEach(::println) // b1, b2
stream.forEach(::println) // Error:java.lang.IllegalStateException: This sequence can be consumed only once. 

Voir également:

Java 8 équivalents de flux Exemples Liés