Search code examples
javajava-stream

Unable to apply Collectors.groupingBy on an IntStream


This code works fine with other objects, but not int, even though those are autoboxed to Integer. I am unable to understand the error message.

jshell> String[] names = new String[]{"apple", "apple", "banana"};
names ==> String[3] { "apple", "apple", "banana" }

jshell> Map<String, Integer> stringMap = Arrays.stream(names).collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(e -> 1)));
stringMap ==> {banana=1, apple=2}

jshell> int[] nums = new int[]{1,2,3,3,4};
nums ==> int[5] { 1, 2, 3, 3, 4 }

jshell> Map<Integer, Integer> numsMap = Arrays.stream(nums).collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(e -> 1)));
|  Error:
|  method collect in interface java.util.stream.IntStream cannot be applied to given types;
|    required: java.util.function.Supplier<R>,java.util.function.ObjIntConsumer<R>,java.util.function.BiConsumer<R,R>
|    found: java.util.stream.Collector<java.lang.Object,capture#1 of ?,java.util.Map<java.lang.Object,java.lang.Integer>>
|    reason: cannot infer type-variable(s) R
|      (actual and formal argument lists differ in length)
|  Map<Integer, Integer> numsMap = Arrays.stream(nums).collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(e -> 1)));
|                                  ^-------------------------^


Solution

  • tl;dr

    Add a call to .boxed.

    No auto-boxing here

    As Commented by Pshemo, IntStream does not auto-box. You are working with int primitives only in an IntStream.

    Your code would work if you simply 👉🏼 insert a call to IntStream#boxed. Your stream of int primitive values then becomes a stream of Integer objects.

    int[] ints = new int[] { 1 , 2 , 3 , 3 , 4 };
    Map < Integer , Integer > integersMap =
            Arrays
                    .stream ( ints )
                    .boxed ( )  // ⬅️
                    .collect (
                            Collectors.groupingBy (
                                    Function.identity ( ) ,
                                    Collectors.summingInt ( ( Integer i ) -> 1 )
                            )
                    );
    

    stringMap = {banana=1, apple=2}

    And, for reference, the String code.

    String[] names = new String[] { "apple" , "apple" , "banana" };
    Map < String , Integer > stringMap =
            Arrays
                    .stream ( names )
                    .collect (
                            Collectors.groupingBy (
                                    Function.identity ( ) ,
                                    Collectors.summingInt ( ( String s ) -> 1 )
                            )
                    );
    

    integersMap = {1=1, 2=1, 3=2, 4=1}