代码日常开发中的优化建议小结

1禁用魔法值

什么是魔法值?其应该是C和C++语言中的一个概念,在字节码层面被用作内存地址的偏移量。在JAVA中,这个概念被赋予了新的意义,通常是指在代码中直接出现的数值或字符串,只有在这个数值记述的那部分代码才能明确其含义的数值或字符。

禁用的原因:

  1. 一是可读性差,不代出代码上下文根本不知道描述的是什么;无法辨识1、2是什么含义,而如果换成常量名,如“USER_STATUS_NORMAL”“USER_STATUS_EXCEPTION”等,代码的可读性会大大提高,开发人员能够更直观地理解代码的功能和逻辑。
  2. 代码可维护性低,如果多个地方使用到该值,想将其变更,需要分散地查找替换不易维护;但如果用常量如“MAX_CONNECTIONS”,那么只需要在定义常量的地方修改一次值,所有引用该常量的地方都会自动更新,大大降低了维护成本。
  3. 不便于代码复用,如多个类或方法中需要用到该值都得重新编写代友一,无法直接复用,还容易出错。

比如说以下示例中的zhangSan,

 if ("zhangSan".equals(key)) {
           update.set("password1", document.getString("zhangSan"));
           String ufPassWord = URLDecoder.decode(document.getString("zhangSan"), "UTF-8");
           String password = MD5Util.MD5Encode(MD5Util.decrypt(zhangSan));
           update.set(key, password);  //密码保存
  } 

修改后

     final String PASSWORD_CONTENT = "zhangSan";
 if (PASSWORD_CONTENT .equals(key)) {
           update.set("password1", document.getString(PASSWORD_CONTENT));
           String ufPassWord = URLDecoder.decode(document.getString(PASSWORD_CONTENT), "UTF-8");
           String password = MD5Util.MD5Encode(MD5Util.decrypt(PASSWORD_CONTENT));
           update.set(key, password);  //密码保存
  } 

2使用构造方法替换类变量的注入

原因是

  1. 避免潜在的错误:如果使用字段注入,可能会在对象尚未完全构建之前就尝试访问依赖项,从而导致空指针或其它运行时错误。而构造函数注入则确保了所有依赖在对象构建过程中已被正确注入,即对象创建时就被明确注入了依赖,从而避免问题产生。
  2. 提高可测性:在单元测试中,通过构造函数注入依赖项,可以更容易使用Mock对象来替换实际依赖项,从而提高测试的灵活性和可维护性。
@Service
public class CommonService {
    @Autowired
    private MongoTemplate mongoTemplate;
}

应修改为

@Service
public class CommonService {
    private MongoTemplate mongoTemplate;
    @Autowired
    public CommonService (MongoTemplate  mongoTemplate){
    	this.mongoTemplate=mongoTemplate;
    }

}

3 去掉没有引用的import

原因是

  1. 无用的import会让代码显得不够整洁
  2. 编译速度可能受影响:import会让编译器在编译时额外处理一些信息,过多的无用的import显示会影响到编译器的编译速度。虽然可以忽略不计,但必竟没用,何必留它。
  3. 产生错误,在开发中,如果引入的类名与未使用import中的同名类,就可能出现编译器无法确定使用哪个类的问题.

代码中有一些为空的处理可用Jdk1.8中的Optional替换

原因是

  1. 代码好看,写法优雅,再通俗点是有可能被装B到
  2. 避免NullPointerException:optional可以显式地表示一个值是存在还是不存在,从而减少了因为忘记检查null而引发的NullPointerException
  3. 支持函数式编程、支持链式调用、还可以通过orElse、orElseGet、orElseThrow等提供默认值和替代方案
// 传统方式
String value = getValue();
if (value != null) {
    // 处理非空值
} else {
    // 处理空值
}

修改后

Optional<String> optionValue=Optional.ofNullable(getValue);
optionValue.ifPresent(val ->{
	//处理非空值
	});
	optionValue.orElse(“defalut”); 

Optional介绍

Optional 类是 Java 8 引入的一个新特性,旨在解决空指针异常(NullPointerException)问题,提供一种优雅的处理 null 值的方式。Optional 类是一个容器,它可以包含一个值或者不包含任何值(即为空)。使用 Optional 可以显式地表示一个值可能存在也可能不存在,从而避免直接使用 null 值。

如何使用 Optional
创建 Optional 对象:

  • 使用 Optional.of(value) 创建一个包含非空值的 Optional 对象。
  • 使用 Optional.ofNullable(value) 创建一个可能包含空值的 Optional 对象。
  • 使用 Optional.empty() 创建一个空的 Optional 对象。

