Guava庫介紹之實用工具類

yyznf 8年前發布 | 10K 次閱讀 Guava Java開發

來自: http://www.cnblogs.com/Jack47/p/Guava-Common-Utilities.html

作者:Jack47

轉載請保留作者和原文出處

歡迎關注我的微信公眾賬號程序員杰克,兩邊的文章會同步,也可以添加我的RSS訂閱源。

本文是我寫的 Google開源的Java編程庫Guava系列 之一,主要介紹Guava中提供的很多小工具類,這些類讓Java語言用起來更舒暢。

使用或者避免null值

null 引用的發明者 Sir C.A.R.Hoare (也是快排算法的發明者)把 null 稱之為十億美元錯誤。 Guava 的開發者們通過研究Google的代碼發現95%的集合中都不需要支持為 null 的值,所以對于開發者而言,遇到 null 時需要快速失敗而不是默默地接受 null 。 null 的含義在大部分場景下都不夠清晰,例如 Map.get(key) 返回 null 時,可能是因為map中的值就是 null ,或者map中沒有這個key。但 null 在有些情況下也很有用,從內存和性能方面來看, null 很廉價,在使用對象數組,是不可避免的要用到 null 的。綜合考慮之后,Guava庫中絕大部分工具都被設計成遇到 null 時快速失敗。

Optional

如果程序員需要使用 null 來表示不存在的情況,那么 Optional<T> 就能派上用場了。 Optional<T> 是用非 null 的值來代替一個可能為 null 的值。舉個例子:

Optional<Integer> possible = Optional.of(null);
boolean isPresent = possible.isPresent(); // returns false

再看這個例子:

Optional<Integer> possible = Optional.of(5);
boolean isPresent = possible.isPresent(); // returns true
possible.get(); // returns 5

聰明的讀者已經發現了, Optional 是一個容器對象,它可能容納一個非 null 的值,也可能沒有值。如果這個值存在, isPresent() 函數會返回 true 而且 get() 函數會返回這個值。

引入 Optional 類除了因為給 null 一個有意義的名字而增加了可讀性外,最大的好處是 Optional 能夠強制你主動思考程序中值不存在的情況,而 null 是很容易被忽略的。如果值不存在,想使用默認值,可以使用 Optional 中提供的 T or(T) 函數,例如:

Optional<Integer> default = Optional.of(0);
Optional possible = Optional.of(field);
return possible.or(default)

如果field為 null ,那么返回值就是 default ,調用者需要先判斷值是否存在 isPresent() ,如果存在,再拿到值 get() 。

Strings 類提供了值可能為 null 的一些函數,例如:

boolean invalid = Strings.isNullOrEmpty(res);
String name = Strings.emptyToNull(passedName);

Preconditions(先決條件)

Preconditions 類中提供了幾個非常實用的靜態函數來幫助檢查調用函數或構造函數時的先決條件是否滿足。這些函數都接受一個 boolean 類型的表達式,如果表達式為 false ,會拋出一個非受檢異常,來通知調用方發生了調用錯誤。

Preconditions 類的目的是提高代碼的可讀性,例如 checkArgument(i >=0 , "Argument was %s but expected nonnegative", i); ,一看就知道是在檢查傳入的參數; this.field = checkNotNull(field) ,是檢查field字段不為空。這里需要注意提供的錯誤信息需要清晰有效。

對象的通用函數

使用這些函數能夠簡化實現對象函數的過程,例如 hashCode() 和 toString() 函數

equal函數

如果對象內部變量可以為 null ,實現 equal 函數有些費勁,因為需要單獨檢查 null 。 Objects.equal 函數已經實現了對 null 敏感的檢查,不會出現 NullPointerException 的異常。

Objects.equal("a", "a"); //returns true
Objects.equal(null, "a"); // returns false
Objects.equal(null, null); // returns true

注:最新的JDK 7里引入了 Ojbects 類,提供了同樣的函數。

hashCode函數

平常實現hashCode函數是不是很痛苦?如果類內部的成員變量較多,代碼就會比較冗長。Guava提供了 Objects.hashCode(field1, field2,...,fieldn) 的函數,它能夠對指定順序的多個字段進行哈希,這樣就不用自己手工實現一遍對各個字段進行哈希的過程了。舉個栗子:

return Objects.hashCode(name, address, url);

toString函數

toString 在日志和調試中發揮巨大威力,但是實現起來很麻煩,需要注意各個有用字段輸出時的組織格式。來看看 MoreObjects.toStringHelper 如何讓整個過程變的簡單:

// return "MyObject{x=1,y=2}
Objects.toStringHelper(this)
        .add("x", 1)
        .add("y", 2)
        .toString();

compare/compareTo函數

實現比較器(Comparator),或者實現 Comparable 接口時,通常需要對類內部的所有成員變量進行比較,實現起來很麻煩。Guava提供了 ComparisonChain 類,它能夠進行"懶"比較:只有當發現為0的結果,才會繼續后面的結果,不然就忽略后續的比較。舉個例子:

public int compareTo(Foo other) {
    return ComparisonChain.start()
    .compare(this.x, other.x)
    .compare(this.y, other.y)
    .result();
}

Ordering

Guava提供了一個 流暢型(fluent) 的比較器(Comparator)類: Ordering ,它提供了鏈條函數來微調或者增強已有的比較器,或者構造復雜的比較器,應用到對象的集合上。

Ordering 的核心是一個 Comparator 實例。使用已有的比較器來構造一個 Ordering 實例:

