代码精简条目

  1. 概述
    1. 目的

   《孙子兵法》讲:“道为术之灵,术为道之体;以道统术,以术得道”。

明道——“道为术之灵,术为道之体;以道统术,以术得道”;道是教育理念、教学规律,是教学原则。“明道”就是加强教育理论研修,学习新课程理念,研习教学论和学习理论,领悟信息技术以及信息技术教育方面的理论框架。
    优术——“术”是能力,能力是知识、方法、策略和经验的集合体;“术”也是可解决实际问题的流程和策略,是可以提高效果和效率的技巧。“优术”即不断提升教学方法,探索和积累课堂教学中实用的教学策略,积淀适合于自己和本校的教学经验,当然还要持续更新信息技术教学所需要的信息技术知识技能。

工匠追求“术”到极致,其实就是在寻“道”,且离悟“道”也就不远了,亦或是已经得道,这就是“工匠精神”——一种追求“以术得道”的精神。如果一个工匠只满足于“术”,不能追求“术”到极致去悟“道”,那只是一个靠“术”养家糊口的工匠而已。

Java 代码精简之“术”,试图阐述出心中的 Java 代码精简之“道”。

    1.  阅读对象
  1. 领域设计工程师。
  2. 产品开发工程师。
  3. 产品测试工程师。
  4. 其他相关人员。
    1. 设计原则与前提

     无

    1.  名词解释
  1. 精简条目

    1. 利用语法
      1. 三元表达式
  1. 三元表达式代码简洁
  2. 三元表达式代码cpu执行效率高

三元运算符x=y>0?A:B;,其性能会比使用if…else…性能更好因为cpu计算能力强,三元运算符两种表达式指令排队进行,而if…else…需要经过判断,判断前并不知道下一指令将是哪个,当默认的下一指令不一致时,更换再执行新指令,这个时间比指令计算时间要多耗时50-60时钟左右。

        1. 原代码

if (code.indexOf(".") > 0) {
   String[] arr code.split("\\.");
   domain arr[0];
   code arr[1];
}

return getBillByCodeAndDomain(codedomain);

        1. 精简

String[] arr code.split("\\.");

return getBillByCodeAndDomain(code.indexOf(".") > 0?arr[1]:codecode.indexOf(".") > 0?arr[0]:null);

   

        1. 注意事项

注意:null值情况会抛异常

      1. 利用 for-each 语句
        1. 原代码

private static JsonElement simplifyProps_LV1(JsonElement jsonObjJSONObject removeList) {
    //初始化值--省略
    Iterator<Stringit removeList.keySet().iterator();
    while (it.hasNext()) {
        String key it.next();
       //业务处理
        }
    }
    return jsonObj;
}

        1. 精简

private static JsonElement simplifyProps_LV1(JsonElement jsonObjJSONObject removeList) {
    //初始化值--省略
   for(String value:removeList.keySet()){

       //业务处理
        }
    }
    return jsonObj;
}

      1. 利用 try-with-resource 语句

在JDK7以前,Java没有自动关闭外部资源的语法特性,直到JDK7中新增了try-with-resource语法,才实现了这一功能。

那什么是try-with-resource呢?简而言之,当一个外部资源的句柄对象(比如FileInputStream对象)实现了AutoCloseable接口,那么就可以按照板式简化。

        1. 原代码

InputStream publicPro null;
try {
   File file null;
   if(!StringUtil.isBlank(ConfUtil.CONF_FILE_PATH))
      file new File(ConfUtil.CONF_FILE_PATH);
   else
      file file new File(PUBLIC);
   InputStreamReader reader new InputStreamReader(new FileInputStream(file),"UTF-8");
   properties.load(reader);
   /* } */
catch (Exception e) {
   logger.warn("公共提示消息文件加载失败",e);
}finally {
   if(publicPro!=null){
      try {
         publicPro.close();
      } catch (Exception e) {
         logger.warn("公共提示消息文件加载失败",e);
      }
   }

        1. 精简

InputStream publicPro = null;

 File file = !StringUtil.isBlank(ConfUtil.CONF_FILE_PATH)?new File(ConfUtil.CONF_FILE_PATH):new File(PUBLIC);
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file),"UTF-8")){
   properties.load(reader);
} catch (Exception e) {
   logger.warn("公共提示消息文件加载失败",e);
}

      1. 利用 return 关键字

