BetterJava-如何更好的使用 Java

BarryBlanki 8年前發布 | 35K 次閱讀 Java Java開發

Java 雖作為最流行的編程語言之一,但是似乎并沒有什么人很享受用它。好吧,Java 確實是這樣的一門編程語言,從最近發布不久的 Java 8 開始,為了更好的使用 Java,我決定收集一些庫,實踐和工具等相關資料。“更好” 是主觀的,所以推薦使用我所說的建議的某些部分,而不是一下子全部按照這些建議來做。請盡情添加其他意見并提交 PR。

這篇文章原始發布在 我的博客.

目錄

Style

Java 傳統的代碼風格是被用來編寫非常復雜的企業級 JavaBean。新的代碼風格看起來會更加整潔,更加正確,并且更加簡單。

Structs

對我們程序員來說,包裝數據是最簡單的事情之一。下面是傳統的通過定義一個 JavaBean 的實現方式:

public class DataHolder {
    private String data;

    public DataHolder() {
    }

    public void setData(String data) {
        this.data = data;
    }

    public String getData() {
        return this.data;
    }
}

這種方式既繁瑣又浪費代碼。即使你的 IDE 可以自動生成這些代碼,也是浪費。因此,別這么干.

相反,我更喜歡 C 語言保存數據的風格來寫一個類:

public class DataHolder {
    public final String data;

    public DataHolder(String data) {
        this.data = data;
    }
}

這樣不僅減少了近一半的代碼行數。并且,這個類里面保存的數據除了你去繼承它,否則不會改變,由于它不可變性,我們可以認為這會更加簡單。

如果你想保存很容易修改的對象數據,像 Map 或者 List,你應該使用 ImmutableMap 或者 ImmutableList,這些會在不變性那一部分討論。

The Builder Pattern

如果你想用這種構造的方式構造更復雜的對象,請考慮構建器模式。

你可以建一個靜態內部類來構建你的對象。構建器構建對象的時候,對象的狀態是可變的,但是一旦你調用了 build 方法之后,構建的對象就變成了不可變的了。

想象一下我們有一個更復雜的 DataHolder。那么它的構建器看起來應該是這樣的:

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

然后調用它:

final ComplicatedDataHolder cdh = new ComplicatedDataHolder.Builder()
    .data("set this")
    .num(523)
    .build();

這有關于構建器更好的例子,他會讓你感受到構建器到底是怎么回事。它沒有使用許多我們盡力避免使用的樣板,并且它會給你不可變的對象和非常好用的接口。

可以考慮下在眾多的庫中選擇一個來幫你生成構建器,取代你親手去寫構建器的方式。

Immutable Object Generation

如果你要手動創建許多不可變對象,請考慮用注解處理器的方式從它們的接口自動生成。它使樣板代碼減少到最小化,減少產生 bug 的可能性,促進了對象的不可變性。看這presentation 有常見的 Java 設計模式中一些問題的有趣的討論。

一些非常棒的代碼生成庫如 [immutables] (https://github.com/immutables/immutables), 谷歌的 auto-value 和 Lombok

Exceptions

使用檢查異常的時候一定要注意,或者干脆別用。它會強制你去用 try/catch 代碼塊包裹住可能拋出異常的部分。比較好的方式就是使你自定義的異常繼承自運行時異常來取而代之。這樣,可以讓你的用戶使用他們喜歡的方式去處理異常,而不是每次拋出異常的時候都強制它們去處理/聲明,這樣會污染代碼。

一個比較漂亮的絕招是在你的方法異常聲明中聲明 RuntimeExceptions。這對編譯器沒有影響,但是可以通過文檔告訴你的用戶在這里可能會有異常拋出。

Dependency injection

在軟件工程領域,而不僅是在 Java 領域,使用依賴注入是編寫可測試軟件最好的方法之一。 由于 Java 強烈鼓勵使用面向對象的設計,所以在 Java 中為了開發可測試軟件,你不得不使用依賴注入。

在 Java 中,通常使用Spring 框架來完成依賴注入。Spring 有基于代碼的和基于 XML 配置文件的兩種連接方式。如果你使用基于 XML 配置文件的方式,注意不要過度使用 Spring,正是由于它使用的基于 XML 配置文件的格式。在 XML 配置文件中絕對不應該有邏輯或者控制結構。它應該僅僅被用來做依賴注入。

使用 Google 和 Square 的 Dagger 或者 Google 的 Guice 庫是 Spring 比較好的替代品。它們不使用像 Spring 那樣的 XML 配置文件的格式,相反它們把注入邏輯以注解的方式寫到代碼中。

Avoid Nulls

盡量避免使用空值。不要返回 null 的集合,你應該返回一個 empty 的集合。如果你確實準備使用 null 請考慮使用 @Nullable 注解。IntelliJ IDEA 內置支持 @Nullable 注解。

閱讀計算機科學領域最糟糕的錯誤了解更多為何不使用 null。

如果你使用的是 Java 8,你可以用新出的優秀的 Optional 類型。如果有一個值你不確定是否存在,你可以像這樣在類中用 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;
    }
}

