過多的使用null可能會導致大量的bugs,Google code 底層代碼中,95%的集合類默認不接受null值。對null值,使用快速失敗拒絕null比默認接受更好。
另外,null本身的含義很模糊。例如,對于null返回值,如Map.get(key)返回null,可能因為和key對應的值為null,也可能map中根本沒有該key。null也可以用以表示失敗或成功,可能代表任何事物。使用其他值而不是null可以使代碼含義表達的更清楚。
盡管如此,有些地方還是應該使用null。在內存和速度方面,null是廉價的,并且在對象數組中是不可避免的。
基于以上原因,Guava大部分工具對null都設計為快速失敗。另外,Guava提供了一些方便使用null的工具。
實際案例不要在Set中使用null,也不要將null作為Map的key值,使用特殊值代替null可以讓查找的語義更清晰。
如果你想把null作為Map的value,更好的辦法不是將該條目放入Map中,而是應該以一個單獨的Set維護“值為null”的鍵集合。因為Map中某個鍵對應的值為null和Map中沒有某個鍵值很容易混淆。
如果需要在List中使用null,并且這個List是稀疏的,則使用Map<Integer, E>可能更好。
如果確實需要null,但null值不能和Guava的集合一起工作,則只能選擇其他方式,如JDK中的Collections.unmodifiableList代替Guava中的ImmutableList。
OptionalGuava設計Optional來解決null問題,Optional<T>表示可能為null的T類型的引用。Optional實例要么包含一個非null的引用,要么什么都不包含(absent),從不會包含null值引用。在需要使用null的時候,可以用Optional代替。
Optional除了賦予null意義外,增加可讀性,還在于它是一種傻瓜式的防護。Optional 迫使你積極思考引用確實的情況,因為你必須顯式地從Optional 獲取引用。
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 instanceOptional<String> optionalName = Optional.fromNullable("bob");assertEquals("bob", optionalName.get());// null instanceassertSame(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) { } }新聞熱點
疑難解答