从反射到switch case手写set 再到BiConsumer优化service层代码逻辑

比如下面这段原始反射代码,QmApResultsDetailDataExportDTO 大概有一百个属性,为了赋值方便用反射给属性赋值,这里不是一个元素的属性赋值,而是从库中查出100条数据,每条数据的一百个元素都要赋值,反射会执行一万次,由于反射赋值非常慢,出现性能问题。

为什么反射会慢:方法查找:getDeclaredMethod 需要遍历类的所有方法 ,访问检查:setAccessible(true) 有开销,安全检查:每次调用都进行权限验证

for (QmApDataSourceNameDTO sourceNameDTO : sourceNameDTOS) {
                   String prop = NumberToLetterConverter.convertToLetters(sourceNameDTO.getSourcePkid());//pkid是数字,转成字符串做属性
                           try {
                      Field field = QmApResultsDetailDataExportDTO.class.getDeclaredField(prop);
                      field.setAccessible(true);  // 私有属性需要设置可访问
                      field.set(exportDTO, sourceNameDTO.getValue());
                           } catch (Exception e) {
                               throw new RuntimeException(e);
                           } 
                       }

如果是写框架,不知道类型,可以用反射,这种应用代码尽量不要用反射。

 

改成手写set后

List<String> pkidList = list.stream().map(e->e.getPkid()).collect(Collectors.toList());
List<QmApDataSourceNameDTO> dataSourceNameDTOList = resultsDetailsMapper.queryDataSourceNames2(pkidList);
for (QmApResultsDetailDataExportDTO exportDTO : list) {
    List<QmApDataSourceNameDTO> filterDataSourceNameDTOList = dataSourceNameDTOList.stream().filter(e->e.getPkid().equals(exportDTO.getPkid())).collect(Collectors.toList());
    for (QmApDataSourceNameDTO qmApDataSourceNameDTO : filterDataSourceNameDTOList) {
       String sourcePkid = qmApDataSourceNameDTO.getSourcePkid();
       switch (sourcePkid) {
          case "1000000":
             exportDTO.setBaaaaaa(qmApDataSourceNameDTO.getValue());
             exportDTO.setBaaaaaaScore(qmApDataSourceNameDTO.getScore());
             break;
          case "1002008":
             exportDTO.setBaacaai(qmApDataSourceNameDTO.getValue());
             exportDTO.setBaacaaiScore(qmApDataSourceNameDTO.getScore());
             break;

这种循环list,每次从大list(dataSourceNameDTOList)中filter一个小结果集,可以优化成把大list按过滤的逻辑分组,避免每次循环都filter一次。switch case太多的情况下可以换成BiConsumer,将赋值

逻辑放到BiConsumer中。

优化后的代码

// 优化:按pkid分组,避免多次遍历整个列表
Map<String, List<QmApDataSourceNameDTO>> groupedDataSourceMap = dataSourceNameDTOList.stream()
       .collect(Collectors.groupingBy(QmApDataSourceNameDTO::getPkid));

// 使用Map替代switch-case,提高可维护性和性能
Map<String, BiConsumer<QmApResultsDetailDataExportDTO, QmApDataSourceNameDTO>> propertySetters = new HashMap<>();
initializePropertySetters(propertySetters);

for (QmApResultsDetailDataExportDTO exportDTO : list) {
    List<QmApDataSourceNameDTO> filterDataSourceNameDTOList = groupedDataSourceMap.getOrDefault(exportDTO.getPkid(), Collections.emptyList());
    for (QmApDataSourceNameDTO qmApDataSourceNameDTO : filterDataSourceNameDTOList) {
       String sourcePkid = qmApDataSourceNameDTO.getSourcePkid();
       BiConsumer<QmApResultsDetailDataExportDTO, QmApDataSourceNameDTO> setter = propertySetters.get(sourcePkid);
       if (setter != null) {
          setter.accept(exportDTO, qmApDataSourceNameDTO);
       }
    }
}

private void initializePropertySetters(Map<String, BiConsumer<QmApResultsDetailDataExportDTO, QmApDataSourceNameDTO>> propertySetters) {
    propertySetters.put("1000000", (dto, data) -> {
       dto.setBaaaaaa(data.getValue());
       dto.setBaaaaaaScore(data.getScore());
    });
    propertySetters.put("1002008", (dto, data) -> {
       dto.setBaacaai(data.getValue());
       dto.setBaacaaiScore(data.getScore());
    });

 

posted @ 2026-05-15 10:33  杨吃羊  阅读(7)  评论(0)    收藏  举报