guava – Optional

過多的使用null可能會致使大量的bugs,Google code 底層代碼中,95%的集合類默認不接受null值。對null值,使用快速失敗拒絕null比默認接受更好。數組

另外,null自己的含義很模糊。例如,對於null返回值,如Map.get(key)返回null,可能由於和key對應的值爲null,也可能map中根本沒有該key。null也能夠用以表示失敗或成功,可能表明任何事物。使用其餘值而不是null可使代碼含義表達的更清楚。工具

儘管如此,有些地方仍是應該使用null。在內存和速度方面,null是廉價的,而且在對象數組中是不可避免的。spa

基於以上緣由,Guava大部分工具對null都設計爲快速失敗。另外,Guava提供了一些方便使用null的工具。設計

實際案例

不要在Set中使用null,也不要將null做爲Map的key值,使用特殊值代替null可讓查找的語義更清晰。code

若是你想把null做爲Map的value,更好的辦法不是將該條目放入Map中,而是應該以一個單獨的Set維護「值爲null」的鍵集合。由於Map中某個鍵對應的值爲null和Map中沒有某個鍵值很容易混淆。對象

若是須要在List中使用null,而且這個List是稀疏的,則使用Map<Integer, E>可能更好。blog

若是確實須要null,但null值不能和Guava的集合一塊兒工做,則只能選擇其餘方式,如JDK中的Collections.unmodifiableList代替Guava中的ImmutableList。內存

Optional

Guava設計Optional來解決null問題,Optional<T>表示可能爲null的T類型的引用。Optional實例要麼包含一個非null的引用,要麼什麼都不包含(absent),從不會包含null值引用。在須要使用null的時候,能夠用Optional代替。ci

Optional除了賦予null意義外,增長可讀性,還在於它是一種傻瓜式的防禦。Optional 迫使你積極思考引用確實的狀況,由於你必須顯式地從Optional 獲取引用。get

Optional 的可能應用方面:

  • 做爲方法返回值,用於取代使用null做爲返回值的狀況。
  • 用於區分「unknow」(如Map不包含)和「known to have no value」(如Map包含該鍵,值爲Optional.absent())。
  • 用於包裝null引用,從而在不支持null的集合中使用。

建立Optional(均爲靜態方法)

Optional.of(T) 建立指定引用的Optional實例,對null值拋出NullPointException。建議直接傳遞常量參數。
Optional.absent() 建立引用缺失的Optional實例
Optional.fromNullable(T) 建立指定引用的Optional實例,若引用爲null則表示缺失
assertEquals("training", Optional.of("training").get());

Optional<String> optionalName = Optional.absent();
assertFalse(optionalName.isPresent());

// Non-null instance
Optional<String> optionalName = Optional.fromNullable("bob");
assertEquals("bob", optionalName.get());
// null instance
assertSame(Optional.absent(), Optional.fromNullable(null));

查詢方法(均爲非靜態方法)

boolean isPresent() 若是該Optional 包含非null引用,返回true。
T get() 返回Optional 所包含的引用,若引用缺失,則拋出IllegalStateException。
T or(T) 返回Optional 所包含的引用,若引用缺失,返回默認值。
T orNull() 返回Optional 所包含的引用,若引用缺失,返回null。
Set<T> asSet() 返回Optional所包含的singleton不可變集合,若爲空,返回空集合。

public void testIsPresent_no() {
        assertFalse(Optional.absent().isPresent());
    }

    public void testIsPresent_yes() {
        assertTrue(Optional.of("training").isPresent());
    }

    public void testGet_absent() {
        Optional<String> optional = Optional.absent();
        try {
            optional.get();
            fail();
        } catch (IllegalStateException expected) {
        }
    }

    public void testGet_present() {
        assertEquals("training", Optional.of("training").get());
    }
    
    public void testOr_T_present() {
        assertEquals("a", Optional.of("a").or("default"));
    }

    public void testOr_T_absent() {
        assertEquals("default", Optional.absent().or("default"));
    }

    public void testOrNull_present() {
        assertEquals("a", Optional.of("a").orNull());
    }

    public void testOrNull_absent() {
        assertNull(Optional.absent().orNull());
    }

    public void testAsSet_present() {
        Set<String> expected = Collections.singleton("a");
        assertEquals(expected, Optional.of("a").asSet());
    }

    public void testAsSet_absent() {
        assertTrue("Returned set should be empty", Optional.absent().asSet().isEmpty());
    }

    public void testAsSet_presentIsImmutable() {
        Set<String> presentAsSet = Optional.of("a").asSet();
        try {
            presentAsSet.add("b");
            fail();
        } catch (UnsupportedOperationException expected) {
        }
    }

    public void testAsSet_absentIsImmutable() {
        Set<Object> absentAsSet = Optional.absent().asSet();
        try {
            absentAsSet.add("foo");
            fail();
        } catch (UnsupportedOperationException expected) {
        }
    }
相關文章
相關標籤/搜索