You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Java Stream处理有序ArrayList,生成带差值的RecordB

需求实现:用Java Stream将RecordA列表转换为RecordB列表

给定的Java类定义

import java.util.*;  

class RecordA{
    Integer id;
    Integer value;
    
    RecordA(Integer id, Integer value) {
        this.id = id;
        this.value = value;
    }
    
    Integer getId() { return id;}
    Integer getValue() { return value;}
}

class RecordB {
    Integer id;
    Integer value;
    Integer diff;
    
    RecordB(Integer id, Integer value, Integer diff) {
        this.id = id;
        this.value = value;
        this.diff = diff;
    }
    
    Integer getId() { return id;}
    Integer getValue() { return value;}
    Integer getDiff() { return diff;}
}

class HelloWorld {
    public static void main(String[] args) {
        List<RecordA> listA = new ArrayList<>();
        RecordA recordA1 = new RecordA(1,10);
        listA.add(recordA1);
        RecordA recordA2 = new RecordA(2,15);
        listA.add(recordA2);
        RecordA recordA3 = new RecordA(3,25);
        listA.add(recordA3);
        RecordA recordA4 = new RecordA(4,30);
        listA.add(recordA4);
        
        System.out.println(listA.size());
    }
}

需求说明

现有一个存储有序RecordA实例的ArrayList,RecordA包含id和value属性。需要遍历该列表,对比当前元素与前一个元素的value值,计算两者的差值(当前value - 前一个value,第一条记录差值为0),并将结果映射为RecordB实例(包含相同的id、value以及计算得到的diff)。最终得到的RecordB列表应如下:

  • 1, 10, 0 //(10-0)
  • 2, 15, 5 //(15-10)
  • 3, 25, 10 //25-15
  • 4, 30, 5 //30-25

要求避免使用普通for循环和prev_val变量,通过Java Stream实现该需求。

解决方案

提供两种符合要求的实现方式:

方式一:利用IntStream遍历索引

通过IntStream.range生成列表的索引范围,根据索引获取当前元素和前一个元素(第一条元素特殊处理),直接映射为RecordB:

import java.util.stream.Collectors;
import java.util.stream.IntStream;

// ... 其他类定义不变

List<RecordB> listB = IntStream.range(0, listA.size())
    .mapToObj(index -> {
        RecordA current = listA.get(index);
        int prevValue = index == 0 ? 0 : listA.get(index - 1).getValue();
        int diff = current.getValue() - prevValue;
        return new RecordB(current.getId(), current.getValue(), diff);
    })
    .collect(Collectors.toList());

方式二:利用AtomicReference维护前值状态(仅适用于串行流)

如果不想依赖索引,可以使用AtomicReference保存前一个元素的value,在流处理中更新状态:

import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

// ... 其他类定义不变

AtomicReference<Integer> prevValueRef = new AtomicReference<>(0);
List<RecordB> listB = listA.stream()
    .map(recordA -> {
        int currentValue = recordA.getValue();
        int diff = currentValue - prevValueRef.get();
        RecordB recordB = new RecordB(recordA.getId(), currentValue, diff);
        prevValueRef.set(currentValue);
        return recordB;
    })
    .collect(Collectors.toList());

注意:这种方式仅支持串行流,并行流会因竞态条件导致状态混乱,而原列表是有序的,串行流完全满足需求。

验证代码

将上述任意一种实现替换HelloWorld类的main方法即可验证结果,示例如下:

public static void main(String[] args) {
    List<RecordA> listA = new ArrayList<>();
    listA.add(new RecordA(1,10));
    listA.add(new RecordA(2,15));
    listA.add(new RecordA(3,25));
    listA.add(new RecordA(4,30));

    // 使用方式一的实现
    List<RecordB> listB = IntStream.range(0, listA.size())
        .mapToObj(index -> {
            RecordA current = listA.get(index);
            int prevValue = index == 0 ? 0 : listA.get(index - 1).getValue();
            int diff = current.getValue() - prevValue;
            return new RecordB(current.getId(), current.getValue(), diff);
        })
        .collect(Collectors.toList());

    // 输出结果
    listB.forEach(b -> System.out.printf("%d, %d, %d%n", b.getId(), b.getValue(), b.getDiff()));
}

执行后会输出:

1, 10, 0
2, 15, 5
3, 25, 10
4, 30, 5

内容的提问来源于stack exchange,提问作者Grafana Next

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 02:10:40