道家人 发表于 2023-6-9 18:29:33

Java对象中转换空值的字段

在后端返回数据给前端时,公司的框架会把值为null的数据去掉,方便前端取值。
如:Person对象为:{name:"浩二", age:24, weight:null, height:114},那返回给前端的就为{name:"浩二", age:24, height:114}。
如果这个时候有个需求:
  Integer类型的字段为null给-1
  Long类型的字段为null给-1L
  String类型的字段为null给""(空字符串)
  对象类型的字段为null给new对象,
不能直接动框架,因此需要手动转化。
 
代码写死转换

这种是最简单的方式,顾名思义,写死代码的方式一个一个字段来转换
示例

转换对象 ConvertNullFiledInfo:
@Data
public class ConvertNullFiledInfo {

    private Integer intNum;

    private Long longNum;

    private String str;

    private ConvertNullFiledInfo info;

}转换代码:
@Service
public class ConvertNullFiledService {

    /**
   * 写死代码的方式一个一个字段来转换
   * @param info
   * @return
   */
    public ConvertNullFiledInfo convertFunction01(ConvertNullFiledInfo info) {
      info.setIntNum(info.getIntNum() == null ? -1 : info.getIntNum());
      info.setLongNum(info.getLongNum() == null ? -1L : info.getLongNum());
      info.setStr(info.getStr() == null ? "" : info.getStr());
      info.setInfo(info.getInfo() == null ? new ConvertNullFiledInfo() : info.getInfo());
      return info;
    }
   
}测试代码:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;


@SpringBootTest
@RunWith(SpringRunner.class)
public class ConvertNullFiledServiceTest {

    @Autowired
    private ConvertNullFiledService convertNullFiledService;

    @Test
    public void convertFunction01() {
      // str和info字段给null
      ConvertNullFiledInfo info = createConvertNullFiledInfo(1, 1L, null, null);
      ConvertNullFiledInfo result = convertNullFiledService.convertFunction01(info);
      System.out.println(result);
    }

    /**
   * 自定义字段创建ConvertNullFiledInfo
   * @param intNum
   * @param longNum
   * @param str
   * @param info
   * @return
   */
    private ConvertNullFiledInfo createConvertNullFiledInfo(Integer intNum, Long longNum, String str, ConvertNullFiledInfo info) {
      ConvertNullFiledInfo result = new ConvertNullFiledInfo();
      result.setIntNum(intNum);
      result.setLongNum(longNum);
      result.setStr(str);
      result.setInfo(info);
      return result;
    }
   
}运行结果:
https://img2023.cnblogs.com/blog/1957622/202306/1957622-20230609175722053-1107021498.png
可以看到是正常转换了的
问题点

这样写虽然简单方便,但是如果有非常多的对象需要转换,就会有许多重复代码;
而且如果字段有修改(类型、名称、被删除、新增),就需要在去转换方法中修改,因此可以用更好的方式。
 
遍历Filed转换

所有对象都有Class类,而Class有getDeclaredFields()方法,能获取到所有字段(filed),
因此可以使用这种方式来转换。
示例

转换代码:
/**
   * 遍历field的方式一个一个字段来转换
   * @param info
   * @return
   */
    public ConvertNullFiledInfo convertByField(ConvertNullFiledInfo info) {
      try {
            Field[] fields = info.getClass().getDeclaredFields();
            for (Field field : fields) {
                // 设置可访问私有变量
                field.setAccessible(true);
                // 获取当前字段值
                Object value = field.get(info);
                // value不为空就跳过
                if (value != null) {
                  continue;
                }
                // 获取当前字段类型
                Class<?> type = field.getType();
                if (type == Integer.class) {
                  // Integer类型就设置为-1
                  field.set(info, -1);
                } else if (type == Long.class) {
                  // Long类型就设置为-1L
                  field.set(info, -1L);
                } else if (type == String.class) {
                  // String类型就设置为“”
                  field.set(info, "");
                } else if (type == ConvertNullFiledInfo.class) {
                  // ConvertNullFiledInfo类型就设置为新对象
                  field.set(info, new ConvertNullFiledInfo());
                }
            }
      } catch (Exception e) {
            e.printStackTrace();
      }
      return info;
    }测试代码:
@Test
public void convertByField() {
    // str和info字段给null
    ConvertNullFiledInfo info = createConvertNullFiledInfo(1, 1L, null, null);
    ConvertNullFiledInfo result = convertNullFiledService.convertByField(info);
    System.out.println(result);
}运行结果:
https://img2023.cnblogs.com/blog/1957622/202306/1957622-20230609175826579-1088665720.png
可以看到也是成功转换了
问题点

这种写法仍然存在问题,可以看到方法的传参和返回值都是固定类型为ConvertNullFiledInfo,
并且在遍历field的时候,也有if判断是写定的ConvertNullFiledInfo,
因此也在一定程度上写死了代码
优化

为了避免写死的情况,可以使用泛型来写
转换代码:
@Service
public class ConvertNullFiledService<T> {
   
    /**
   * 使用泛型,遍历field的方式一个一个字段来转换
   * @param object
   * @return
   */
    public T convertByFieldGeneric(T object) {
      try {
            Field[] fields = object.getClass().getDeclaredFields();
            for (Field field : fields) {
                // 设置可访问私有变量
                field.setAccessible(true);
                // 获取当前字段值
                Object value = field.get(object);
                // value不为空就跳过
                if (value != null) {
                  continue;
                }
                // 获取当前字段类型
                Class<?> type = field.getType();
                if (type == Integer.class) {
                  // Integer类型就设置为-1
                  field.set(object, -1);
                } else if (type == Long.class) {
                  // Long类型就设置为-1L
                  field.set(object, -1L);
                } else if (type == String.class) {
                  // String类型就设置为“”
                  field.set(object, "");
                } else if (type == object.getClass()) {
                  // T类型就设置为新对象
                  Object newObj = object.getClass().newInstance();
                  field.set(object, newObj);
                }
            }
      } catch (Exception e) {
            e.printStackTrace();
      }
      return object;
    }
}测试代码:
@Test
public void convertByFieldGeneric() {
    // 全部字段给null
    ConvertNullFiledInfo info = createConvertNullFiledInfo(null, null, null, null);
    ConvertNullFiledInfo result = (ConvertNullFiledInfo) convertNullFiledService.convertByFieldGeneric(info);
    System.out.println(result);
}运行结果:
https://img2023.cnblogs.com/blog/1957622/202306/1957622-20230609175910465-1938624813.png
成功转换
 
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Java对象中转换空值的字段