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

如何通过泛型或Java8 Function类消除Java方法重复代码

冗余代码场景

现有泛型方法存在大量重复分支逻辑,原始代码如下:

private <Y> void meth(
            MyObj ds, MultiValueMap<String, List> mvm, Class<Y> data) {

        if(data.isAssignableFrom(Employee.class)) {
            for (Employee rd : (List<Employee>) mvm.get(0).get(1)) {
               
                for (String cName : (List<String>) mvm.get(0).get(0)) {
                    ds.setCellValue((String)rd.getDataElement(cName));
                   
                }
               
            }
        }

        if(data.isAssignableFrom(Department.class)) {
            for (Department rd : (List<Department>) mvm.get(0).get(1)) {
               
                for (String cName : (List<String>) mvm.get(0).get(0)) {
                    ds.setCellValue((String)rd.getDataElement(cName));
                    
                }
               
            }
        }
        
        // 其余10个左右逻辑高度相似的if分支
}

各分支仅处理的业务实体类型(Employee、Department等)有区别,遍历MultiValueMap取值、调用setCellValue与getDataElement的核心逻辑完全重复,纠结选择Java 8 Function传参方案,还是优化泛型实现来消除冗余。

方案选型结论

不需要二选一,两种方案是互补关系,单独使用任意一种都有明显短板:

  • 仅优化泛型:现有泛型参数Y没有任何类型约束,编译器根本不知道Y类型存在getDataElement方法,才会需要每个分支单独做类型强转、写重复逻辑,如果不配合公共行为约束,光调整泛型写法根本解决不了重复问题。
  • 仅传Function参数:可以解决不同类型的方法适配问题,但缺少泛型约束的话,类型校验只能留到运行时,容易抛出类型转换异常,代码可读性也更差。

实际落地可以根据项目的代码修改权限选对应组合方案,两种方案都能完全删掉所有重复if分支,后续新增实体类型不需要修改方法内部逻辑。


方案1:泛型上界约束+公共接口(优先选)

适合场景:所有业务实体的getDataElement方法签名完全一致,且你可以修改这些实体类的代码。

  1. 先抽公共接口,约束所有实体的公共行为:
// 所有需要处理的业务实体统一实现该接口
public interface DataElementProvider {
    String getDataElement(String columnName);
}

让Employee、Department等所有对应实体都实现这个接口,不需要修改实体内部的原有逻辑。
2. 重构meth方法,给泛型加上界约束,删掉所有if分支:

private <T extends DataElementProvider> void meth(
        MyObj ds, 
        MultiValueMap<String, List> mvm, 
        Class<T> entityClass) {
    // 公共逻辑只需要写一次,不用每个分支重复取值
    List<String> columnNames = (List<String>) mvm.get(0).get(0);
    List<T> entityList = (List<T>) mvm.get(0).get(1);

    for (T entity : entityList) {
        for (String columnName : columnNames) {
            ds.setCellValue(entity.getDataElement(columnName));
        }
    }
}

这个方案类型安全等级最高,所有类型校验在编译期完成,不会出现运行时强转异常,调用方也不需要传额外参数,使用成本最低。


方案2:泛型+函数式参数(适配不能修改实体的场景)

适合场景:没法修改原有实体类代码,或者部分实体的取值逻辑不统一。
因为取值逻辑需要传入动态的列名,单参数Function不够用,用BiFunction接收实体、列名两个入参,返回对应的单元格值即可:

private <T> void meth(
        MyObj ds,
        MultiValueMap<String, List> mvm,
        Class<T> entityClass,
        BiFunction<T, String, String> valueGetter) {
    List<String> columnNames = (List<String>) mvm.get(0).get(0);
    List<T> entityList = (List<T>) mvm.get(0).get(1);

    for (T entity : entityList) {
        for (String columnName : columnNames) {
            ds.setCellValue(valueGetter.apply(entity, columnName));
        }
    }
}

调用时直接传入对应实体的方法引用即可,不需要写任何分支判断:

// 处理Employee
meth(ds, mvm, Employee.class, Employee::getDataElement);
// 处理Department
meth(ds, mvm, Department.class, Department::getDataElement);

这个方案灵活度最高,不需要侵入原有实体的代码,哪怕个别实体的取值方法名不一样,只要符合入参出参规则,都可以通过传入自定义lambda适配。


额外注意

原代码里用isAssignableFrom做类型判断本身就有风险:如果传入的是对应实体的子类,会进入分支但强转可能失败,上述两种重构方案都把类型校验提前到了编译期,能规避这类运行时异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 05:57:12