利用 return 关键字,可以提前函数返回,避免定义中间变量。

        1. 原代码

int existIndex = -1;
for (int 0len targetList.size(); leni++) {
    Map<StringObjectmap targetList.get(i);
    Object value map.get(key);
    if (targetValue.equals(value)) {
        existIndex i;
        return existIndex;
    }
}
return -1;

        1. 精简


for (int 0len targetList.size(); leni++) {
    Map<StringObjectmap targetList.get(i);
    Object value map.get(key);
    if (targetValue.equals(value)) {
        return i;
    }
}
return -1;

      1. 利用 static 关键字

利用 static 关键字,可以把字段变成静态字段,也可以把函数变为静态函数,调用时就无需初始化类对象。

原代码

public final class GisHelper {    public double distance(double lng1, double lat1, double lng2, double lat2) {        // 方法实现代码    }}

GisHelper gisHelper = new GisHelper();double distance = gisHelper.distance(116.178692D, 39.967115D, 116.410778D, 39.899721D);

        1. 精简

public final class GisHelper {     public static double distance(double lng1, double lat1, double lng2, double lat2) {        // 方法实现代码    }}
double distance = GisHelper.distance(116.178692D, 39.967115D, 116.410778D, 39.899721D);

      1. 利用 lambda 表达式

Java 8 发布以后,lambda 表达式大量替代匿名内部类的使用,在简化了代码的同时,更突出了原有匿名内部类中真正有用的那部分代码。

        1. 原代码

new Thread(new Runnable() {  

  public void run() {     

   // 线程处理代码  

  }}).start();

        1. 精简

new Thread(() -> {    

 // 线程处理代码

}).start();

      1. 利用方法引用

方法引用(::),可以简化 lambda 表达式,省略变量声明和函数调用。

        1. 原代码

List<StringflowIds=flowList.stream().map(item->(String)item.get(BillConstants.BIZFLOWID)).distinct().collect(Collectors.toList());

        1. 精简

List<StringflowIds=flowList.stream().map(String::get(BillConstants.BIZFLOWID)).distinct().collect(Collectors.toList());

      1. 利用静态导入

静态导入(import static),当程序中大量使用同一静态常量和函数时,可以简化静态常量和函数的引用。

import static静态导入是JDK1.5中的新特性。

一般我们导入一个类都用 import 包名.类名;

而静态导入是这样:import static 包名.类名.*;

这里的多了个static,还有就是类名后面多了个 .* 。意思是导入这个类里的静态成员(静态方法、静态变量)。当然,也可以只导入某个静态方法,只要把 .* 换成静态方法名就行了。然后在这个类中,就可以直接用方法名调用静态方法,而不必用“类名.方法名()” 的方式来调用。

        1. 精简

import static com.yonyou.ucf.mdd.ext.option.model.po.OptionDataPO.PARAMS_TYPE_ORG;
import static java.util.stream.Collectors.*;

        1. 注意事项

注意:静态引入容易造成代码阅读困难,所以在实际项目中应该警慎使用。

    1. 利用注解
      1. 利用 Lombok 注解

Lombok 提供了一组有用的注解,可以用来消除Java类中的大量样板代码。

        1. 原代码

public class UserVO {   

  

private Long id;  

  private String name;  

public Long getId() {
   return id;
}
public void setId(Long id) {
   this.id = id;
}
public String getName() {
   return name;
}
public void setName(String name) {
   this.name = name;
}

}

        1. 精简

@Data

public class UserVO {   

  private Long id;  

  private String name;  

  ...

}

      1. 利用 Validation 注解

  采用Validation 可以避免大量的判空,长度及正则校验代码量。

        1. 精简

@Data

public class B00XXXBean {

    /** 登录名 */

    @Length(max = 10, message = "{valid.length}")

    @NotBlank(message = "{valid.name}")

    @Pattern(regexp = "^[\u4E00-\u9FA5A-Za-z0-9_]+$", message = "{valid.format}")

    private String staffname;

    /** 姓名 */

    @Length(max = 10, message = "{valid.length}")

    @NotBlank(message = "{valid.staffrealname}")

