Comment vérifier si Java 8 Flux de données est vide?
Comment puis-je vérifier si un Stream
est vide et renvoie une exception si ce n'est pas, en tant que non-exploitation du terminal?
En gros, je suis à la recherche de quelque chose d'équivalent pour le code ci-dessous, mais sans se matérialiser les flux entre les deux. En particulier, la vérification ne devrait pas se produire avant que le flux est effectivement consommée par un terminal d'opération.
public Stream<Thing> getFilteredThings() {
Stream<Thing> stream = getThings().stream()
.filter(Thing::isFoo)
.filter(Thing::isBar);
return nonEmptyStream(stream, () -> {
throw new RuntimeException("No foo bar things available")
});
}
private static <T> Stream<T> nonEmptyStream(Stream<T> stream, Supplier<T> defaultValue) {
List<T> list = stream.collect(Collectors.toList());
if (list.isEmpty()) list.add(defaultValue.get());
return list.stream();
}
- Vous ne pouvez pas avoir votre gâteau et le manger aussi, et tout à fait littéralement donc, dans ce contexte. Vous devez consommer le flux pour savoir si elle est vide. C'est le point de Stream sémantique (la paresse).
- Il peut être consommé, finalement, à ce stade de la vérification
- Pour vérifier que le flux n'est pas vide, vous devez tenter de consommer au moins un élément. À ce point, le flux a perdu de sa "virginité" et ne peut pas être consommé à nouveau depuis le début.
Vous devez vous connecter pour publier un commentaire.
Si vous pouvez vivre avec peu de parallèles capablilities, la solution suivante de travail:
Voici un exemple de code utilisant:
Le problème avec (l'efficacité) de l'exécution parallèle est que le soutien à la scission de la
Spliterator
nécessite un thread-safe façon de remarquer que l'une des fragments a vu toute valeur dans un thread-safe manière. Puis, le dernier des fragments de l'exécution detryAdvance
a réaliser que c'est le dernier (et elle aussi ne pouvait pas l'avance) pour lancer l'exception appropriée. Donc je n'ai pas ajouter le support pour le partage de l'ici.Les autres réponses et les commentaires sont correctement qu'à examiner le contenu d'un flux, il faut ajouter un terminal de l'opération, ce qui "consomment" le flux de. Cependant, on peut faire cela et mettez le résultat dans un ruisseau, sans mise en mémoire tampon de l'intégralité du contenu du flux. Voici quelques exemples:
Fondamentalement tour du flux dans un
Iterator
afin d'appelerhasNext()
sur elle, et si elle est vraie, tournez leIterator
de retour dans uneStream
. C'est inefficace en ce que toutes les opérations suivantes sur le cours d'eau va passer par l'Itérateur dehasNext()
etnext()
méthodes, ce qui implique aussi que le flux est effectivement traitées de manière séquentielle (même si c'est plus tard transformé en parallèle). Toutefois, cela ne permet de tester les flux sans mise en mémoire tampon jusqu'à l'ensemble de ses éléments.Il y a sans doute une façon de faire cela à l'aide d'un
Spliterator
au lieu d'uneIterator
. Cela permet le retour de flux d'avoir les mêmes caractéristiques que le flux d'entrée, y compris l'exécution en parallèle.estimatedSize
etcharacteristics
pourrait même améliorer single-threaded performance. Il se trouve seulement que j'ai écrit leSpliterator
solution alors que vous étiez affichage de laIterator
solution...tryAdvance
avant laStream
n'est elle transforme les paresseux de la nature de laStream
dans un “partiellement paresseux” flux". Elle implique également que la recherche pour le premier élément n'est pas, en parallèle, une opération de plus que vous devez vous séparer d'abord et netryAdvance
sur la répartition des pièces, simultanément, en faire un véritable fonctionnement en parallèle, que j'ai compris. Si la seule exploitation du terminal estfindAny
ou similaire qui permettrait de détruire l'ensemble de laparallel()
demande.tryAdvance
avant que le flux ne et avez de l'envelopper chaque fraction de partie dans un proxy et de recueillir le “hasAny” de l'information de toutes les opérations simultanées sur votre propre et de s'assurer que la dernière concurrente l'opération déclenche l'exception, si le flux est vide. Des tas de trucs...Vous devez effectuer un terminal de l'opération sur le Stream de commande pour l'un des filtres à appliquer. Par conséquent, vous ne pouvez pas savoir si elle sera vide jusqu'à ce que vous consommer.
Meilleur que vous pouvez faire est de résilier le Flux avec un
findAny()
d'exploitation du terminal, qui va s'arrêter quand il en trouve un élément, mais si il n'en existe pas, il devra parcourir toutes les entrées de la liste pour le savoir.Ce serait seulement vous aider si l'entrée de la liste a de nombreux éléments, et l'un des premiers passe les filtres, puisque seulement un petit sous-ensemble de la liste devraient être consommés avant que vous savez que le Flux n'est pas vide.
Bien sûr, vous aurez toujours besoin de créer un nouveau Flux de données afin de produire la liste de sortie.
anyMatch(alwaysTrue())
, je pense que c'est le plus proche dehasAny
.anyMatch(alwaysTrue())
correspond parfaitement à la destinée de la sémantique de votrehasAny
, vous donnant unboolean
au lieu deOptional<T>
---mais nous sommes fractionnement de poils ici 🙂alwaysTrue
est une Goyave prédicat.anyMatch(e -> true)
ensuite.Je pense, devrait être suffisant pour carte un booléen
Dans le code c'est:
Suivantes Stuart idée de ce qui pourrait être fait avec un
Spliterator
comme ceci:Je pense que cela fonctionne avec le parallèle de cours d'eau comme la
stream.spliterator()
opération prendra fin le flux, et ensuite de le reconstruire comme l'exigeDans mon cas d'utilisation j'ai besoin d'un défaut
Stream
plutôt qu'une valeur par défaut. c'est assez facile à changer si ce n'est pas ce dont vous avez besoinSpliterator
je me demande comment les deux se comparer.