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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 12:07:46