    @Pattern(regexp = "^[\u4E00-\u9FA5A-Za-z0-9_]+$", message = "{valid.format}")

    private String realname;

    /** 登录密码 */

    @Length(min = 1, max = 50, message = "{valid.password.length}")

    @NotBlank(message = "{valid.password.notblank}")

    @Pattern(regexp = "^[0-9a-zA-Z_]{1,}$", message = "{valid.format}")

    private String password;

    /** 确认密码 */

    @NotBlank(message = "{valid.repassword}")

    @Pattern(regexp = "^[0-9a-zA-Z_]{1,}$", message = "{valid.format}")

    private String password2;

    /** 电话 */

    @Pattern(regexp = "^[150[0-9]+]{11}", message = "{valid.tel}")

    private String tel;

    /** 邮箱 */

    @Email(message = "{valid.mail}")

    private String mail;

}

@Service

@Validated

public class UserService { 

   public Long createUser(@Valid UserCreateVO create) { 

       // TODO: 创建用户   

      return null;

    }}

      1. 利用 @NonNull 注解

Spring 的 @NonNull 注解,用于标注参数或返回值非空,适用于项目内部团队协作。只要实现方和调用方遵循规范,可以避免不必要的空值判断,这充分体现了阿里的“新六脉神剑”提倡的“因为信任,所以简单”。

        1. 原代码

public List<UserVO> queryCompanyUser(Long companyId) { 

   // 检查公司标识  

  if (companyId == null) {  

      return null;  

     //业务处理

  }

List<UserVO> userList = queryCompanyUser(companyId);

if (CollectionUtils.isNotEmpty(userList)) {  

  for (UserVO user : userList) {    

// TODO: 处理业务

 }}

        1. 精简

public @NonNull List<UserVO> queryCompanyUser(@NonNull Long companyId) {

}

List<UserVO> userList = queryCompanyUser(companyId);

for (UserVO user : userList) {   

 // TODO: 处理公司用户

}

      1. 利用注解特性

注解有以下特性可用于精简注解声明:1、当注解属性值跟默认值一致时,可以删除该属性赋值;2、当注解只有value属性时,可以去掉value进行简写;3、当注解属性组合等于另一个特定注解时,直接采用该特定注解。

        1. 原代码

@Lazy(true);

@Service(value = "userService")

@Component(value = "uimetaConfProps")
@PropertySource(value = {"classpath:uimeta-sdk.properties"})

@RequestMapping(path = "/getUser", method = RequestMethod.GET)

        1. 精简

@Lazy

@Service("userService")

@Component("uimetaConfProps")
@PropertySource( "classpath:uimeta-sdk.properties")

@GetMapping("/getUser")

    1. 利用泛型
      1. 泛型接口

在 Java 没有引入泛型前,都是采用 Object 表示通用对象,最大的问题就是类型无法强校验并且需要强制类型转换。

        1. 原代码

public interface Comparable { 

   public int compareTo(Object other);

}
@Getter@Setter@ToStringpublic class UserVO implements Comparable { 

   private Long id;
    @Override   

 public int compareTo(Object other) {  

      UserVO user = (UserVO)other;

        return Long.compare(this.id, user.id);  

  }}

        1. 精简

public interface Comparable<T> {   

  public int compareTo(T other);

}
@Getter

@Setter

@ToString

public class UserVO implements Comparable<UserVO> { 

   private Long id;
    @Override 

   public int compareTo(UserVO other) {  

      return Long.compare(this.id, other.id);  

  }}

    1. 利用自身方法
      1. 利用构造方法

构造方法,可以简化对象的初始化和设置属性操作。对于属性字段较少的类,可以自定义构造方法。

        1. 精简对比

简化了set属性

/*

 * 构造方法用于给对象的数据进行初始化

 * 究竟是如何进行初始化的,对象的数据指的是什么?

 * 感觉书里这样讲很抽象,能否写代码举个例子

 */

public class Cat {

    private String name;

    private int age;

 

    // 无参构造方法

    public Cat() {

 

    }

 

    // 有参构造方法

    public Cat(String name, int age) {

        this.name = name;

        this.age = age;

    }

 

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name = name;

    }

 

    public int getAge() {

        return age;

    }

 

    public void setAge(int age) {

        this.age = age;

    }

 

    public static void main(String[] args) {

        Cat blackCat1 = new Cat();

        blackCat1.setName("一只黑猫");

        blackCat1.setAge(7);

        System.out.println(blackCat1.getName() + " " + blackCat1.getAge());

        Cat blackCat2 = new Cat("五更琉璃"17);

        System.out.println(blackCat2.getName() + " " + blackCat2.getAge());

    }

}

 

//程序运行结果:

//一只黑猫 7

//五更琉璃 17