這樣,現在你可以清晰地知道 data 肯定不為 null,但是 bar 不清楚是不是存在。Optional 有如 isPresent 這樣的方法,可以用來檢查是否為 null,感覺和原來的方式并沒有太大區別。但是它允許你可以這樣寫:

final Optional<FooWidget> fooWidget = maybeGetFooWidget();
final Baz baz = fooWidget.flatMap(FooWidget::getBar)
                         .flatMap(BarWidget::getBaz)
                         .orElse(defaultBaz);

這樣比寫一連串的判斷是否為空的檢查代碼更好。使用 Optional 唯一不好的是標準庫對 Optional 的支持并不是很好,所以對 null 的處理仍然是必要的。

Immutable-by-default

變量,類和集合應該設置為不可變的,除非你有很好的理由去修改他們。

變量可以用 final 關鍵字使起不可變:

final FooWidget fooWidget;
if (condition()) {
    fooWidget = getWidget();
} else {
    try {
        fooWidget = cachedFooWidget.get();
    } catch (CachingException e) {
        log.error("Couldn't get cached value", e);
        throw e;
    }
}
// fooWidget is guaranteed to be set here

現在你可以確定 fooWidget 對象不會意外地被重新賦值了。final 關鍵詞也可以在 if/else 和 try/catch 代碼塊中使用。當然,如果 fooWidget 對象本身不是不可變的,你可以很容易去修改它。

使用集合的時候,任何可能的情況下盡量使用 Guava 的 ImmutableMapImmutableList, 或者 ImmutableSet 類。這些類都有構建器,你可以很容易地動態構建集合,一旦你執行了 build 方法,集合就變成了不可變的。

類應該聲明不可變的字段(通過 final 實現)和不可變的集合使該類不可變。或者,可以對類本身使用 final 關鍵詞,這樣這個類就不會被繼承也不會被修改了。

Avoid lots of Util classes

如果你發現在你正在往工具類中添加很多方法,就要注意了。

public class MiscUtil {
    public static String frobnicateString(String base, int times) {
        // ... etc
    }

    public static void throwIfCondition(boolean condition, String msg) {
        // ... etc
    }
}

乍一看這些工具類似乎很不錯,因為里面的那些方法放在別處確實都不太合適。因此,你以可重用代碼的名義全放這了。

這個想法比本身這么做還要糟糕。請把這些類放到它應該在的地方去并積極重構。不要命名一些像 “MiscUtils” 或者 “ExtrasLibrary” 這樣的很普通的類,包或者庫。這會鼓勵產生無關代碼。

Formatting

格式化代碼對大多數程序員來說并沒有它應有的那么重要。統一化你的代碼格式對閱讀你的代碼的人有幫助嗎?當然了。但是別在為了 if 代碼塊匹配添加空格上耗一天。

如果你確實需要一個代碼格式風格的教程,我高度推薦 Google’s Java Style 這個教程。寫的最好的部分是 Programming Practices。絕對值得一讀。

Javadoc

文檔對對你代碼的閱讀著來說也很重要。這意味著你要給出使用示例,并且給出你的變量,方法和類清晰地描述。

這樣做的必然結果是不要對不需要寫文檔的地方填寫文檔。如果你對一個參數的含義沒什么可說的,或者它本身已經很明顯是什么意思了,就不要為其寫文檔了。統一樣板的文檔比沒有文檔更加糟糕,這樣會讓讀你代碼的人誤以為那就是文檔。

Streams

Java 8 有很棒的 stream and lambda 語法。你可以像這樣來寫代碼:

final List<String> filtered = list.stream()
    .filter(s -> s.startsWith("s"))
    .map(s -> s.toUpperCase())
    .collect(Collectors.toList());

取代這樣的寫法:

