In the input, I have a list of Integers and Strings together.
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 error:
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
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();
There's no need to do iteration twice, and because in the source list you except only Integer
and String
types filter can be discarded. So your method eventually boils down to a couple of lines:
public int sum(List<?> mixed) {
return mixed.stream()
.mapToInt(x -> x instanceof Integer? (Integer) x : Integer.parseInt((String) x))
.sum();
}
Note:
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 it makes sense if your intention was not to return a value in case of invalid data but to emphasize it with an exception.String | Number
) and runtime checks using instanceof
but Java cares about type-safety and in the real-life scenario you shouldn't create such a mixed collection in the first place. It was probably done using a row-type collection or Object
class as a generic type in order to circumvent the compiler. Instead, it would be cleaner and less error-prone to process the source of string values separately like that: strSource.stream().map(Integer::parseInt).collect(Collectors.toList());
As a consequence sum()
method will be exempted from the redundant responsibility and contracts to:
list.stream().mapToInt(Integer::intValue).sum();