如何使用Java流将currentElement的值与前一个值相结合。

huangapple go评论75阅读模式
英文:

How can we combine currentElement's value with prior one using java stream

问题

我只想尝试将下面的代码转换成Java 8,但不知道如何做到这一点,这是我的代码:

BigDecimal previousVal = BigDecimal.ZERO;
for (SequenceHistory ele : histories) {
  Row row = new Row();
  previousVal = previousVal.add(ele.getSeqTotal() == null ? BigDecimal.ZERO : ele.getSeqTotal());
  row.setTotal(previousVal);
  rows.add(row);
}

我使用了类级变量来实现,但由于构造函数在多次调用中共享,而值也会在其他调用中保留,所以它没有起作用。任何建议都将不胜感激。

英文:

I am just trying to convert below code in java 8, But unable to figure out how to do that here is my code:

BigDecimal previousVal = BigDecimal.ZERO;
for (SequenceHistory ele : histories) {
  Row row = new Row();
  previousVal = previousVal.add(ele.getSeqTotal() == null ? BigDecimal.ZERO : ele.getSeqTotal());
  row.setTotal(previousVal);
  rows.add(row);
}

I did it by using class level variable but its didn't work because constructor issharing in multiple calls, and val was persist for other calls as well. Any suggestion would be appreciated.

答案1

得分: 2

我不建议在这里使用[tag:java-stream](下面有解释)。

存在一个问题,你想要迭代List<SequenceHistory>,并且在每次迭代中递增并使用另一个值。由于BigDecimal是不可变的,所以在lambda表达式中很难进行递增操作,也不能在lambda表达式中重新赋值,因为lambda表达式中使用的变量必须是有效final的要求。因此,你可以使用AtomicReference<T>,它确保变量本身适用于lambda表达式,并且封装了可变操作。

AtomicReference<BigDecimal> ref = new AtomicReference<>(BigDecimal.ZERO);
List<Row> rows = histories.stream()
    .map(SequenceHistory::getSeqTotal)                          
    .map(total -> total == null ? BigDecimal.ZERO : total)      
    .map(total -> ref.accumulateAndGet(total, BigDecimal::add)) 
    .map(total -> new Row(total))                               
    .collect(Collectors.toList());                             

我将Row类的setter更改为构造函数,以简洁起见。否则,将使用.map(total -> { Row row = new Row(); row.setTotal(total); return row; })


结论: 此解决方案说明了为什么在依赖于使用并发实现进行序列处理的可变操作结果时,[tag:java-stream]不适用。

英文:

I don't recommend to enforce [tag:java-stream] here (explanation below).

There is a problem that you want to iterate List&lt;SequenceHistory&gt; and increment and use another value in the meanwhile with each iteration. This increment cannot happen easily in the lambda expression because BigDecimal is immutable and you cannot reassign in the lambda expression such a new value since there is a requirement the variables used in the lambda expression must be effectively final. For this reason, you can use AtomicReference&lt;T&gt; that assures the variable itself is qualified for the lambda expression and the mutability operations are encapsulated.

AtomicReference&lt;BigDecimal&gt; ref= new AtomicReference&lt;&gt;(BigDecimal.ZERO);
List&lt;Row&gt; rows =  histories.stream()
    .map(SequenceHistory::getSeqTotal)                          // get the total
    .map(total -&gt; total == null ? BigDecimal.ZERO : total)      // value or ZERO
    .map(total -&gt; ref.accumulateAndGet(total, BigDecimal::add)) // increment and get
    .map(total -&gt; new Row(total))                               // create a new Row
    .collect(Collectors.toList());                              // collect as a List

I changed the setter of the clas Row to a constructor for the sake of brevity. .map(total -&gt; { Row row = new Row(); row.setTotal(total); return row; }) would be used otherwise.


Conclusion: This solution demonstrates why [tag:java-stream] is not suitable for such processing where you rely on the result of mutable operations using concurrent implementations for sequence processing.

huangapple
  • 本文由 发表于 2020年4月7日 10:49:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/61072055.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定