在Java流中执行Reduce操作的异常[重复]

问题描述 投票:0回答:3

我是Java 8的新手,在下面的示例中,我创建了一个Map,其keyvalue为String,value为ArrayList of integer。

Map<String,List<Integer>> mapLstInteger=new HashMap<String,List<Integer>>() {
            {
                put("A",Arrays.asList(1,2,3));
                put("B",Arrays.asList(4,5,6));
                put("C",Arrays.asList(7,8,9));
            }
        };

我写下面的代码来对每个键执行arrayList元素的总和,并试图将sum值存储在单独的ArrayList中。

List<Integer> sumLst=mapLstInteger.entrySet().stream().map(e->e.getValue())
        .reduce((inputLst, outputLst)->{
            int sum=0;
            for(int count=0;count<inputLst.size();count++)
            {
                sum=sum+inputLst.get(count);
            }
            outputLst.add(sum);
            return outputLst;
        }).get();

当我尝试执行以下代码时,我遇到异常。

java.util.AbstractList.add(AbstractList.java:148)中的线程“main”java.lang.UnsupportedOperationException中的异常,位于com.calculation.sum.client的java.util.AbstractList.add(AbstractList.java:108)。 java.util.stream.ReduceOps上的Client.lambda $ 1(Client.java:43)$ 2ReducingSink.accept(ReduceOps.java:123)at java.util.stream.ReferencePipeline $ 3 $ 1.accept(ReferencePipeline.java:193)at at Java.util.HashMap $ EntrySpliterator.forEachRemaining(HashMap.java:1696),java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481),java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) at java.util.stream.ReduceOps $ ReduceOp.evaluateSequential(ReduceOps.java:708)at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)at java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java) :479)at com.calculation.sum.client.Client.main(Client.java:37)

任何人都可以让我知道我在上面的代码中做错了什么>

java java-8 java-stream
3个回答
0
投票

之所以发生这种情况,是因为你使用的是AbstractList生产的原始Arrays.asListList<T>抽象实现不允许添加或删除元素。

public void add(int index, E element) {
    throw new UnsupportedOperationException();
}

但无论如何,回到你的问题。你也可以通过自定义Collector获得你想要的东西,在那里你可以提供你的自定义List<T>实现,无论是ArrayListLinkedList,还是你觉得更好的任何东西。

mapLstInteger.values()
             .stream()
             .collect(Collector.of(
                     () -> new ArrayList<>(),  // Supplier
                     (output, toSumList) -> {  // Accumulator
                         output.add(toSumList.stream()
                                             .mapToInt(Integer::intValue)
                                             .sum());
                     },
                     // The Combiner implementation will be called
                     // in case of a "parallel" Stream. 
                     // No need to worry about it here. 
                     // But in case, we would need to merge the partial results
                     (output, partial) -> {
                        output.addAll(partial);
                        return output;
                     }
             ));

一个更简洁的版本是

mapLstInteger.values()
             .stream()
             .map(l -> l.stream().mapToInt(Integer::intValue).sum())
             .collect(Collectors.toCollection(ArrayList::new));

这将正确输出[6, 15, 24]


3
投票

首先你使用Arrays::asList,它被记录为返回由指定数组支持的固定大小列表,我认为固定大小应该告诉你你做错了什么。

比你正在使用反模式创建一个HashMap - 通过创建一个匿名的内部类,通过HashMap扩展Map<String,List<Integer>> mapLstInteger=new HashMap<String,List<Integer>>()....

比,你违反了reduce的规格,它应该一直返回一个新的对象,但你总是投入到outputLst

然而,当你关心的只是它的价值时,你正在创造一个Map - 在这种情况下创造一个List<List<Integer>>

根据你的代码,即使是我在下面写的代码来对每个键执行arrayList元素的总和也是不正确的。我会想到我想要实现的实际事情,然后尝试去做,如果我是你。


0
投票

你应该做以下事情:

    mapLstInteger.values().stream()
                 .flatMapToInt(list -> list.stream()
                                           .filter(Objects::nonNull)
                                           .mapToInt(Integer::intValue)).sum();

添加了过滤器以确保在null整数的情况下不会获得空指针。作为一般规则,如果您被迫在流中使用传统循环,那么您可能做错了。通过将int列表变为int值,我们可以轻松地总结,如上所示。

最初误解了一个问题,认为你想要的总体总和是一个实际问题的更新解决方案:

    mapLstInteger.values().stream()
                 .map(list -> list.stream()
                                  .filter(Objects::nonNull)
                                  .mapToInt(Integer::intValue).sum())
                                  .collect(Collectors.toList());
© www.soinside.com 2019 - 2024. All rights reserved.