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

如何将List<Data>转换为字段更少的List<SmallerData>?能否无需foreach提升效率?

将List转换为List的实现方案及效率优化

首先先明确两个类的完整定义(包含必要的构造方法、getter,用于字段读取和对象实例化):

// Data类
public class Data {
    private Long id;
    private String name;
    private Integer age;
    private Double height;

    // 全参构造
    public Data(Long id, String name, Integer age, Double height) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.height = height;
    }

    // 仅提供转换需要的getter
    public String getName() { return name; }
    public Integer getAge() { return age; }
}

// SmallerData类
public class SmallerData {
    private String name;
    private Integer age;

    // 对应字段的构造方法
    public SmallerData(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    // 可选:toString方便输出验证
    @Override
    public String toString() {
        return "SmallerData{name='" + name + "', age=" + age + "}";
    }
}

1. 基础实现:显式foreach循环

这是最直观的方式,但也是你想避免的写法,仅作参考:

List<Data> dataList = service.findAll();
List<SmallerData> smallerDataList = new ArrayList<>(dataList.size());

for (Data data : dataList) {
    smallerDataList.add(new SmallerData(data.getName(), data.getAge()));
}

// 输出结果
smallerDataList.forEach(System.out::println);

2. 无显式foreach的实现:Java Stream API

Stream API可以完全避免手写foreach循环,同时支持并行处理提升大数据量下的效率:

串行Stream(适合小数据量)

代码简洁,效率和显式foreach几乎一致:

List<Data> dataList = service.findAll();
List<SmallerData> smallerDataList = dataList.stream()
    .map(data -> new SmallerData(data.getName(), data.getAge()))
    .collect(Collectors.toList());

// 输出结果
smallerDataList.forEach(System.out::println);

并行Stream(适合大数据量)

利用多核CPU并行处理,数据量越大提升越明显:

List<Data> dataList = service.findAll();
List<SmallerData> smallerDataList = dataList.parallelStream()
    .map(data -> new SmallerData(data.getName(), data.getAge()))
    .collect(Collectors.toList());

注意:小数据量下并行Stream的线程调度开销可能抵消性能收益,建议数据量上万条以上时使用。

3. 高效映射:使用MapStruct框架

如果项目中有频繁的对象映射需求,MapStruct是最优解——它在编译时生成直接的映射代码,无反射开销,效率和手动写foreach完全一致,代码还最简洁:

步骤1:添加Maven依赖

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version>
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.5.5.Final</version>
    <scope>provided</scope>
</dependency>

步骤2:定义映射接口

MapStruct会自动匹配同名字段,无需手动编写映射逻辑:

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;

@Mapper
public interface DataMapper {
    DataMapper INSTANCE = Mappers.getMapper(DataMapper.class);

    SmallerData dataToSmallerData(Data data);
    List<SmallerData> dataListToSmallerDataList(List<Data> dataList);
}

步骤3:使用映射接口

List<Data> dataList = service.findAll();
List<SmallerData> smallerDataList = DataMapper.INSTANCE.dataListToSmallerDataList(dataList);

// 输出结果
smallerDataList.forEach(System.out::println);

效率对比

  • 显式foreach:无额外开销,效率顶尖,但代码繁琐。
  • 串行Stream:和foreach效率持平,代码更简洁,适合大多数场景。
  • 并行Stream:大数据量下利用多核优势,效率高于串行;小数据量不推荐。
  • MapStruct:编译时生成代码,效率与手动foreach一致,代码最简洁,适合频繁映射场景。

内容的提问来源于stack exchange,提问作者Binny Bogs

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 06:24:59