【Java 编程】Java 开发实践与经验:BetterJava


原文: https://www.seancassidy.me/better-java.html

Github

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 应用的部署变得简单,比如 DropwizardSpring 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

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

猜你喜欢

转载自blog.csdn.net/antony1776/article/details/85063157
今日推荐