Home > database >  No suitable method found for collect/reduce - Can't sum a list of Integers with stream()
No suitable method found for collect/reduce - Can't sum a list of Integers with stream()

Time:02-20

In input i have a list of Integers and Strings togheter. The first stream works fine, the second stream works until the filter, i don't know why. My code:

import java.util.List;
import java.util.stream.*;

public class MixedSum {

    public int sum(List<?> mixed) {

        int m = mixed.stream().filter(x -> x instanceof String).map(x -> Integer.parseInt((String) x)).collect(Collectors.summingInt(Integer::intValue));
        int n = mixed.stream().filter(x -> x instanceof Integer).collect(Collectors.summingInt(Integer::intValue));

        return m   n;
    }
}

I have this problem:

error: no suitable method found for collect(Collector<Integer,CAP#1,Integer>) int n = mixed.stream().filter(x -> x instanceof Integer).collect(Collectors.summingInt(Integer::intValue)); ^ method Stream.<R#1>collect(Supplier<R#1>,BiConsumer<R#1,? super CAP#2>,BiConsumer<R#1,R#1>) is not applicable (cannot infer type-variable(s) R#1 (actual and formal argument lists differ in length)) method Stream.<R#2,A>collect(Collector<? super CAP#2,A,R#2>) is not applicable (inferred type does not conform to upper bound(s) inferred: CAP#2 upper bound(s): Integer,Object) where R#1,T,R#2,A are type-variables: R#1 extends Object declared in method <R#1>collect(Supplier<R#1>,BiConsumer<R#1,? super T>,BiConsumer<R#1,R#1>) T extends Object declared in interface Stream R#2 extends Object declared in method <R#2,A>collect(Collector<? super T,A,R#2>) A extends Object declared in method <R#2,A>collect(Collector<? super T,A,R#2>) where CAP#1,CAP#2 are fresh type-variables: CAP#1 extends Object from capture of ? CAP#2 extends Object from capture of ? 1 error

CodePudding user response:

The compiler can't infer the type. You need to cast it like you do it in your first step:

int n = mixed.stream()
             .filter(x -> x instanceof Integer)
             .map(x -> (int) x)
             .collect(Collectors.summingInt(Integer::intValue));

or if you want to use method reference

int n = mixed.stream()
             .filter(x -> x instanceof Integer)
             .map(Integer.class::cast)
             .collect(Collectors.summingInt(Integer::intValue));

CodePudding user response:

Before applying the method reference Integer::intValue in the second stream you have to cast the elements of the stream to the Integer type.

Since you want to get just a sum of integer primitives there is no need to resort to the help of collectors, instead, you can coerce a stream of objects to IntStream and apply the sum() method.

        int m = mixed.stream()
                .filter(x -> x instanceof String)
                .mapToInt(x -> Integer.parseInt((String) x))
                .sum();
        
        int n = mixed.stream()
                .filter(x -> x instanceof Integer)
                .mapToInt(x -> (Integer) x)
                .sum();

And there's no need to do iteration twice, so your sum() method eventually can look like this (remove the filter() if you don't expect any type except Integer and String):

    public int sum(List<?> mixed) {
        return mixed.stream()
                .filter(x -> x instanceof String || x instanceof Integer) // can be removed if there's no need to discard other types
                .mapToInt(x -> x instanceof Integer? (Integer) x : Integer.parseInt((String) x))
                .sum();
    }

Note:

  • Becouse Integer.parseInt() might cause NumberFormatException if conversion fails the stream will not produce the value if the source list contains at least one string that is comprised of other symbols apart from digits. That's what is called a fail-fast implementation and might make sense it was your intention - not to return a value if there are some invalid data but emphasize it with an exception.
  • Related