找不到适合 collect/reduce 的方法 - 无法使用 stream() 对整数列表求和

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

在输入中,我有一个整数和字符串列表。

第一个流工作正常,第二个流工作直到过滤器,我不知道为什么。我的代码:

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

我有这个错误:

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

编译器无法推断类型。您需要像在第一步中那样进行投射:

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

或者如果你想使用方法参考

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

在第二个流中应用方法引用 Integer::intValue 之前,您必须 cast 流的元素为 Integer 类型。

由于您只想获得整数基元的总和,因此无需求助于收集器的帮助,相反,您可以将对象流强制为 IntStream 并应用 sum()方法。

        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();

不需要重复两次,因为在源列表中你只能丢弃 IntegerString 类型的过滤器。所以你的方法最终归结为几行:

    public int sum(List<?> mixed) {
        return mixed.stream()
                .mapToInt(x -> x instanceof Integer? (Integer) x : Integer.parseInt((String) x))
                .sum();
    }

注:

  • 因为 Integer.parseInt() 可能会导致 NumberFormatException 如果转换失败,如果源列表至少包含一个 string,则流将不会产生值除了数字之外的其他符号。这就是所谓的 fail-fast 实现 如果您的意图不是 return 一个值以防无效数据而是 例外强调.
  • 另一件值得指出的事情是,这段代码只有作为练习才有价值。在某些语言中,您可能会遇到联合类型 (String | Number) 和使用 instanceof 的运行时检查,但 Java 关心 type-safety 而在 real-life 场景中,您首先不应创建这样的混合集合。它可能是使用 row-type 集合或 Object class 作为泛型类型完成的,以便 绕过编译器 。相反,像这样单独处理字符串值的来源会更干净、更少 error-prone:
   strSource.stream().map(Integer::parseInt).collect(Collectors.toList());

因此 sum() 方法将免除多余的责任,并与以下合同签订合同:

   list.stream().mapToInt(Integer::intValue).sum();