凌云时刻 · 技术
导读:论术悟道,一览 Java 代码精简的十一种“术”,追寻技术工匠之道。
作者 | 常意
来源 | 凌云时刻(微信号:linuxpk)
前言
古语有云:
道为术之灵,术为道之体;以道统术,以术得道。
其中:“道”指“规律、道理、理论”,“术”指“方法、技巧、技术”。意思是:“道”是“术”的灵魂,“术”是“道”的肉体;可以用“道”来统管“术”,也可以从“术”中获得“道”。
在拜读大佬孤尽的文章时,感受最深的一句话就是:“优质的代码一定是少即是多的精兵原则”,这就是大佬的代码精简之“道”。
工匠追求“术”到极致,其实就是在寻“道”,且离悟“道”也就不远了,亦或是已经得道,这就是“工匠精神”——一种追求“以术得道”的精神。如果一个工匠只满足于“术”,不能追求“术”到极致去悟“道”,那只是一个靠“术”养家糊口的工匠而已。作者根据多年来的实践探索,总结了大量的 Java 代码精简之“术”,试图阐述出心中的 Java 代码精简之“道”。
1. 利用语法
1.1 利用三元表达式
普通:
String title;if (isMember(phone)) { title = "会员";} else { title = "游客";}
精简:
String title = isMember(phone) ? "会员" : "游客";
注意:对于包装类型的算术计算,需要注意避免拆包时的空指针问题。
1.2 利用 for-each 语句
从 Java 5 起,提供了 for-each 循环,简化了数组和集合的循环遍历。for-each 循环允许你无需保持传统 for 循环中的索引就可以遍历数组,或在使用迭代器时无需在 while 循环中调用 hasNext 方法和 next 方法就可以遍历集合。
普通:
double[] values = ...;for(int i = 0; i < values.length; i++) { double value = values[i]; // TODO: 处理value}
List valueList = ...;Iterator iterator = valueList.iterator();while (iterator.hasNext()) { Double value = iterator.next(); // TODO: 处理value}
精简:
double[] values = ...;for(double value : values) { // TODO: 处理value}
List valueList = ...;for(Double value : valueList) { // TODO: 处理value}
1.3 利用 try-with-resource 语句
所有实现 Closeable 接口的“资源”,均可采用 try-with-resource 进行简化。
普通:
BufferedReader reader = null;try { reader = new BufferedReader(new FileReader("cities.csv")); String line; while ((line = reader.readLine()) != null) { // TODO: 处理line }} catch (IOException e) { log.error("读取文件异常", e);} finally { if (reader != null) { try { reader.close(); } catch (IOException e) { log.error("关闭文件异常", e); } }}
精简:
try (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) { String line; while ((line = reader.readLine()) != null) { // TODO: 处理line }} catch (IOException e) { log.error("读取文件异常", e);}
1.4 利用 return 关键字
利用 return 关键字,可以提前函数返回,避免定义中间变量。
普通:
public static boolean hasSuper(@NonNull List userList) { boolean hasSuper = false; for (UserDO user : userList) { if (Boolean.TRUE.equals(user.getIsSuper())) { hasSuper = true; break; } } return hasSuper;}
精简:
public static boolean hasSuper(@NonNull List userList) { for (UserDO user : userList) { if (Boolean.TRUE.equals(user.getIsSuper())) { return true; } } return false;}
1.5 利用 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);
精简:
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.6 利用 lambda 表达式
Java 8 发布以后,lambda 表达式大量替代匿名内部类的使用,在简化了代码的同时,更突出了原有匿名内部类中真正有用的那部分代码。
普通:
new Thread(new Runnable() { public void run() { // 线程处理代码 }}).start();
精简:
new Thread(() -> { // 线程处理代码}).start();
1.7 利用方法引用
方法引用(::),可以简化 lambda 表达式,省略变量声明和函数调用。
普通:
Arrays.sort(nameArray, (a, b) -> a.compareToIgnoreCase(b));List userIdList = userList.stream() .map(user -> user.getId()) .collect(Collectors.toList());
精简:
Arrays.sort(nameArray, String::compareToIgnoreCase);
List userIdList = userList.stream()
.map(UserDO::getId)
.collect(Collectors.toList());
静态导入(import static),当程序中大量使用同一静态常量和函数时,可以简化静态常量和函数的引用。
普通:
List areaList = radiusList.stream().map(r -> Math.PI * Math.pow(r, 2)).collect(Collectors.toList());...
精简:
import static java.lang.Math.PI;import static java.lang.Math.pow;import static java.util.stream.Collectors.toList;
List areaList = radiusList.stream().map(r -> PI * pow(r, 2)).collect(toList());...
注意:静态引入容易造成代码阅读困难,所以在实际项目中应该警慎使用。
Java 的异常分为两类:Checked 异常和 Unchecked 异常。Unchecked 异常继承了RuntimeException ,特点是代码不需要处理它们也能通过编译,所以它们称作 Unchecked 异常。利用 Unchecked 异常,可以避免不必要的 try-catch 和 throws 异常处理。
普通:
@Servicepublic class UserService { public void createUser(UserCreateVO create, OpUserVO user) throws BusinessException { checkOperatorUser(user); ... } private void checkOperatorUser(OpUserVO user) throws BusinessException { if (!hasPermission(user)) { throw new BusinessException("用户无操作权限"); } ... } ...}
@RestController@RequestMapping("/user")public class UserController { @Autowired private UserService userService;
@PostMapping("/createUser") public Result createUser(@RequestBody @Valid UserCreateVO create, OpUserVO user) throws BusinessException { userService.createUser(create, user); return Result.success(); } ...}
精简:
@Servicepublic class UserService { public void createUser(UserCreateVO create, OpUserVO user) { checkOperatorUser(user); ... } private void checkOperatorUser(OpUserVO user) { if (!hasPermission(user)) { throw new BusinessRuntimeException("用户无操作权限"); } ... } ...}
@RestController@RequestMapping("/user")public class UserController { @Autowired private UserService userService;
@PostMapping("/createUser") public Result createUser(@RequestBody @Valid UserCreateVO create, OpUserVO user) { userService.createUser(create, user); return Result.success(); } ...}
2. 利用注解
Lombok 提供了一组有用的注解,可以用来消除Java类中的大量样板代码。
普通:
public class UserVO { private Long id; private String name; public Long getId() { return this.id; } public void setId(Long id) { this.id = id; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } ...}
精简:
@Getter@Setter@ToStringpublic class UserVO { private Long id; private String name; ...}
普通:
@Getter@Setter@ToStringpublic class UserCreateVO { @NotBlank(message = "用户名称不能为空") private String name; @NotNull(message = "公司标识不能为空") private Long companyId; ...}@Service@Validatedpublic class UserService { public Long createUser(@Valid UserCreateVO create) { // TODO: 创建用户 return null; }}
精简:
@Getter
@Setter
@ToString
public class UserCreateVO {
@NotBlank(message = "用户名称不能为空")
private String name;
@NotNull(message = "公司标识不能为空")
private Long companyId;
...
}
@Service
@Validated
public class UserService {
public Long createUser(@Valid UserCreateVO create) {
// TODO: 创建用户
return null;
}
}
Spring 的 @NonNull 注解,用于标注参数或返回值非空,适用于项目内部团队协作。只要实现方和调用方遵循规范,可以避免不必要的空值判断,这充分体现了阿里的“新六脉神剑”提倡的“因为信任,所以简单”。
普通:
public List queryCompanyUser(Long companyId) { // 检查公司标识 if (companyId == null) { return null; }
// 查询返回用户 List userList = userDAO.queryByCompanyId(companyId); return userList.stream().map(this::transUser).collect(Collectors.toList());}
Long companyId = 1L;List userList = queryCompanyUser(companyId);if (CollectionUtils.isNotEmpty(userList)) { for (UserVO user : userList) { // TODO: 处理公司用户 }}
精简:
public @NonNull List queryCompanyUser(@NonNull Long companyId) { List userList = userDAO.queryByCompanyId(companyId); return userList.stream().map(this::transUser).collect(Collectors.toList());}
Long companyId = 1L;List userList = queryCompanyUser(companyId);for (UserVO user : userList) { // TODO: 处理公司用户}
注解有以下特性可用于精简注解声明:
当注解属性值跟默认值一致时,可以删除该属性赋值;
当注解只有value属性时,可以去掉value进行简写;
当注解属性组合等于另一个特定注解时,直接采用该特定注解。
普通:
@Lazy(true);
@Service(value = "userService")
@RequestMapping(path = "/getUser", method = RequestMethod.GET)
精简:
@Lazy
@Service("userService")
@GetMapping("/getUser")
3. 利用泛型
3.1 泛型接口
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?


微信扫码登录