      1. 利用链式编程

链式编程,也叫级联式编程,调用对象的函数时返回一个this对象指向对象本身,达到链式效果,可以级联调用。链式编程的优点是:编程性强、可读性强、代码简洁。

        1. 原代码

if (!isByAlias && dataSources.length > 1) {
    returnSql.append("(");
    for (int i = 0; i < dataSources.length; i++) {
        returnSql.append(dataSources[i] + " ");
        returnSql.append(CompareUtils.toSqlCompare(compareLogic,
                commonVO.getValue1(), commonVO.getValue2(),
                filterItem.getItemType()));
        returnSql.append(" or ");
    }
    returnSql.delete(returnSql.length() - 4, returnSql.length());
    returnSql.append(")");
} else {
    returnSql.append((isByAlias ? filterItem.getItemName() : dataSource) + " ");
    returnSql.append(CompareUtils.toSqlCompare(compareLogic,
            commonVO.getValue1(), commonVO.getValue2(),
            filterItem.getItemType()));
}

        1. 精简

if (!isByAlias && dataSources.length > 1) {
    returnSql.append("(")
    for (int i = 0; i < dataSources.length; i++) {
        .append(dataSources[i] + " ")
        .append(CompareUtils.toSqlCompare(compareLogic,
                commonVO.getValue1(), commonVO.getValue2(),
                filterItem.getItemType()))
        .append(" or ");
    }
    .delete(returnSql.length() - 4, returnSql.length())
    .append(")");
} else {
    returnSql.append((isByAlias ? filterItem.getItemName() : dataSource) + " ");
           .append(CompareUtils.toSqlCompare(compareLogic,
            commonVO.getValue1(), commonVO.getValue2(),
            filterItem.getItemType()));
}

