Utiliser un collecteur sur un flux primitif
-
21-12-2019 - |
Question
Existe-t-il dans Java 8 un moyen d'utiliser Stream :: collect (collecteur) sur des streams primitifs ?
Normalement un Stream<Integer>
à titre d'exemple, il existe deux méthodes de collecte :
<R,A> R collect(Collector<? super T,A,R> collector)
<R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)
Cependant IntStream
n'a qu'une seule méthode de collecte :
Maintenant, comme exemple de code, j'ai ce qui suit :
@Override
public void run() {
result = LongStream.range(1, maximum).boxed()
.collect(Collectors.toMap(i -> i, i -> (int)Iterators.longStream(new CollatzGenerator(i)).count()))
.entrySet().stream()
.max(Comparator.comparingLong(Map.Entry::getValue))
.get().getKey();
}
Comme vous pouvez le voir, j'ai d'abord boxé les primitives afin de pouvoir utiliser un Collectors.
méthode.
Existe-t-il un moyen d'utiliser des primitives tout en conservant le même code avec Collectors.toMap
?
La solution
Depuis Map
est une interface générique, il n'y a aucun moyen de créer un Map
sans boxe.Cependant, cela n’a pas de sens de rassembler des objets dans un Map
du tout quand tout ce que vous voulez est de créer un autre flux (avec seulement deux valeurs enveloppées dans un Map.Entry
).Vous pouvez simplement créer le Map.Entry
instances sans collecter les valeurs :
LongStream.range(1, maximum)
.mapToObj(i->new AbstractMap.SimpleEntry<>(i, Iterators.longStream(new CollatzGenerator(i)).count()))
.max(Comparator.comparingLong(Map.Entry::getValue))
.get().getKey();
Cela fait toujours de l'auto-boxing, mais une fois que vous êtes à ce stade, vous pouvez vous débarrasser du Map.Entry
également en créant vous-même une classe de détenteurs de valeur appropriée :
static final class TwoLongs {
final long key, value;
TwoLongs(long k, long v) { key=k; value=v; }
public long getKey() { return key; }
public long getValue() { return value; }
}
Avec cette classe de titulaire, vous pouvez traiter vos données sans encadrer le long
s :
LongStream.range(1, maximum)
.mapToObj(i->new TwoLongs(i, Iterators.longStream(new CollatzGenerator(i)).count()))
.max(Comparator.comparingLong(TwoLongs::getValue))
.get().getKey();
Eh bien, c'est toujours une sorte de boxe, mais la création d'un élément (le TwoLongs
instance) objet au lieu de trois (un Map.Entry
et deux Long
s).
Autres conseils
long result = LongStream.range(0, 9)
.mapToObj(i -> new long[]{i, i})
.max(Comparator.comparingLong(pair -> pair[1]))
.get()[0];