Java中合并两个多属性对象列表的高效实现方案(避免逐个属性赋值)
Awesome question—having to manually handle 15+ properties with getters/setters is such a tedious chore, so let’s break down the best, most scalable ways to merge your lists efficiently!
Core Logic First
From your example, it looks like we need to prioritize non-default/non-null values for each property: take the value from listA if it’s not a default (like 0 or null), otherwise use the value from listB. Let’s cover three practical approaches:
1. Use Reflection Utility Libraries (Fast & Simple)
Libraries like Apache Commons BeanUtils or Spring BeanUtils handle the heavy lifting of reflection, so you don’t have to write all the field-access code yourself. We’ll wrap them in a custom utility to enforce our "non-default priority" logic.
Example with Apache Commons BeanUtils
First, add the dependency (Maven):
<dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.4</version> </dependency>
Then create a reusable merge utility:
import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.PropertyUtils; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; public class BeanMerger { public static <T> List<T> mergeLists(List<T> listA, List<T> listB, Class<T> beanClass) { List<T> mergedList = new ArrayList<>(); for (int i = 0; i < Math.min(listA.size(), listB.size()); i++) { try { T merged = beanClass.newInstance(); // Copy all properties from listA first BeanUtils.copyProperties(merged, listA.get(i)); // Override with non-default values from listB for (Field field : beanClass.getDeclaredFields()) { Object mergedValue = PropertyUtils.getProperty(merged, field.getName()); Object bValue = PropertyUtils.getProperty(listB.get(i), field.getName()); if (isDefaultValue(mergedValue) && !isDefaultValue(bValue)) { PropertyUtils.setProperty(merged, field.getName(), bValue); } } mergedList.add(merged); } catch (Exception e) { // Handle exceptions (e.g., log and skip, or rethrow) e.printStackTrace(); } } return mergedList; } // Customize this to match your object's default value rules private static boolean isDefaultValue(Object value) { if (value == null) return true; if (value instanceof Number) return ((Number) value).doubleValue() == 0; if (value instanceof String) return ((String) value).isEmpty(); if (value instanceof Boolean) return !((Boolean) value); // Add more checks for your specific property types (e.g., Date, enums) return false; } }
Usage
List<YourObject> mergedList = BeanMerger.mergeLists(listA, listB, YourObject.class);
2. MapStruct (Performance & Type Safety)
If you want zero reflection overhead and compile-time safety, MapStruct is perfect. It generates plain getter/setter code at build time, so no runtime reflection costs.
Add Dependencies (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>
Define a Mapper Interface
import org.mapstruct.Mapper; import org.mapstruct.MappingTarget; import org.mapstruct.NullValuePropertyMappingStrategy; @Mapper(componentModel = "spring", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) public interface YourObjectMapper { // Initialize merged object with listA's values YourObject fromListA(YourObject sourceA); // Override merged object with non-default values from listB default void mergeFromListB(YourObject sourceB, @MappingTarget YourObject merged) { if (!isDefaultValue(sourceB.getName())) merged.setName(sourceB.getName()); if (!isDefaultValue(sourceB.getAge())) merged.setAge(sourceB.getAge()); if (!isDefaultValue(sourceB.getWeight())) merged.setWeight(sourceB.getWeight()); // Repeat for other properties (MapStruct can also auto-generate this with custom conditions) } // Reuse the same default value check as before default boolean isDefaultValue(Object value) { if (value == null) return true; if (value instanceof Number) return ((Number) value).doubleValue() == 0; if (value instanceof String) return ((String) value).isEmpty(); if (value instanceof Boolean) return !((Boolean) value); return false; } }
Usage
YourObjectMapper mapper = org.mapstruct.factory.Mappers.getMapper(YourObjectMapper.class); List<YourObject> mergedList = new ArrayList<>(); for (int i = 0; i < Math.min(listA.size(), listB.size()); i++) { YourObject merged = mapper.fromListA(listA.get(i)); mapper.mergeFromListB(listB.get(i), merged); mergedList.add(merged); }
3. Custom Reflection (No Third-Party Dependencies)
If you want to avoid external libraries entirely, write a simple reflection-based utility:
import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; public class CustomMergeUtility { public static <T> List<T> mergeLists(List<T> listA, List<T> listB, Class<T> beanClass) { List<T> mergedList = new ArrayList<>(); for (int i = 0; i < Math.min(listA.size(), listB.size()); i++) { try { T merged = beanClass.newInstance(); T objA = listA.get(i); T objB = listB.get(i); for (Field field : beanClass.getDeclaredFields()) { field.setAccessible(true); Object valueA = field.get(objA); Object valueB = field.get(objB); // Pick non-default value, prioritize listA first Object finalValue = isDefaultValue(valueA) ? valueB : valueA; // Fallback to listA's value if both are default if (isDefaultValue(finalValue)) finalValue = valueA; field.set(merged, finalValue); } mergedList.add(merged); } catch (Exception e) { e.printStackTrace(); } } return mergedList; } private static boolean isDefaultValue(Object value) { // Same logic as before if (value == null) return true; if (value instanceof Number) return ((Number) value).doubleValue() == 0; if (value instanceof String) return ((String) value).isEmpty(); if (value instanceof Boolean) return !((Boolean) value); return false; } }
Usage
List<YourObject> mergedList = CustomMergeUtility.mergeLists(listA, listB, YourObject.class);
Quick Recommendations
- For simplicity: Go with Apache Commons BeanUtils (least code to write).
- For performance: Use MapStruct (compile-time code generation, no reflection).
- For no external dependencies: Use the custom reflection utility.
内容的提问来源于stack exchange,提问作者Puspanjali Padhy