Ordering<Item> ordering = Ordering.from(Comparator<Item> comparator);

也可以使用自然順序: Ordering<T>.natural()
或者自己實現一個 Ordering 類,只需要繼承并實現 compare() 函數就可以。

對 Ordering 進行微調:

reverse()
compound(Comparator)
onResultOf(Function)
nullsFirst()

由于 Ordering 類繼承自 Comparator ,所以在任何需要 Comparator 的地方,都可以使用 Ordering 代替,同時 Ordering 提供了一些操作:

immutableSortedCopy()
isOrdered()/ isStrictlyOrdered()
min()   

字符串相關的函數

合并(Joiner)

流暢風格的 Joiner 提供了使用分隔符把一些字符串序列合并到一起的功能。例如:

Joiner joiner = Joiner.on("; ").skipNulls();
// returns "Harry; Ron; Hermione
return joiner.join("Harry", null, "Ron", "Hermione");

如果不想跳過值為 null 的字符串,想用某個特定字符串代替 null ,可以使用函數 useForNull(String) 。

Joiner 類也可以用在其他對象類型上,此時會使用對象的 toString() 函數得到字符串,然后進行合并。

</div>

切分(Splitter)

Java的字符串分割函數有一些詭異的行為,例如 String.split() 函數會默默地把尾部的分隔符丟棄掉。而使用 Splitter 的好處在于可以完整地顯示地控制這些行為。 Splitter 類可以用來在任意的 Pattern , char , String 或者 CharMatcher 上進行分割。舉個例子:

// returns ["foo", " bar", "", "   qux", ""]
Splitter.on(',').split("foo, bar,,   qux,");
        

Splitter 還提供了其他的配置函數來對合并過程進行定制: omitEmptyStrings() , trimResults() , limit() 等。例如對于上面的例子,如果想忽略空字符串,讓結果中去掉開頭和結尾的空格,可以這樣做:

// returns ["foo","bar","qux"]
Splitter.on(',')
              .trimReults()
              .omitEmptyStrings()
              .split("foo, bar,,   qux,");

注意: Splitter 和 Joiner 實例都是不可變的(immutable),所以 Splitter 和 Joiner 都是線程安全的,可以聲明為 static final 的常量來使用。他們的配置函數都是返回一個新的 Splitter 實例,此時需要使用返回的新的 Splitter 的實例。

字符匹配(Character Matchers)

CharMatcher 類的設計思想很巧妙,定義兩個基本屬性,然后任意組合他們。這樣API的復雜度是線性增加的,但是靈活性和功能是平方式增強的。

CharMatcher 定義的兩個屬性:

  1. 需要匹配什么樣的字符串?
  2. 在這些匹配的字符串上執行什么樣的操作?例如 trimming , collapsing , removing 等。

一些例子:

    // remove control characters
    String noControl = CharMatcher.JAVA_ISO_CONTROL.removeFrom(inputString);
    // only the digits
    String theDigits = CharMatcher.DIGIT.retainFrom(inputString);
    // eliminate all characters that aren't digits or lowercase
    String lowerAndDigit = CharMatcher.JAVA_DIGIT.or(CharMatcher.JAVA_LOWER_CASE).retainFrom(inputString);
    // trim whitespace and replace/collapse whitespace into single spaces
    String spaced = CharMatcher.WHITESPACE.trimAndCollapseFrom(inputString, ' ');

認真的讀者通過看上面的例子會發現 CharMatcher 已經提供了很多現成的匹配特定字符串的常量,例如 WHITESPACE , JAVA_DIGIT 等。也可以通過其他幾個函數來構造匹配特定字符串的 CharMatcher :

is(char);
isNot(char);
negate()
inRange(char, char)
or(CharMatcher);
and(CharMatcher);

可以在CharMatcher上執行的操作

boolean matchesAllOf(CharSequence)
boolean matchesAnyOf(CharSequence)
boolean matchesNoneOf(CharSequence)
int indexIn(CharSequence, int)
int countIn(CharSequence)
String removeFrom(CharSequence)
String retainFrom(CharSequence)
String trimFrom(CharSequence)
String replaceFrom(CharSequence, char)

Charsets

Charsets 類提供了Java平臺的所有實現中都支持的六個標準的字符集的常量引用。所以不要這樣做:

try {
    bytes = content.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
    throw new AssertionError(e);
}

而是用下面的代碼替代:

bytes = content.getBytes(Charsets.UTF_8);

注:JDK7中 StandardCharsets 類已經實現了同樣功能

基本類型相關的函數

Java中 Arrays 類提供了眾多對數組進行操作的函數,基礎類型對應的包裝類例如 Integer ,也提供了很多使用函數。而 Guava 為Java中的8個基本類型提供了其他一些非常實用的函數,例如數組和集合相關的API,從類型轉換到 byte 數組的表示方式等。

例如:

int[] content = {1,3,4};
Ints.indexOf(content, 3); // 1
Ints.concat(new int[] {1,2}, new int[]{3, 4})  // 1,2,3,4
Ints.contains(new int[]{10,20,30,40}, 20) // true
Ints.min(10,20,30,40) // 10
byte[] bytes = Ints.toByteArray(integer);

回到本系列目錄: Google Java編程庫Guava介紹

如果您看了本篇博客,覺得對您有所收獲,請點擊右下角的“推薦”,讓更多人看到!

資助Jack47寫作,打賞一個雞蛋灌餅錢吧

微信打賞

支付寶打賞

</div>

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