当前位置: 首页 > 知识库问答 >
问题:

是累加器的减少在Java8允许修改其参数?

匡翰
2023-03-14

在Java 8中,Stream有一个方法reduce:

T reduce(T identity, BinaryOperator<T> accumulator);

累加器运算符是否允许修改其任一参数?我不这么认为,因为JavaDoc说累加器应该是非干涉的,尽管所有示例都谈到修改集合,而不是修改集合的元素。

举个具体的例子,如果我们有

 integers.reduce(0, Integer::sum);

假设整数是可变的,那么可以通过将第二个参数的值添加到第一个参数中(就地)来修改第一个参数吗?

我想不会,但我也想举一个例子,说明这种干扰在哪里会引起问题。

共有2个答案

郑富
2023-03-14
  static void accumulatorTest() {
     ArrayList<Point> points = new ArrayList<>();
     points.add(new Point(5, 6));
     points.add(new Point(0, 6));
     points.add(new Point(1, 9));
     points.add(new Point(4, 16));
     BinaryOperator<Point> sumPoints = new BinaryOperator<Point>() {
        public Point apply(Point p1, Point p2) {
           p2.x += p1.x;
           p2.y += p1.y;
           return new Point(p2); //return p2 and the list is transformed into running total
        }
     };
     Point sum = points.stream().reduce(new Point(0, 0), sumPoints); 
     System.out.println(sum);
     System.out.println(points);
  }

答案是正确的;我们得到所有x和y坐标的总和。修改原始列表,并通过输出确认:

Java语言awt。点[x=10,y=37][java.awt.java.x=5,y=6]点。awt。点[x=5,y=12],爪哇。awt。点[x=6,y=21],爪哇。awt。点[x=10,y=37]]

葛景龙
2023-03-14

不。累加器不应该修改它的参数;它接受两个值并产生一个新值。如果您想在累加过程中使用突变(例如,将字符串累加到StringBuffer而不是连接),请使用为此设计的Stream.collect()

下面是一个代码示例,如果您尝试此操作,它会生成错误的答案。假设您想对假设的MutableInteger类进行加法:

// Don't do this
MutableInteger result = stream.reduce(new MutableInteger(0), (a,b) -> a.add(b.get()));

得到错误答案的一个原因是,如果我们并行分解计算,那么现在两个计算共享相同的可变起始值。请注意:

a + b + c + d
= 0 + a + b + 0 + c + d  // 0 denotes identity
= (0 + a + b) + (0 + c + d) // associativity

因此,我们可以自由分割流,计算部分和,然后将结果相加。但是,如果它们共享相同的标识值,并且该值由于其中一个计算而发生变异,则另一个可能以错误的值开始。

 类似资料:
  • 问题内容: 在Java 8中,Stream有一种减少方法: 是否允许累加器运算符修改其两个参数之一?我猜不是因为JavaDoc说累加器应该是NonInterfering,尽管所有示例都提到修改集合,而不是修改集合的元素。 因此,举一个具体的例子,如果我们有 并假设暂时是可变的,是否可以通过向其添加第二个参数的值来修改其第一个参数? 我猜不是,但是我也想举个例子说明这种干扰会引起什么问题。 问题答案

  • 在研究这个问题时,我注意到GCC(V4.7)的实现在取值时移动了参数。下面的代码显示了此行为: 在这里,我们看到执行了的一个副本(这似乎是合理的,因为的参数是由value取的),但接下来有两个移动。由于是在的副本上操作的,因此它移动参数的事实可以看作是一个不重要的实现细节。但是,当将与一起使用时,此行为会引起一些麻烦: 这种行为是否为标准所允许?是否允许移动其参数?如果是这样的话,我们可以将返回的

  • 您可以使用allowedKeys选项允许修饰键和{{action}}助手一起使用。 有时, {{action}}帮助器会使用按下的修改键来丢弃单击事件。 因此, allowedKeys选项指定不应忽略哪些键。 语法 (Syntax) <button {{action 'action-name' allowedKeys = "alt"}}></button> 例子 (Example) 下面给出的示

  • 我目前正在读O'reilly的《Java 8 Lambdas》是一本非常好的书。我遇到了这样一个例子。 我有一个 这会产生正确的输出。 我的问题是将reduce方法视为最后一个参数,即二进制运算符 我的问题是这个参数用于哪个?如果我改变 如果我传递NULL,则输出相同,然后返回N.P.E。 for此参数用于什么? 更新 为什么如果我在上运行它,我会收到不同的结果? 第一次运行。 第二次运行 第三次

  • 在这种实现中,TableModelEvent中的rowIndex和colIndex与在第二次事件时的模型状态之间存在不一致,以及在MyTableModel对象上调用update(int[],String)方法所收到的后续事件。 我相信问题来自于这样一个事实,即我试图修改事件源,同时接收基于该源的某个特定状态生成的事件,但如果指示模式变化的任何事件与模型修改交织在一起,以及基于模型的旧状态生成的其他

  • 问题内容: 我已经与进行了大量合作,最近在添加几个月时遇到了我认为是错误的错误。经过一些研究,看来它不是错误,而是按预期工作。根据此处找到的文档: Example#2当增加或减少月份时要当心 谁能证明为什么这不被认为是错误? 此外,是否有人有任何优雅的解决方案来纠正此问题,并使+1个月按预期工作,而不是按预期工作? 问题答案: 为什么不是错误: 当前行为是正确的。内部发生以下情况: 将月份数(最初