    1. 利用工具方法
      1. 避免空值判断
        1. 原代码

if (params == null || params.isEmpty())

if( entity.getFields()!=null){

        1. 精简

if (!CollectionUtils..isEmpty(params)) {

if (!CollectionUtils..isNotEmpty(entity.getFields())) {

      1. 避免条件判断

        1. 原代码

if (pageIndex <= 0) {
    pageIndex = 1;
}

        1. 精简

pageIndex=Math.max(pageIndex,1);

      1. 简化赋值语句
        1. 精简

// JDK流派--mdd

List<String> ignoreParams=Arrays.asList(new String[]{"localId","id","classId","defineId","tenantId","_status","pubts","isdeleted","propertytype"});

// Guava流派

List<String> ignoreParams=ImmutableList.of(new String[]{"localId","id","classId","defineId","tenantId","_status","pubts","isdeleted","propertytype"});

        1. 注意事项

注意:Arrays.asList 返回的 List 并不是 ArrayList ,不支持 add 等变更操作。

避免方法:

List<String> ignoreParams=new ArrayList<>(Arrays.asList(new String[]{"localId","id","classId","defineId","tenantId","_status","pubts","isdeleted","propertytype"}));

      1. 简化数据拷贝

VO的拷贝

        1. 简化

BeanUtils.copyProperties(source, target);

BeanUtils.copyProperties(oneBill, poiDto);

        1. 反例

List<Object> list = JSON.parseArray(jsonObject.getString("data"));

list =JSON.parseArray(GsonHelper.ToJSon(bill.getData()));

精简代码,但不能以过大的性能损失为代价。例子是浅层拷贝,需要做JSON序列化,此处用不着 JSON 这样重量级的武器。

      1. 简化异常断言
        1. 原代码

if (optionData == null) {
    logger.error("没有对应的参数值, name: {}", name);
    throw new IllegalArgumentException("没有对应的参数值,name: " + name);
}

        1. 精简

Assert.notNull(optionData ,"没有对应的参数值,name: " + name);

        1. 注意事项

注意:可能有些插件不认同这种判断,导致使用该对象时会有空指针警告。

因为java的断言是默认关闭的,需要先开启。

run -> Edit configurations,

    1. 利用数据结构
      1. 利用数组简化

对于固定上下限范围的 if-else 语句,可以用数组+循环来简化。

        1. 原代码

public static int getGrade(double score) {  

   if (score >= 90.0D) {  

      return 1;  

  }  

  if (score >= 80.0D) {  

      return 2;   

 }    if (score >= 60.0D) { 

       return 3;  

  }    if (score >= 30.0D) {   

     return 4;   

 }   

 return 5;}

        1. 精简

private static final double[] SCORE_RANGES = new double[] {90.0D, 80.0D, 60.0D, 30.0D};

public static int getGrade(double score) {   

 for (int i = 0; i < SCORE_RANGES.length; i++) {   

     if (score >= SCORE_RANGES[i]) {     

       return i + 1;    

}    }  

  return SCORE_RANGES.length + 1;

}

      1. 利用 Map 简化

对于映射关系的 if-else 语句,可以用Map来简化。此外,此规则同样适用于简化映射关系的 switch 语句。

        1. 原代码

public static String getBiologyClass(String name) {  

  switch (name) {  

      case "dog" :     

       return "animal";    

case "cat" :    

        return "animal";   

     case "lavender" :     

       return "plant";      

  ...      

  default :      

      return null;   

 }}

        1. 精简

private static final Map<String, String> BIOLOGY_CLASS_MAP    = ImmutableMap.<String, String>builder()  

      .put("dog", "animal")     

 .put("cat", "animal")  

 .put("lavender", "plant")   

     ...    

    .build();

public static String getBiologyClass(String name) { 

   return BIOLOGY_CLASS_MAP.get(name);

}

    1. 利用 Optional
      1. 保证值存在
        1. 原代码

Integer thisValue;

if (Objects.nonNull(value)) {  

  thisValue = value;

} else {

thisValue = DEFAULT_VALUE;

}

        1. 精简

Integer thisValue = Optional.ofNullable(value).orElse(DEFAULT_VALUE);

      1. 保证值合法
        1. 原代码

Integer thisValue;

if (Objects.nonNull(value) && value.compareTo(MAX_VALUE) <= 0) {  

  thisValue = value;

} else {  

  thisValue = MAX_VALUE;

}

        1. 精简

Integer thisValue = Optional.ofNullable(value)   

 .filter(tempValue -> tempValue.compareTo(MAX_VALUE) <= 0)

.orElse(MAX_VALUE);

      1. 避免空判断
        1. 原代码

String zipcode = null;

if (Objects.nonNull(user)) { 

   Address address = user.getAddress();  

  if (Objects.nonNull(address)) {   

     Country country = address.getCountry();   

     if (Objects.nonNull(country)) { 

           zipcode = country.getZipcode(); 

       }   

 }}

        1. 精简

string zipcode = Optional.ofNullable(user)

.map(User::getAddress)   

 .map(Address::getCountry)

.map(Country::getZipcode)

.orElse(null);

    1. 利用 Stream

流(Stream)是Java 8的新成员,允许你以声明式处理数据集合,可以看成为一个遍历数据集的高级迭代器。流主要有三部分构成:获取一个数据源→数据转换→执行操作获取想要的结果。每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象,这就允许对其操作可以像链条一样排列,形成了一个管道。流(Stream)提供的功能非常有用,主要包括匹配、过滤、汇总、转化、分组、分组汇总等功能。

  

      1. 匹配集合数据
        1. 原代码

boolean isFound = false;

for (UserDO user : userList) {

if (Objects.equals(user.getId(), userId)) {   

     isFound = true;      

  break;   

 }}

        1. 精简

boolean isFound = userList.stream() 

   .anyMatch(user -> Objects.equals(user.getId(), userId));

      1. 过滤集合数据

        1. 原代码

List<UserDO> resultList = new ArrayList<>();

for (UserDO user : userList) {   

 if (Boolean.TRUE.equals(user.getIsSuper())) {  

      resultList.add(user);  

  }}

        1. 精简

List<UserDO> resultList = userList.stream() 

   .filter(user -> Boolean.TRUE.equals(user.getIsSuper()))   

 .collect(Collectors.toList());

      1. 汇总集合数据
        1. 原代码

double total = 0.0D;

for (Account account : accountList) {   

 total += account.getBalance();

}

        1. 精简

double total = accountList.stream().mapToDouble(Account::getBalance).sum();

      1. 转化集合数据

        1. 原代码

List<UserVO> userVOList = new ArrayList<>();

for (UserDO userDO : userDOList) { 

   userVOList.add(transUser(userDO));

}

        1. 精简

List<UserVO> userVOList = userDOList.stream()    

.map(this::transUser)

.collect(Collectors.toList());

      1. 分组集合数据
        1. 原代码

Map<Long, List<UserDO>> roleUserMap = new HashMap<>();

for (UserDO userDO : userDOList) {  

  roleUserMap.computeIfAbsent(userDO.getRoleId(), key -> new ArrayList<>())    

.add(userDO);

}

        1. 精简

Map<Long, List<UserDO>> roleUserMap = userDOList.stream()  

  .collect(Collectors.groupingBy(UserDO::getRoleId));

      1. 分组汇总集合
        1. 原代码

Map<Long, Double> roleTotalMap = new HashMap<>();

for (Account account : accountList) {  

  Long roleId = account.getRoleId(); 

   Double total = Optional.ofNullable(roleTotalMap.get(roleId)).orElse(0.0D);    roleTotalMap.put(roleId, total + account.getBalance());

}

        1. 精简


roleTotalMap = accountList.stream().collect(Collectors.groupingBy(Account::getRoleId, Collectors.summingDouble(Account::getBalance)));

    1. 利用程序结构
      1. 返回条件表达式

条件表达式判断返回布尔值,条件表达式本身就是结果。

        1. 原代码

if(RELEASE_SUCCESS.equals(result.toString())){
    logger.debug("##RedisTool:releaseLock #锁释放成功!lockKey:"+lockKey+",requestId:"+requestId);
    return true;
}
logger.debug("##RedisTool:releaseLock #锁释放失败!lockKey:"+lockKey+",requestId:"+requestId);
return false;

        1. 精简

return RELEASE_SUCCESS.equals(result.toString())

    1. 利用设计模式
      1. 模板方法模式

模板方法模式(Template Method Pattern)定义一个固定的算法框架,而将算法的一些步骤放到子类中实现,使得子类可以在不改变算法框架的情况下重定义该算法的某些步骤。

        1. 原代码

@Repository

public class UserValue {

    /** 值操作 */

    @Resource(name = "stringRedisTemplate")

    private ValueOperations<String, String> valueOperations;

    /** 值模式 */

    private static final String KEY_FORMAT = "Value:User:%s";

    /** 设置值 */

    public void set(Long id, UserDO value) {

        String key = String.format(KEY_FORMAT, id);

        valueOperations.set(key, JSON.toJSONString(value));

    }

    /** 获取值 */

    public UserDO get(Long id) {

        String key = String.format(KEY_FORMAT, id);

        String value = valueOperations.get(key);

        return JSON.parseObject(value, UserDO.class);

    }

    ...

}

@Repository

public class RoleValue {

    /** 值操作 */

    @Resource(name = "stringRedisTemplate")

    private ValueOperations<String, String> valueOperations;

    /** 值模式 */

    private static final String KEY_FORMAT = "Value:Role:%s";

    /** 设置值 */

    public void set(Long id, RoleDO value) {

        String key = String.format(KEY_FORMAT, id);

        valueOperations.set(key, JSON.toJSONString(value));

    }

    /** 获取值 */

    public RoleDO get(Long id) {

        String key = String.format(KEY_FORMAT, id);

        String value = valueOperations.get(key);

        return JSON.parseObject(value, RoleDO.class);

    }

    ...

}

        1. 精简

public abstract class AbstractDynamicValue<I, V> {

    /** 值操作 */

    @Resource(name = "stringRedisTemplate")

    private ValueOperations<String, String> valueOperations;

    /** 设置值 */

    public void set(I id, V value) {

        valueOperations.set(getKey(id), JSON.toJSONString(value));

    }

    /** 获取值 */

    public V get(I id) {

        return JSON.parseObject(valueOperations.get(getKey(id)), getValueClass());

    }

    ...

    /** 获取主键 */

    protected abstract String getKey(I id);

    /** 获取值类 */

    protected abstract Class<V> getValueClass();

}

@Repository

public class UserValue extends AbstractValue<Long, UserDO> {

    /** 获取主键 */

    @Override

    protected String getKey(Long id) {

        return String.format("Value:User:%s", id);

    }

    /** 获取值类 */

    @Override

    protected Class<UserDO> getValueClass() {

        return UserDO.class;

    }

}

@Repository

public class RoleValue extends AbstractValue<Long, RoleDO> {

    /** 获取主键 */

    @Override

    protected String getKey(Long id) {

        return String.format("Value:Role:%s", id);

    }

    /** 获取值类 */

    @Override

    protected Class<RoleDO> getValueClass() {

        return RoleDO.class;

    }

}

      1. 建造者模式

建造者模式(Builder Pattern)将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。

        1. 原代码

public interface DataHandler<T> {

    /** 解析数据 */

public T parseData(Record record);

    /** 存储数据 */

public boolean storeData(List<T> dataList);

}

public <T> long executeFetch(String tableName, int batchSize, DataHandler<T> dataHandler) throws Exception {

    // 构建下载会话

    DownloadSession session = buildSession(tableName);

    // 获取数据数量

    long recordCount = session.getRecordCount();

    if (recordCount == 0) {

        return 0;

    }

    // 进行数据读取

    long fetchCount = 0L;

    try (RecordReader reader = session.openRecordReader(0L, recordCount, true)) {

        // 依次读取数据

        Record record;

        List<T> dataList = new ArrayList<>(batchSize);

        while ((record = reader.read()) != null) {

            // 解析添加数据

            T data = dataHandler.parseData(record);

            if (Objects.nonNull(data)) {

                dataList.add(data);

            }

            // 批量存储数据

            if (dataList.size() == batchSize) {

                boolean isContinue = dataHandler.storeData(dataList);

                fetchCount += batchSize;

                dataList.clear();

                if (!isContinue) {

                    break;

                }

            }

        }

        // 存储剩余数据

        if (CollectionUtils.isNotEmpty(dataList)) {

            dataHandler.storeData(dataList);

            fetchCount += dataList.size();

            dataList.clear();

        }

    }

    // 返回获取数量

    return fetchCount;

}

 // 使用案例

long fetchCount = odpsService.executeFetch("user", 5000, new DataHandler() {

    /** 解析数据 */

    @Override

public T parseData(Record record) {

        UserDO user = new UserDO();

        user.setId(record.getBigint("id"));

        user.setName(record.getString("name"));

        return user;

    }

    /** 存储数据 */

    @Override

public boolean storeData(List<T> dataList) {

        userDAO.batchInsert(dataList);

        return true;

    }

});

        1. 精简

public <T> long executeFetch(String tableName, int batchSize, Function<Record, T> dataParser, Function<List<T>, Boolean> dataStorage) throws Exception {

    // 构建下载会话

    DownloadSession session = buildSession(tableName);

    // 获取数据数量

    long recordCount = session.getRecordCount();

    if (recordCount == 0) {

        return 0;

    }

    // 进行数据读取

    long fetchCount = 0L;

    try (RecordReader reader = session.openRecordReader(0L, recordCount, true)) {

        // 依次读取数据

        Record record;

        List<T> dataList = new ArrayList<>(batchSize);

        while ((record = reader.read()) != null) {

            // 解析添加数据

            T data = dataParser.apply(record);

            if (Objects.nonNull(data)) {

                dataList.add(data);

            }

            // 批量存储数据

            if (dataList.size() == batchSize) {

                Boolean isContinue = dataStorage.apply(dataList);

                fetchCount += batchSize;

                dataList.clear();

                if (!Boolean.TRUE.equals(isContinue)) {

                    break;

                }

            }

        }

        // 存储剩余数据

        if (CollectionUtils.isNotEmpty(dataList)) {

            dataStorage.apply(dataList);

            fetchCount += dataList.size();

            dataList.clear();

        }

    }

    // 返回获取数量

    return fetchCount;

}

 // 使用案例

long fetchCount = odpsService.executeFetch("user", 5000, record -> {

        UserDO user = new UserDO();

        user.setId(record.getBigint("id"));

        user.setName(record.getString("name"));

        return user;

    }, dataList -> {

        userDAO.batchInsert(dataList);

        return true;

    });

普通的建造者模式,实现时需要定义 DataHandler 接口,调用时需要实现 DataHandler 匿名内部类,代码较多较繁琐。而精简后的建造者模式,充分利用了函数式编程,实现时无需定义接口,直接使用 Function 接口;调用时无需实现匿名内部类,直接采用 lambda 表达式,代码较少较简洁。

      1. 代理模式

Spring 中最重要的代理模式就是 AOP (Aspect-Oriented Programming,面向切面的编程),是使用 JDK 动态代理和 CGLIB 动态代理技术来实现的。

        1. 原代码

@Slf4j

@RestController

@RequestMapping("/user")

public class UserController {

    /** 用户服务 */

    @Autowired

    private UserService userService;

    /** 查询用户 */

    @PostMapping("/queryUser")

    public Result<?> queryUser(@RequestBody @Valid UserQueryVO query) {

        try {

            PageDataVO<UserVO> pageData = userService.queryUser(query);

            return Result.success(pageData);

        } catch (Exception e) {

            log.error(e.getMessage(), e);

            return Result.failure(e.getMessage());

        }

    }

    ...

}

        1. 精简

// UserController代码同"精简1"

@Slf4j

@Aspect

public class WebExceptionAspect {

    /** 点切面 */

    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")

    private void webPointcut() {}

    /** 处理异常 */

    @AfterThrowing(pointcut = "webPointcut()", throwing = "e")

    public void handleException(Exception e) {

        Result<Void> result = Result.failure(e.getMessage());

        writeContent(JSON.toJSONString(result));

    }

    ...

}

    1. 利用删除代码

“少即是多”,“少”不是空白而是精简,“多”不是拥挤而是完美。删除多余的代码,才能使代码更精简更完美。

      1. 删除已废弃的代码

删除项目中的已废弃的包、类、字段、方法、变量、常量、导入、注解、注释、已注释代码、Maven包导入、MyBatis的SQL语句、属性配置字段等,可以精简项目代码便于维护。

        1. 原代码

      1. 删除接口方法的public

对于接口(interface),所有的字段和方法都是 public 的,可以不用显式声明为 public 。

        1. 原代码

public interface JointQueryService {

public abstract List<JointQuery> getQueryList(String billNumber);

public abstract Map<String,Object> getQueryRuleMap(String billNumber);

}

        1. 精简

public interface JointQueryService {

abstract List<JointQuery> getQueryList(String billNumber);

abstract Map<String,Object> getQueryRuleMap(String billNumber);

}

      1. 删除枚举构造方法的 private

对于枚举(menu),构造方法都是 private 的,可以不用显式声明为 private 。

        1. 原代码

public enum EnumExtTypeYXY {

//外部不分档模式

VAR_255("define","varchar",60,0,255);

/**

 * 扩展字段命名方式

 */

private String code;

/**

 * 扩展字段的类型

 */

private String type;

/**

 * 扩展表的扩展数量

 */

private Integer outerCount;

/**

 * 内部表的扩展数量

 */

private Integer innerCount;

        1. 精简

public enum EnumExtTypeYXY {

//外部不分档模式

VAR_255("define","varchar",60,0,255);

/**

 * 扩展字段命名方式

 */

 String code;

/**

 * 扩展字段的类型

 */

 String type;

/**

 * 扩展表的扩展数量

 */

 Integer outerCount;

/**

 * 内部表的扩展数量

 */

 Integer innerCount;

      1. 删除不必要的变量

不必要的变量,只会让代码看起来更繁琐。

        1. 原代码

public Boolean existsUser(Long userId) {

    Boolean exists = userDAO.exists(userId);

    return exists;

}

        1. 精简

public Boolean existsUser(Long userId) {

    return  userDAO.exists(userId);

}

    1. 多级for循环

      1. 原代码

      1. 精简

业务拆解;大循环在外,小循环在内。

    1. 开放性设计 

    1. 兼容性设计 

    1. 其他设计要求

  1. 产品/服务高可用指标

  1. 变更设计 

  1. 附录

猜你喜欢

转载自blog.csdn.net/zhb15810357012/article/details/131380225