检查和获取值:

  • 使用 isPresent() 方法检查 Optional 是否包含值。
  • 使用 get() 方法获取 Optional 中的值,如果 Optional 为空,则抛出 NoSuchElementException。
  • 使用 orElse(other) 方法获取值,如果 Optional 为空,则返回指定的默认值。
  • 使用 orElseGet(Supplier) 方法获取值,如果 Optional 为空,则使用 Supplier 提供的方法生成一个默认值。
  • 使用 orElseThrow(Supplier) 方法获取值,如果 Optional 为空,则使用 Supplier 提供的方法抛出异常。
    链式操作:
  • 使用 map(Function) 方法对 Optional 中的值进行转换。
  • 使用 flatMap(Function) 方法对 Optional 中的值进行转换,该转换函数本身返回一个 Optional 对象。
  • 使用 filter(Predicate) 方法过滤 Optional 中的值。

解决的问题

  • 减少空指针异常:通过使用 Optional,可以避免在代码中直接使用可能为 null 的值,从而减少 NullPointerException 的发生。
  • 提高代码可读性:Optional 强制开发者显式处理可能为空的情况,使得代码更加清晰。
  • 更好的API设计:方法可以返回 Optional 对象,而不是返回 null,这样可以明确告知调用者结果可能不存在

示例:假设我们有一个用户类 User,其中包含一个地址类 Address,地址类中有一个城市字段 city。我们想要获取用户的城市的名称,但是用户、地址或城市可能为 null。

public class User {
    private Address address;
    // getters and setters
}

public class Address {
    private String city;
    // getters and setters
}

// 使用 Optional 避免 NullPointerException
public String getCityName(User user) {
    return Optional.ofNullable(user)
                   .map(User::getAddress)
                   .map(Address::getCity)
                   .orElse("Unknown City");
}
//在这个例子中,如果 user、address 或 city 为 null,getCityName 方法将返回 "Unknown City",而不是抛出 NullPointerException。

注意事项

  • Optional 主要用于解决返回值可能为空的情况,不应用于字段或方法参数。
  • 过度使用 Optional 可能会导致代码变得复杂,应该谨慎使用。
  • Optional.get() 方法在 Optional 为空时会抛出异常,因此在使用前最好先使用 isPresent() 或其他方法进行检查。
  • 通过合理使用 Optional,可以使代码更加健壮和易于维护。

4 避免嵌套的判断

if(!CollectionUtils.isEmpty(statusNameList)){
        if(statusNameList.size() == 1){
              it.put("statusName", statusNameList.get(0));
        }
 }

可修改为

if(!CollectionUtils.isEmpty(statusNameList) && statusNameList.size() == 1){
              it.put("statusName", statusNameList.get(0));     
  }
//或者修改为
Optional.ofNullable(statusNameList)
        .filter(list -> list.size() == 1)
        .ifPresent(list -> it.put("statusName", list.get(0)));

类和方法不要太长

一个类也好,一个方法也好,真心不要太长,把所有的逻辑一股脑写在一起。如果这么做了,后面维护时,去找问题时真的很累,由期是交由本身对此代码逻辑不熟悉的人,眼累、心累,满脑会飘菜刀的,结合单一职责原则SRP,每个方法应该只做一件事,如果逻辑真的很复杂,建议拆成多个小方法,不要循环套训话,判断套判断的。方法长度建议在5-20行适中(当然这不是标准),这样会让逻辑清晰、也有勇气看下去,也便于排查问题或测试。

有的方法返回可以减少变量

 public Document getAreaSecurityTest(){
        Document info = new Document();
        return info;
    }

修改为

 public Document getAreaSecurity(){
        return new Document();
    }

避免在判断逻辑在使用Boolean类型

原因:
Boolean类型只有在需求表示一个可能为null的布尔值时使用,它是一个对象,使用时涉及到自动装箱(boolean到Boolean)和拆箱的操作(Boolean到boolean),底层是有性能开销的。Boolean对象占用现多的内存空间,因为它是一个对象,需要额外的内存来存储对象头和引用。

Boolean b = false
if (b) {  // Noncompliant, it will throw NPE when b == null
  foo();
} else {
  bar();
}

修改为

//这段代码只是想表述不要用包装类
boolean b=false;
if(b){
 ....
}else{
....
}

建议常规场景下StringBuild替换StringBuffer

StringBuilder 和 StringBuffer 都是 Java 中用于处理可变字符串的类,但它们之间有一些关键的区别:

1.线程安全性:

  • StringBuffer 是线程安全的,它的所有公共方法都是同步的,可以在多线程环境中安全使用。
  • StringBuilder 不是线程安全的,它的方法没有同步,因此在单线程环境中性能更好。

2.性能:

  • 由于 StringBuilder 不需要同步,所以在单线程环境中,它的性能通常优于 StringBuffer。

选择使用 StringBuilder 替换 StringBuffer 的情况包括

  • 单线程环境:如果您的代码运行在单线程环境中,或者您确定在多线程环境中对字符串的操作是原子的,那么使用 StringBuilder 可以获得更好的性能。
  • 性能敏感的代码:在性能关键的代码段中,如果字符串操作是主要的性能瓶颈,使用 StringBuilder 可能会带来性能提升。
  • 不需要线程安全:如果您确定您的代码不需要线程安全,或者您有其他机制来保证线程安全,那么使用 StringBuilder 是合适的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值