Java8: 修改forEach循环外部变量的引用

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

Java8: change the reference of the variable outside of forEach

问题

我尝试同时做两件事情:

1. 对列表中对象的特定字段进行求和

  1. AtomicReference<BigDecimal> doReqQtySum = new AtomicReference<>(BigDecimal.ZERO);
  2. AtomicReference<BigDecimal> boQtySum = new AtomicReference<>(BigDecimal.ZERO);
  3. models.forEach(detail -> {
  4. doReqQtySum.accumulateAndGet(detail.getDoReqQty(), (bg1, bg2) -> bg1.add(bg2));
  5. boQtySum.accumulateAndGet(detail.getBoQty(), (bg1, bg2) -> bg1.add(bg2));
  6. });

2. 从列表中过滤出一个对象

  1. DoRequestDetailModel originProductRequestDetail = models.stream()
  2. .filter(m -> m.getIsOriginProduct())
  3. .reduce((a, b) -> {
  4. throw new IllegalStateException();
  5. })
  6. .get();

我希望这段代码能够工作,但实际上它并不能:

  1. AtomicReference<BigDecimal> doReqQtySum = new AtomicReference<>(BigDecimal.ZERO);
  2. AtomicReference<BigDecimal> boQtySum = new AtomicReference<>(BigDecimal.ZERO);
  3. DoRequestDetailModel originProductRequestDetail = new DoRequestDetailModel();
  4. models.forEach(detail -> {
  5. doReqQtySum.accumulateAndGet(detail.getDoReqQty(), (bg1, bg2) -> bg1.add(bg2));
  6. boQtySum.accumulateAndGet(detail.getBoQty(), (bg1, bg2) -> bg1.add(bg2));
  7. if(detail.getIsOriginProduct()) {
  8. originProductRequestDetail = detail;
  9. }
  10. });

下面的代码可以完成任务:

  1. AtomicReference<BigDecimal> doReqQtySum = new AtomicReference<>(BigDecimal.ZERO);
  2. AtomicReference<BigDecimal> boQtySum = new AtomicReference<>(BigDecimal.ZERO);
  3. List<DoRequestDetailModel> tempList = new ArrayList<>();
  4. models.forEach(detail -> {
  5. doReqQtySum.accumulateAndGet(detail.getDoReqQty(), (bg1, bg2) -> bg1.add(bg2));
  6. boQtySum.accumulateAndGet(detail.getBoQty(), (bg1, bg2) -> bg1.add(bg2));
  7. if(detail.getIsOriginProduct()) {
  8. tempList.add(detail);
  9. }
  10. });

是否有更好的解决方案?

英文:

I try to do two things at once:<br/>

1.Sum values from specific field of the objects in a list

  1. AtomicReference&lt;BigDecimal&gt; doReqQtySum = new AtomicReference&lt;&gt;(BigDecimal.ZERO);
  2. AtomicReference&lt;BigDecimal&gt; boQtySum = new AtomicReference&lt;&gt;(BigDecimal.ZERO);
  3. models.forEach(detail -&gt; {
  4. doReqQtySum.accumulateAndGet(detail.getDoReqQty(), (bg1, bg2) -&gt; bg1.add(bg2));
  5. boQtySum.accumulateAndGet(detail.getBoQty(), (bg1, bg2) -&gt; bg1.add(bg2));
  6. });

2.Filter a object from list

  1. DoRequestDetailModel originProductRequestDetail = models.stream()
  2. .filter(m -&gt; m.getIsOriginProduct())
  3. .reduce((a, b) -&gt; {
  4. throw new IllegalStateException();
  5. })
  6. .get();

