文章目录
原文: https://www.seancassidy.me/better-java.html
Java 当然是一门很好的编程语言,它非常流行,但也不可否认比较难用,冗长、笨拙、刻板,这是用 Java 编程时常会有的体验。Java 8 带来了很多新特性,让程序员可以写出更简洁、流畅的 Java 代码。
1. 风格
传统的 JavaBean 风格的代码让程序显得拖沓、烦冗!
比如:
public class DataHolder {
private String data;
public DataHolder() {
}
public void setData(String data) {
this.data = data;
}
public String getData() {
return this.data;
}
}
这样的代码好吗?
好的代码应该是让复杂的事情变简单,而不是让简单的事情变复杂。尽管大部分代码都可以通过 IDE 自动生成,但这种代码信息密度太低,极大的影响可读性。So, Don’t do this!
这时,可以尝试 C 结构体风格的 Java 类:
public class DataHolder {
public final String data;
public DataHolder(String data) {
this.data = data;
}
}
- 删除掉多余的 setter,getter 方法
- 默认为 immutable,简化逻辑
对于复杂的对象,可以使用建造者模式
来构建,例如:
public class ComplicatedDataHolder {
public final String data;
public final int num;
// lots more fields and a constructor
public static class Builder {
private String data;
private int num;
public Builder data(String data) {
this.data = data;
return this;
}
public Builder num(int num) {
this.num = num;
return this;
}
public ComplicatedDataHolder build() {
return new ComplicatedDataHolder(data, num); // etc
}
}
}
- Builder 是一个内部类,用于构建对象;
- Builder 是 mutable 的;
- 当调用 build() 方法时,会产生一个 immutable ComplicatedDataHolder 类实例。
使用示例:
final ComplicatedDataHolder cdh = new ComplicatedDataHolder.Builder()
.data("set this")
.num(523)
.build();
这是构建者模式的一种实例,通过它可以让代码显得更加流畅、可读。
2. 依赖注入
依赖注入(Dependency injection)让软件具有更好的可测性,在面向对象的设计与开发中广泛应用。
Java 可以使用 Spring 框架提供的 DI 功能。注入的方式有三种:xml 配置文件,注解,编码。
除了 Spring,也可以考虑使用 Dagger 或 Guice。
3. 避免使用 null
尽可能的避免使用 null,也不要在方法中返回 null。必须使用 null 的场景,需添加 @Nullable 注解。
Java 8 提供了 Optional 类型,当一个值可能为 null 时,用 Optional 类来包裹它,如下:
public class FooWidget {
private final String data;
private final Optional<Bar> bar;
public FooWidget(String data) {
this(data, Optional.empty());
}
public FooWidget(String data, Optional<Bar> bar) {
this.data = data;
this.bar = bar;
}
public Optional<Bar> getBar() {
return bar;
}
}
这样的话,返回结果就永远不会是 null 了,Optional 有类似 isPresent 的方法,可以编写如下所示的代码:
final Optional<FooWidget> fooWidget = maybeGetFooWidget();
final Baz baz = fooWidget.flatMap(FooWidget::getBar)
.flatMap(BarWidget::getBaz)
.orElse(defaultBaz);
这样就不用去写一连串的 check null 代码了。
目前,标准库对 Optional 的支持还不够完善,可以考虑使用 guava 等三方库提供的 Optional 特性。
4. Immutable-by-default
变量、类、集合默认应该为 immutable(不可编辑),除非有特殊需要。
变量和类对象可以通过 final 声明为 immutable。
集合可以使用 Guava 提供的 ImmutableMap,ImmutableList,或者 ImmutableSet 类。它们都有自己的 Builder 类,用来动态构建,最后调用 builder() 方法返回构建的 Immutable 集合实例。
5. 接口默认方法代替各种 util 类
项目中常常会有各种各样的 util 类,有时候用着挺方便,但这并不是一种良好的开发习惯。
Java 8 中的接口可以定义 default 方法,可以试着将通用方法放在接口中,这样任何想使用这些方法的类都可以通过实现接口的方式获得。
public interface Thrower {
default void throwIfCondition(boolean condition, String msg) {
// ...
}
default void throwAorB(Throwable a, Throwable b, boolean throwA) {
// ...
}
}
6. Streams
Java 8 提供了 stream 和 lambda,可以写出下面形式的代码:
final List<String> filtered = list.stream()
.filter(s -> s.startsWith("s"))
.map(s -> s.toUpperCase());
而不是:
final List<String> filtered = Lists.newArrayList();
for (String str : list) {
if (str.startsWith("s") {
filtered.add(str.toUpperCase());
}
}
是不是清爽了很多,又可以愉快的编程了!
7. 部署
框架(Framework)让 Java 应用的部署变得简单,比如 Dropwizard 和 Spring Boot,除此之外,还有 Play framework,也可以考虑。
这些框架就是为了降低部署程序的复杂度,让程序变得开箱即用。对于新手来说,使用框架能让其专注于编程本身;对于项目来说,使用框架可以实现快速构建!
Jar 的部署方式,比 War 或 Ear 更简单。
当然,框架只能保证通用性需求,如果项目需要有特殊的部署需求的话,则需要进行定制。
8. Maven
https://books.sonatype.com/mvnex-book/reference/index.html
Maven 依然是构建、打包、测试 Java 程序的标准工具!如果你是新手,你应该从 Maven 开始。同时 Gradle 作为后起之秀,也有它的优点。
Maven repository,可以使用 Artifactory 或 Nexus。
9. 持续集成
项目开发越来越敏捷化,因此持续集成也就变得越来越重要。
Jenkins 和 Travis-CI 是必然选择。
代码覆盖率很有用,可以考虑 Cobertura 提供的 Maven 插件。
10. 自动化管理
Chef,Puppet,Ansible
11. 常用库
Java 最大的优点就是拥有丰富的三方库,下面列出的是一些比较常用的:
Apache Commons
- Commons Codec: 大量的 Base64/hex 字符串的编解码工具,不用自己去写了
- Commons Lang: 字符集/字符串的构建、操作,各种常用杂散工具
- Commons IO:FileUtils.copyDirectory, FileUtils.writeStringToFile, IOUtils.readLines 等等
Guava
guava 是 google 提供的 Java 通用库,包含了很多重要但 JDK 没有提供的特性。
- Cache:
- Immutable:
- Events
…
Gson
google 提供的 JSON 库
final Gson gson = new Gson();
final String json = gson.toJson(fooWidget);
final FooWidget newFooWidget = gson.fromJson(json, FooWidget.class);
Java Tuples
Java 语言本身没有 tuple 类型,可以使用 javatuples 库,如下:
Pair<String, Integer> func(String input) {
// something...
return Pair.with(stringResult, intResult);
}
Joda-Time
最好的时间处理库,Java 8 之前的项目可以考虑使用。
Lombok
一个有趣的库,通过注解,可以编写如下代码:
public class Foo {
@Getter @Setter private int var;
}
jOOQ
如果你不喜欢厚重的ORM框架,如Hibernate,可是试着用 jOOQ,使用它可以编写如下风格的 SQL 代码:
// Typesafely execute the SQL statement directly with jOOQ
Result<Record3<String, String, String>> result =
create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
.from(BOOK)
.join(AUTHOR)
.on(BOOK.AUTHOR_ID.equal(AUTHOR.ID))
.where(BOOK.PUBLISHED_IN.equal(1948))
.fetch();
既灵活、又简洁!
Eclipse Memory Analyzer
内存分析工具,可以排查内存泄漏问题。
可以使用 jmap 来生成 heap dump 文件:
$ jmap -dump:live,format=b,file=heapdump.hprof -F 8152
Attaching to process ID 8152, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 23.25-b01
Dumping heap to heapdump.hprof ...
... snip ...
Heap dump file created