您的当前位置:首页正文

java变量的声明与赋值分离规范示例

2024-11-04 来源:个人技术集锦

自检:

变量声明之后是否有立即赋值,集合声明之后是否有立即添加元素

存在的问题:

变量的声明和赋值分离带来的问题就是,把赋值的过程与业务处理混杂在一起。

编程规则:

变量要一次性完成初始化

应对策略:

  • 1.在声明前面加上final,用不变性的限制约束代码。
  • 2.用声明式的方式进行集合的初始化。
    • 传统的集合初始化方式是命令式的,而我们要做的就是用声明式的方式进行集合的初始化,让初始化的过程一次性完成。再进一步,以声明式的标准来看代码,会帮助我们发现许多的。

1. 变量的初始化

EpubStatus status = null;
CreateEpubResponse response = createEpub(request);
if (response.getCode() == 201) {
    status = EpubStatus.CREATED;
} else {
    status = EpubStatus.TO_CREATE;
}

上面的代码,从语义上说,第一行的变量初始化其实是没有用的,这是一次假的初始化。这段代码里的变量赋值是在声明很久之后才完成的,也就是说,变量初始化没有一次性完成。

这种代码真正的问题就是不清晰,变量初始化与业务处理混在在一起。通常来说,这种代码后面紧接着就是一大堆更复杂的业务处理。很多代码难读,一个重要的原因就是把不同层面的代码混在了一起。

这种代码在实际的代码库中出现的频率非常高,只不过,它会以各种变形的方式呈现出来。有的变量甚至是在相隔很远的地方才做了真正的赋值,完成了初始化,这中间已经夹杂了很多的业务代码在其中,进一步增加了理解的复杂度。所以,我们编程时要有一个基本原则:变量一次性完成初始化。

final CreateEpubResponse response = createEpub(request);
final EpubStatus status = toEpubStatus(response);
private EpubStatus toEpubStatus(final CreateEpubResponse response) {
    if (response.getCode() == 201) {
        return EpubStatus.CREATED;
    }
    return EpubStatus.TO_CREATE;
}

在这段改进的代码中,我们提取出了一个函数,将 response 转成对应的内部的 EPUB 状态。

还有一点不知道你注意到了没有,在新的变量声明中,我加上了 final,在 Java 的语义中,一个变量加上了 final,也就意味着这个变量不能再次赋值。尽可能编写不变的代码,尽可能使用不变的量。所以,在能够使用 final 的地方尽量使用 final,限制变量的赋值。

对于 Java 程序员来说,还有一个特殊的场景,就是异常处理的场景,强迫你把变量的声明与初始化分开,就像下面这段代码:

InputStream is = null;
try {
    is = new FileInputStream(...);
    ...
} catch (IOException e) {
    ...
} finally {
    if (is != null) {
        is.close();
    }
}

如果采用 Java 7 之后的版本,采用 try-with-resource 的写法,代码就可以更简洁了:

try (InputStream is = new FileInputStream(...)) {
    ...
}

2. 集合的初始化

List<Permission> permissions = new ArrayList<>();
permissions.add(Permission.BOOK_READ);
permissions.add(Permission.BOOK_WRITE);
check.grantTo(Role.AUTHOR, permissions);

这和我们前面所说的变量先声明后赋值,本质上是一回事,都是从一个变量的声明到初始化成一个可用的状态,中间隔了太远的距离。

我们可以使用 Guava(Google 提供的一个 Java 库)进行修改优化:

List<Permission> permissions = ImmutableList.of(
Permission.BOOK_READ,
Permission.BOOK_WRITE
);
check.grantTo(Role.AUTHOR, permissions);

这段代码里的 List 用的是一个 ImmutableList,也就是一个不可变的 List,也就是说,这个 List 一旦创建好了,就是不能修改了,对应的实现就是各种添加、删除之类的方法全部都禁用了。

针对Map同样有类似的用法:

private static Map<Locale, String> CODE_MAPPING = ImmutableMap.of(
LOCALE.ENGLISH, "EN",
LOCALE.CHINESE, "CH"
);

对比我们改造前后的代码,二者之间还有一个更关键的区别:前面的代码是命令式的代码,而后面的代码是声明式的代码。

命令式的代码,就是告诉你“怎么做”的代码,就像改造前的代码,声明一个集合,然后添加一个元素,再添加一个元素。而声明式的代码,是告诉你“做什么”的代码,改造后就是,我要一个包含了这两个元素的集合。

您可能感兴趣的文章:
Top