利用Idea重構功能及Java8語法特性——優化深層巢狀程式碼

蘇先生ii發表於2019-08-05

當遇到深層巢狀程式碼,如for,if,lambda表示式或內部類及這些程式碼的組合,這時我們可以通過Java 8的語法特性來進行優化。

下面的程式碼是一個巢狀迴圈的示例。

public MappedField getMappedField(final String storedName) {
    for (final MappedField mf : persistenceFields) {
        for (final String n : mf.getLoadNames()) {
            if (storedName.equals(n)) {
                return mf;
            }
        }
    }
    return null;
}

重構1:

巢狀的for/if語句通暢可以通過Java 8中的stream來替代。

Optional<String> found = persistenceFields.stream()
.flatMap(mappedField -> mappedField.getLoadNames().stream())
.filter(storedName::equals)
.findFirst();

上述重構程式碼會返回Optional,但筆者希望返回mappedField物件,再次改造後的程式碼如下。

persistenceFields.stream()
.filter(mappedField -> {
    for (String name : mappedField.getLoadNames()) {
        if (storedName.equals(name)) {
            return true;
        }
    }
    return false;
}
)
.findFirst()

 

重構2: 進行更好的封裝

重構1還存在一些問題,我們需要了解mappedField的結構,並通過迴圈遍歷其所有name來找到匹配的name。根據迪米特法則(Law of Demeter ),及命令-不要去詢問法則(Tell, Don’t Ask), 下面程式碼應該由MappedField物件來提供對應的方法來判斷,而不是由呼叫者去了解MappedField結構後去寫邏輯進行判斷。

for (final MappedField mf : persistenceFields) {
    if (mf.hasName(storedName)) {
        return mf;
    }
}

因此將上述程式碼提取為MappedField類中獨立的方法,並命名為hasName。如果使用的IDE 是IDEA則可以通過refractor中的extract功能完成提取。

最後呼叫hasName方法來替代迴圈判斷邏輯。

接著通過Idea的refractor 中的move功能將程式碼移動到目標類位置。

接著通過stream來重構hasName方法,hasName方法變更為下面的形式。

public Boolean hasName(String storedName) {
    return getLoadNames().stream()
    .anyMatch(storedName::equals);
}

經過上述步驟最終重構後的程式碼為。

public MappedField getMappedField(final String storedName) {
    return persistenceFields.stream()
    .filter(mf -> mf.hasName(storedName))
    .findFirst()
    .orElse(null);
}

如需要返回Optional包裝的物件則需要去掉orElse。

public Optional<MappedField> getMappedField(final String storedName) {
    return persistenceFields.stream()
    .filter(mf -> mf.hasName(storedName))
    .findFirst();
}

 

總結

這類程式碼特徵通常為:

  • 存在深層的迴圈或條件判斷巢狀。
  • 需要通過多個getter方法來訪問物件內部資料。

重構方法:

考慮tell don’t ask原則,提供專用的方法供外部呼叫訪問資料,而不是通過使用者經過多次訪問去獲取物件資料。並通過stream提供的操作來完成重構。

 

————END————

相關文章