如何将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
相关产品推荐
相关产品推荐