final List<String> filtered = new ArrayList<>();
for (String str : list) {
    if (str.startsWith("s") {
        filtered.add(str.toUpperCase());
    }
}

它讓你可以寫更多的流暢的代碼,并且可讀性更高。

Deploying

Java 的部署問題確實有點棘手。現如今有兩種主流的方式:使用框架或者靈活性更高的內部研發的解決方案。

Frameworks

由于 Java 的部署并不容易,所以使用框架還是很有幫助的。最好的兩個框架是 Dropwizard和 Spring BootPlay 框架 也可以被看作為一種部署框架。

這些框架都是盡力地降低你部署代碼的壁壘。它們對 Java 新手或者想提高效率的人尤有幫助。單獨的 JAR 包部署會比復雜的 WAR 包或者 EAR 包部署更簡單一點。

然而,這些框架并沒有你想象的那么靈活,如果你的項目的開發者選擇的框架并不合適,你不得不遷移到手動配置更多的部署方案上來。

Maven

不錯的替代工具Gradle.

Maven 仍然是構建,打包和測試的標準。有很多不錯的替代工具,如 Gradle,但是他們同樣都沒有像 Maven 那樣的適應性。如果你是 Maven 新手,你應該從Maven 實例這里開始。

我喜歡用一個根 POM(Project Object Model,項目對象模型)來管理所有用到的外部依賴。它會像這個樣子。這個根 POM 僅僅包含一個外部依賴,但是如果你的產品足夠大,你將會有幾十個外部依賴了。你的根 POM 應該像其他 Java 項目一樣采用版本控制和發布的方式,有一個自己的項目。

如果你認為你的根 POM 每添加一個外部依賴都打上一個標簽很麻煩,那你肯定沒有遇到過為了排查依賴錯誤引起的問題,浪費一周的時間翻遍整個項目的情況。

你所有的 Maven 項目都應該包含你的根 POM,以及這些項目的所有版本信息。這樣你會清除地了解到你們公司選擇的每一個外部依賴的版本,以及所有正確的 Maven 插件。如果你要引入很多的外部依賴,它將會是這樣子的:

<dependencies>
    <dependency>
        <groupId>org.third.party</groupId>
        <artifactId>some-artifact</artifactId>
    </dependency>
</dependencies>

如果你想使用內部依賴,它應該被每一個單獨項目的 **** 部分來管理。否則那將會很難保持根 POM 的版本號是正常的。

Dependency Convergence

Java 最好的一方面就是擁有大量的第三方庫可以做任何事。基本上每一個 API 或者工具包都有一個 Java SDK,可以很方便的用 Maven 引入。

并且這些第三方 Java 庫本身依賴特定版本的其他的庫。如果你引入足夠多的庫,你會發現有些庫的版本是沖突的,像這樣:

Foo library depends on Bar library v1.0
Widget library depends on Bar library v0.9

你的項目到底要引入哪一個版本呢?

如果你的項目依賴于不同版本的同一個庫,使用 Maven 依賴趨同插件構建時將會報錯。然后你有兩個方案來解決這個沖突:

  1. 在你的 dependencyManagement 部分明確地支出你所使用的 Bar 的版本號
  2. 在 FOO 或者 Widget 中排除對 Bar 的依賴。

這兩個方案到底選哪一個要看你面對的是什么情況:如果你想跟蹤一個項目的版本,那么選擇排除的方案是不錯的。另一方面,如果你想明確地指出它,你可以選擇一個版本,盡管你在需要更新其他依賴的時候也需要更新它。

Continuous Integration

很明顯,你需要某種形式的持續集成服務器來幫你不斷構建你的快照版本和基于 git 標簽構建。

Jenkins 和 Travis-CI 就成了很自然的選擇.

代碼覆蓋率非常有用,Cobertura 就有 一個很好的 Maven 插件 a good Maven plugin 并且支持 CI。還有一些其他的支持 Java 的代碼覆蓋率工具,但是我只用過 Cobertura。

Maven repository

你需要一個地方存儲你生成的 JAR 包,WAR 包或者 EAR 包,因此,你需要一個倉庫。

一般選擇有 Artifactory 和 Nexus 這兩個。它們都可以用,但是它們都有著各自的優缺點。

你應該有自己的 Artifactory/Nexus 設備和鏡像 使你的依賴基于此。這樣就不會由于上游的 Maven 庫宕機而使你的構建崩潰了。

Configuration management

現在,你的代碼已經編譯完了,你的倉庫也跑起來了,最終你需要把你的代碼從開發環境部署到生產環境了。到了這里,千萬不要吝嗇,因為將來很長一段時間,你會從這些自動化方式中嘗到很多的甜頭。

ChefPuppet,和 Ansible 是很典型的選擇。我曾經也寫了一個叫 Squadron 的也可供選擇,當然,我認為你應該仔細看看這個,因為它使用起來比其他的更為簡單方便。

無論你選擇了什么工具,不要忘了使你的部署實現自動化。

Libraries

對 Java 來說,擁有大量的擴展庫也許是最大的特點了。下面這些一小部分的擴展庫對大部分人來說很適用的。

Missing Features

Java 標準庫曾經作出過驚人的改進,但是現在來看,它仍然缺少一些關鍵的特性。

Apache Commons

Apache Commons 項目 擁有大量的有用的擴展庫。

Commons Codec 對 Base64 和 16 進制字符串來說有很多有用的編/解碼方法。不要再浪費時間重寫這些東西了。

Commons Lang 有許多關于字符串的操作和創建,字符集和許多各種各樣的實用的方法。

Commons IO 擁有所有你能想到的關于文件操作的方法。有FileUtils.copyDirectoryFileUtils.writeStringToFileIOUtils.readLines 和更多實用的方法。

Guava

Guava 是谷歌優秀的對 Java 標準庫缺少的特性進行補充的擴展庫。雖然這很難提煉總結出我有多喜歡這個庫,但是我會盡力的。

Cache 讓你可以用很簡單的方法,實現把網絡訪問,磁盤訪問,緩存函數或者其他任何你想要緩存的內容,緩存到內存當中。你僅僅只需要實現 CacheBuilder 類并且告訴 Guava 怎么樣構建你的緩存,一切就搞定了!

Immutable 集合。它有許多如:ImmutableMapImmutableList,或者甚至ImmutableSortedMultiSet 等不可變集合可以使用,如果你喜歡用這種風格的話。

我也喜歡用 Guava 的方式來寫一些可變的集合:

// Instead of
final Map<String, Widget> map = new HashMap<>();

// You can use
final Map<String, Widget> map = Maps.newHashMap();

它還有一些靜態類如 ListsMapsSets 等。使用起來它們顯得更整潔,并且可讀性更強。

如果你堅持使用 Java 6 或者 7 的話,你可以使用 Collections2 這個類,它有一些像 filter 和 transform 這樣的方法。能夠讓你沒有 Java 8 的 Stream 的支持也能寫出流暢的代碼。

Guava 也可以做一些很簡單的事情,比如 Joiner 類可以用來用分隔符把字符串拼接起來,并且可以用忽略的方式來處理打斷程序的數據。

Gson

谷歌的 Gson 庫是一個簡單快速的 JSON 解析庫。可以這樣用:

final Gson gson = new Gson();
final String json = gson.toJson(fooWidget);

final FooWidget newFooWidget = gson.fromJson(json, FooWidget.class);

這用起來真的很簡單,很愉悅。Gson 用戶手冊 有很多的使用示例。

Java Tuples

Java 令我比較煩惱的問題之一 Java 標準庫中沒有內置對元組的支持。幸運的是,Java tuples 項目解決了這個問題。

它使用用起來很簡單,很棒:

Pair<String, Integer> func(String input) {
    // something...
    return Pair.with(stringResult, intResult);
}

Javaslang

Javaslang 是一個函數式編程庫,它被設計用來彌補本應該出現在 Java 8 中但缺失的一些特性。它有這樣的一些特點:

  • 一個全新函數式集合庫
  • 緊密集成的元組功能
  • 模式匹配
  • 通過不可變性保證線程安全
  • 饑漢式和懶漢式的數據類型
  • 通過 Option 實現了 null 的安全性
  • 通過 Try 更好的實現異常處理

有一些 Java 庫依賴于原始的 Java 集合類。它們通過以面向對象和被設計為可變的方式來保證和其他的類的兼容性。而 Javaslang 的集合的設計靈感來源于 Haskell, Clojure 和 Scala,是一個全新的飛躍。它們被設計為函數式風格并且遵循不可變性的設計風格。

像下面這樣的代碼就可以自動實現線程安全,并且不用 try-catch 語句處理異常:

// Success/Failure containing the result/exception
public static Try<User> getUser(int userId) {
    return Try.of(() -> DB.findUser(userId))
        .recover(x -> Match.of(x)
            .whenType(RemoteException.class).then(e -> ...)
            .whenType(SQLException.class).then(e -> ...));
}

// Thread-safe, reusable collections
public static List<String> sayByeBye() {
    return List.of("bye, "bye", "collect", "mania")
               .map(String::toUpperCase)
               .intersperse(" ");
}

Joda-Time

Joda-Time 是我用過的最簡單的時間處理庫。簡單,直接,并且很容易測試。夫復何求?

因為 Java 8 已經有了自己的新的 時間處理庫, 所以如果你還沒有用 Java 8,你需要這一個庫足矣。

Lombok

Lombok 是一個很有意思的庫。它可以讓你以注解的方式減少 Java 中糟糕的樣板代碼。

想為你的類的變量添加 setter 和 getter 方法嗎?像這樣:

public class Foo {
    @Getter @Setter private int var;
}

現在你就可以這么用了:

final Foo foo = new Foo();
foo.setVar(5);

這還有很多例子。我在之前的產品中還沒有用過 Lombok,但是現在我等不急了。

Play framework

好的替代品Jersey 或者 Spark

在 Java 實現 RESTful web services 有兩大主要陣營:JAX-RS 和其他。

JAX-RS 是傳統的實現方式。你可以用像 Jersey 這樣的框架,以注解的方式來實現接口及其實現的結合。這樣你就可以很容易的根據接口類來開發客戶端。

Play 框架 基于 JVM 的 web services 實現和其他根本框架不同:它有一個路由文件,你寫的類要和路由文件中的路由信息關聯起來。Play 框架其實是一個完整的 MVC 框架,但是你可以很簡單地僅僅使用它的 REST web services 部分的功能。

它同時支持 Java 和 Scala。雖然對重點支持的 Scala 稍有不足,但是對 Java 的支持還是很好用的。

如果你在 Python 中用過像 Flask 這樣的微框架,你對 Spark 肯定會很熟悉。它對 Java 8 的支持尤其的好。

SLF4J

有很多 Java 日志解決方案。我最喜歡的是 SLF4J,因為它擁有非常棒的可插拔性,同時能夠和很多的日志框架想結合。有沒有做過同時使用 java.util.logging,JCL,和 log4j 的奇葩項目?SLF4J 就是為你而生。

兩頁手冊足夠你可以開始入門使用 SLF4J 了。

jOOQ

我不喜歡重量級的 ORM 框架,因為我喜歡 SQL。所以我寫了很多 JDBC 模板,但是很難去維護它。jOOQ 是一個更好的解決方案。

它讓你在 Java 中用類型安全的方式編寫 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();

使用 jOOQ 和 DAO 的模式讓你的數據庫訪問變得輕而易舉。

Testing

測試是軟件的關鍵環節。下面這些軟件包能夠讓你更容易地測試。

jUnit 4

好的替代品TestNG.

jUnit 就無需多言了。它是 Java 單元測試中的標準工具。

但是很可能你使用的 jUnit 并沒有發揮它的全部潛力。jUnit 支持參數化測試規則化測試,theories 可以隨機測試特定代碼,還有 assumptions,可以讓你少寫很多樣板代碼。

jMock

如果你完成了依賴注入,這是它的回報:可以 mock 出有副作用(比如和 REST 服務器交互)的代碼,并且可以斷言調用這段代碼的行為。

jMock 是標準的 Java mock 工具。像這樣使用:

public class FooWidgetTest {
    private Mockery context = new Mockery();

    @Test
    public void basicTest() {
        final FooWidgetDependency dep = context.mock(FooWidgetDependency.class);

        context.checking(new Expectations() );

        final FooWidget foo = new FooWidget(dep);

        Assert.assertTrue(foo.doThing());
        context.assertIsSatisfied();
    }
}

這段代碼通過 jMock 建立了一個 FooWidgetDependency,然后添加你所期望結果的條件。我們期望 dep 的 call 方法會被以一個字符串為參數的形式調用,并且會被調用 0 次或者多次。

如果你想一遍又一遍地設置相同的依賴,你應該把它放到 test fixture 中,并且把assertIsSatisfied 放在以 @After 注解的 fixture 中。

AssertJ

你曾經用 jUnit 干過這個嗎?

final List<String> result = some.testMethod();
assertEquals(4, result.size());
assertTrue(result.contains("some result"));
assertTrue(result.contains("some other result"));
assertFalse(result.contains("shouldn't be here"));

這是很惡心的樣板代碼。AssertJ 可以解決這個問題。你可以把相同的代碼轉換成這個樣子:

assertThat(some.testMethod()).hasSize(4)
                             .contains("some result", "some other result")
                             .doesNotContain("shouldn't be here");

這樣的流暢接口讓你的測試更具有可讀性。你還想咋地?

Tools

IntelliJ IDEA

好的替代品Eclipse 和 Netbeans

Java 最好的 IDE 是 IntelliJ IDEA。它有大量的牛逼的特性,它是真正的能讓 Java 用來像不戴套做愛那么爽的工具。自動完成功能超棒,代碼檢查功能也是頂尖的,重構工具那是相當有幫助。

免費的社區版對我來說已經足夠好了,但是它的旗艦版加載了更多的牛逼的特性,如數據庫工具,Spring 框架的支持和對 Chronon 的支持。

Chronon

我最喜歡 GDB 7 的特性之一就是調試的時候能夠按照時間跟蹤回來。當你擁有了旗艦版的 IntelliJ,你可以通過安裝 Chronon IntelliJ 插件實現。

你可以獲取到變量的變化歷史,后退,方法的歷史以及更多的信息。如果你是第一次用會覺得有點怪,但是它真的能夠幫你解決很復雜的 bug,諸如海森堡類的 bug。

JRebel

好的替代品DCEVM

持續集成往往以軟件即服務為產品目標。想象一下如果你不用等待代碼構建完成而能實時看到代碼的變化會是怎樣?

這就是 JRebel 所做的。一旦你將你的服務器和你的 JReble 以 hook 方式連接,你就可以從服務器看到實時變化。當你想快速試驗的時候它能為你節省大量的時間。

The Checker Framework

Java 的類型系統很差勁。它不能夠區分正常的字符串和正則表達式字符串,更不用說壞點檢查了。不過 Checker Framework 可以完成這個功能并且能夠實現更多的東西。

它使用像 @Nullable 這樣的注解來檢查類型。你甚至可以使用自定義注解來實現靜態分析,甚至更強大的功能。

Code Quality

即使遵循著最佳實踐的原則,即使是最好的開發者,也都會犯錯誤。這有很多工具,你可以使用它們驗證你的代碼從而檢查代碼是否有問題。下面是選出的最流行的一部分工具。很多這些工具都可以和流行的 IDE 如 Eclipse 或者 IntelliJ 集成,可以讓你更快地發現代碼中的錯誤。

  • Checkstyle:一個靜態代碼分析工具,它主要著力于保證你的代碼符合代碼標準。檢查規則在一個 XML 文件中定義,你可以把它檢入你的版本控制工具,和你的代碼放在一起。
  • FindBugs:主要集中于發現你的代碼中可能導致產生 bug 或者錯誤的部分。雖然作為獨立的進程運行,但是對流行的 IDE 和構建工具的支持也很好。
  • PMD:和 FindBugs 很相似,PMD 著力于發現你代碼中的錯誤和整理的你的代碼。你可以把針對你的代碼的檢查規則控制在 XML 文件中,和你的代碼放在一塊兒提交。
  • SonarQube:和前面所述的工具不同,它是在本地運行的,SonarQube 啟動一個服務器,你把你代碼提交到這個服務器來進行分析。它提供了 web 界面,你可以看到你的代碼的健康狀況信息,如不好的做法,潛在的 bug,測試覆蓋率百分比,和你寫代碼的技術水平

除了在開發工程中使用這些工具,把它們用在你的構建階段往往也是一個不錯的想法。它可以和想 Maven 或者 Gradle 這樣的構建工具綁定到一起,也可以和持續集成工具綁定使用。

Eclipse Memory Analyzer

即使在 Java 中內存泄露也時有發生。幸運的是,我們有一些工具就是為此而生。Eclipse Memory Analyzer 是我用過的最好用的解決內存泄露問題的工具。它能夠獲取到堆棧信息讓你查閱,去發現問題所在。

有幾種方法可以獲取到 JVM 進程的堆棧信息,但是我用 jmap 工具實現:

$ 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

然后你可以用內存分析器打開 heapdump.hprof 文件,快看看到底是怎么回事。

Resources

這些資源能夠幫你成為 Java 大牛。

Books

Podcasts

Videos

來源:http://blog.smoker.cc/translation/20160511.html?utm_source=tuicool&utm_medium=referral 

 本文由用戶 BarryBlanki 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!