I would like this code, but it dosen't work:

  1. AtomicReference&lt;BigDecimal&gt; doReqQtySum = new AtomicReference&lt;&gt;(BigDecimal.ZERO);
  2. AtomicReference&lt;BigDecimal&gt; boQtySum = new AtomicReference&lt;&gt;(BigDecimal.ZERO);
  3. DoRequestDetailModel originProductRequestDetail = new DoRequestDetailModel();
  4. models.forEach(detail -&gt; {
  5. doReqQtySum.accumulateAndGet(detail.getDoReqQty(), (bg1, bg2) -&gt; bg1.add(bg2));
  6. boQtySum.accumulateAndGet(detail.getBoQty(), (bg1, bg2) -&gt; bg1.add(bg2));
  7. if(detail.getIsOriginProduct()) {
  8. originProductRequestDetail = detail;
  9. }
  10. });

The next code could be done

  1. AtomicReference&lt;BigDecimal&gt; doReqQtySum = new AtomicReference&lt;&gt;(BigDecimal.ZERO);
  2. AtomicReference&lt;BigDecimal&gt; boQtySum = new AtomicReference&lt;&gt;(BigDecimal.ZERO);
  3. List&lt;DoRequestDetailModel&gt; tempList = new ArrayList&lt;&gt;();
  4. models.forEach(detail -&gt; {
  5. doReqQtySum.accumulateAndGet(detail.getDoReqQty(), (bg1, bg2) -&gt; bg1.add(bg2));
  6. boQtySum.accumulateAndGet(detail.getBoQty(), (bg1, bg2) -&gt; bg1.add(bg2));
  7. if(detail.getIsOriginProduct()) {
  8. tempList.add(detail);
  9. }
  10. });

Is there a better solution ?

答案1

得分: 1

  1. 你还需要使用`AtomicReference`
  2. AtomicReference<BigDecimal> doReqQtySum = new AtomicReference<>(BigDecimal.ZERO);
  3. AtomicReference<BigDecimal> boQtySum = new AtomicReference<>(BigDecimal.ZERO);
  4. AtomicReference<DoRequestDetailModel> originProductRequestDetail = new AtomicReference<>(new DoRequestDetailModel());
  5. models.forEach(detail -> {
  6. doReqQtySum.accumulateAndGet(detail.getDoReqQty(), (bg1, bg2) -> bg1.add(bg2));
  7. boQtySum.accumulateAndGet(detail.getBoQty(), (bg1, bg2) -> bg1.add(bg2));
  8. if(detail.getIsOriginProduct()) {
  9. if(originProductRequestDetail.get()) throw new IllegalStateException();
  10. originProductRequestDetail.set(detail);
  11. }
  12. });
  13. 这是因为你在`forEach`内部调用的函数范围中更改了外部变量的引用。[这里][1]有一个相关的问题。
  14. [1]: https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value
英文:

You would have to use AtomicReference as well:

  1. AtomicReference&lt;BigDecimal&gt; doReqQtySum = new AtomicReference&lt;&gt;(BigDecimal.ZERO);
  2. AtomicReference&lt;BigDecimal&gt; boQtySum = new AtomicReference&lt;&gt;(BigDecimal.ZERO);
  3. AtomicReference&lt;DoRequestDetailModel&gt; originProductRequestDetail = new AtomicReference&lt;&gt;(new DoRequestDetailModel());
  4. models.forEach(detail -&gt; {
  5. doReqQtySum.accumulateAndGet(detail.getDoReqQty(), (bg1, bg2) -&gt; bg1.add(bg2));
  6. boQtySum.accumulateAndGet(detail.getBoQty(), (bg1, bg2) -&gt; bg1.add(bg2));
  7. if(detail.getIsOriginProduct()) {
  8. if(originProductRequestDetail.get()) throw new IllegalStateException();
  9. originProductRequestDetail.set(detail);
  10. }
  11. });

It's because you're changing a reference of an outside variable in the scope of the function invoked inside forEach. Here is a related question.

huangapple
  • 本文由 发表于 2020年3月16日 17:42:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/60703560.html
匿名

发表评论

匿名网友

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

确定