Utiliser Java 8 stream ce qui est la meilleure façon pour mapper un List<Integer>
lorsque vous n'avez pas de sortie pour l'entrée Integer?
Renvoyez simplement null? Mais maintenant, la taille de ma liste de sortie sera plus petite que ma taille d'entrée ...
List<Integer> input = Arrays.asList(0,1,2,3);
List<Integer> output = input.stream()
.map(i -> {
Integer out = crazyFunction(i);
if(out == null || out.equals(0))
return null;
return Optional.of(out);
})
.collect(Collectors.toList());
Je ne comprends pas pourquoi vous (et toutes les réponses) compliquez les choses. Vous avez une opération de mappage et une opération de filtrage. La manière la plus simple consiste donc à appliquer ces opérations l'une après l'autre. Et à moins que votre méthode ne retourne déjà un Optional
, il n'est pas nécessaire de traiter Optional
.
input.stream().map(i -> crazyFunction(i))
.filter(out -> out!=null && !out.equals(0))
.collect(Collectors.toList());
Il peut être simplifié pour
input.stream().map(context::crazyFunction)
.filter(out -> out!=null && !out.equals(0))
.collect(Collectors.toList());
Mais vous semblez avoir une question plus théorique sur le type de List
à générer, un avec des espaces réservés pour les valeurs absentes ou un avec une taille différente de la liste d'entrée.
La réponse simple est: ne pas générer de liste. Un List
n'est pas une fin en soi, vous devez donc considérer pour quel type de opération vous avez besoin de cette liste (ou de son contenu) et appliquer l'opération correctement comme opération terminale du flux . Ensuite, vous avez votre réponse car l'opération dicte si les valeurs absentes doivent être filtrées ou représentées par une valeur spéciale (et quelle valeur doit être).
Ce pourrait être une réponse différente pour différentes opérations…
Remplacez l'appel map
par flatMap
. L'opération map
produit une valeur de sortie par valeur d'entrée, tandis que l'opération flatMap
produit un nombre quelconque de valeurs de sortie par valeur d'entrée - inclut zéro.
Le moyen le plus simple est probablement de remplacer le chèque comme ceci:
List<Integer> output = input.stream()
.flatMap(i -> {
Integer out = crazyFunction(i);
if (out == null || out.equals(0))
return Stream.empty();
else
return Stream.of(out);
})
.collect(Collectors.toList());
Un refactoring supplémentaire pourrait changer crazyFunction
pour qu'il retourne un Optional
(probablement OptionalInt
). Si vous l'appelez depuis map
, le résultat est un Stream<OptionalInt>
. Ensuite, vous devez flatMap
ce flux pour supprimer les options vides:
List<Integer> output = input.stream()
.map(this::crazyFunctionReturningOptionalInt)
.flatMap(o -> o.isPresent() ? Stream.of(o.getAsInt()) : Stream.empty())
.collect(toList());
Le résultat de flatMap
est un Stream<Integer>
qui contient les int
s, mais c'est OK puisque vous allez les envoyer dans un List
. Si vous n'alliez pas encadrer les valeurs int
en List
, vous pourriez convertir les Stream<OptionalInt>
vers un IntStream
en utilisant ce qui suit:
flatMapToInt(o -> o.isPresent() ? IntStream.of(o.getAsInt()) : IntStream.empty())
Pour plus de détails sur la gestion des flux d'options, voir cette question et ses réponses .
Variantes plus simples de la réponse de @Martin Magakian:
List<Integer> input = Arrays.asList(0,1,2,3);
List<Optional<Integer>> output =
input.stream()
.map(i -> crazyFunction(i)) // you can also use a method reference here
.map(Optional::ofNullable) // returns empty optional
// if original value is null
.map(optional -> optional.filter(out -> !out.equals(0))) // return empty optional
// if captured value is zero
.collect(Collectors.toList())
;
List<Integer> outputClean =
output.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList())
;
Vous pouvez encapsuler la sortie dans un Facultatif qui peut ou non contenir une valeur non nulle.
Avec une sortie: return Optional.of(out);
Sans sortie: return Optional.<Integer>empty();
Vous devez encapsuler dans une option car un tableau ne peut contenir aucune valeur nulle .
List<Integer> input = Arrays.asList(0,1,2,3);
List<Option<Integer>> output = input.stream()
.map(i -> {
Integer out = crazyFunction(i);
if(out == null || out.equals(0))
return Optional.<Integer>empty();
return Optional.of(out);
})
.collect(Collectors.toList());
Cela garantira que input.size() == output.size()
.
Plus tard, vous pouvez exclure l'option facultative vide en utilisant:
List<Integer> outputClean = output.stream()
.filter(Optional::isPresent)
.map(i -> {
return i.get();
})
.collect(Collectors.toList());