Using a Collector on a primitive stream

boxing, java, java-8, java-stream, primitive

Solution

Since `Map` is a Generic interface there is no way to create a `Map` without boxing. However, it doesn’t make sense to collect items into a `Map` at all when all you want is to create another stream (with just two values wrapped in a `Map.Entry`). You can just create the `Map.Entry` instances without collecting the values:

LongStream.range(1, maximum)
  .mapToObj(i->new AbstractMap.SimpleEntry<>(i, Iterators.longStream(new CollatzGenerator(i)).count()))
  .max(Comparator.comparingLong(Map.Entry::getValue))
  .get().getKey();

This still does auto-boxing but once you are at this point you can get rid of the `Map.Entry` too by creating an appropriate value holder class by yourself:

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; }
}

With this holder class you can process your data without boxing the `long`s:

LongStream.range(1, maximum)
  .mapToObj(i->new TwoLongs(i, Iterators.longStream(new CollatzGenerator(i)).count()))
  .max(Comparator.comparingLong(TwoLongs::getValue))
  .get().getKey();

Well, it is still some kind of boxing but creating one item (the `TwoLongs` instance) object instead of three (one `Map.Entry` and two `Long`s).

Problem

Is there in Java 8 any way to use Stream::collect(Collector) on primitive streams? Normally a `Stream<Integer>` as example has two methods for collecting: - `<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)` However `IntStream` only has one method for collecting: - `<R> R collect(Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R,R> combiner)` Now as example code I have the following: ``` @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(); } ``` As you can see I first box the primitives in order to be able to use a `Collectors.` method. Is there any way I can use primitives and still have the same code with `Collectors.toMap` ?

Original source