您当前的位置: 首页 >  Java

凌云时刻

暂无认证

  • 0浏览

    0关注

    1437博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Java 代码精简之道 | 凌云时刻

凌云时刻 发布时间:2020-05-13 18:28:46 ,浏览量:0

凌云时刻 · 技术

导读:论术悟道,一览 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());
 1.8 利用静态导入

静态导入(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());...


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

 1.9 利用 unchecked 异常

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. 利用注解

 2.1 利用 Lombok 注解

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;    ...}




 2.2 利用 Validation 注解

普通:

@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;
    }
}
 2.3 利用 @NonNull 注解

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: 处理公司用户}
 2.4 利用注解特性

注解有以下特性可用于精简注解声明:

  1. 当注解属性值跟默认值一致时,可以删除该属性赋值;

  2. 当注解只有value属性时,可以去掉value进行简写;

  3. 当注解属性组合等于另一个特定注解时,直接采用该特定注解。

普通:

@Lazy(true);
@Service(value = "userService")
@RequestMapping(path = "/getUser", method = RequestMethod.GET)

精简:

@Lazy
@Service("userService")
@GetMapping("/getUser")

3. 利用泛型

 3.1 泛型接口

关注
打赏
1663816507
查看更多评论
立即登录/注册

微信扫码登录

0.3885s