使用Optional類避免null
null代表不確定性,有可能這個對象不存在(大多數情況);有可能是成功或失敗;有可能是對象存在但對象為空白(在集合中的情況)。任何不確定性因素都可能會給程式埋下隱患。Optional類強迫你思考null的真正含義,去除null的含糊,讓程式更優雅的處理null的情況。可以避免拋出null 指標異常。使用Optional除了賦予null語義,增加了可讀性,最大的優點在於它是一種傻瓜式的防護。Optional迫使你積極思考引用缺失的情況,因為你必須顯式地從Optional擷取引用。直接使用null很容易讓人忘掉某些情形,儘管FindBugs可以協助尋找null相關的問題,但是我們還是認為它並不能準確地定位問題根源。
比如有如下方法,你想從一個Map集合中找到對應key的value值。當結果返回null的時候,到底是這個key不存在了。還是這個key對應的value為null了。
public Integer findFromMap(Integer key){ Map<String, Integer> map = Maps.newHashMap(); map.put("foo", null); map.put("bar", 1); System.out.println(map.get(key)); return map.get(key); }
Optional類或許可以解決這個問題,它強迫你不能返回null,一定要返回一個有意義的值。
//不存在時使用,不用返回null Optional<String> absentString = Optional.absent(); //確定存在不為空白,如果為null立即返回null 指標異常 Optional<String> presentString = Optional.of("must exist"); //不確定是否為空白 Optional<String> possibleNullString = Optional.fromNullable(findSomething(param)); //如果不存在返回預設值 String defaultString = possibleNullString.or("not exist"); //判斷是否存在 if(possibleNullString.isPresent()){ //返回存在值 possibleNullString.get(); } //返回Optional所包含引用的單例不可變集 possibleNullString.asSet();前置條件: 讓方法中的條件檢查更簡單
public void testPreconditions(String param1, String param2, boolean state) { //檢查expression是否為true,用來檢查傳遞給方法的參數。檢查失敗時拋出的異常IllegalArgumentException checkArgument(param1 != null && param2 != null); //檢查state是否true,檢查失敗時拋出的異常IllegalStateException checkState(state, "state must be false"); //檢查是否為null,檢查失敗時拋出的異常NullPointerException checkNotNull(param1); checkNotNull(param2, "param2 can not be null!"); //檢查index作為索引值對某個列表、字串或數組是否有效。index>=0 && index<size * int index = 1; int size = 10; checkPositionIndex(index, size); //檢查index作為位置值對某個列表、字串或數組是否有效。index>=0 && index<=size * checkElementIndex(index, size); }Object方法
equals
避免拋出null 指標異常
hashcode
用對象的所有欄位作散列[hash]運算應當更簡單。Guava的Objects.hashCode(Object…)會對傳入的欄位序列計算出合理的、順序敏感的散列值。你可以使用Objects.hashCode(field1, field2, …, fieldn)來代替手動計算散列值
toString
更方便使用
@Test public void testOjbects(){ boolean flag = Objects.equal("a", "b"); Objects.hashCode("aaa", "bbb"); String string = MoreObjects.toStringHelper(this).add("x", 1).addValue(123).toString(); String expected = "TestGuava{x=1, 123}"; assertEquals(expected, string); }鏈式風格的比較子
@Test public void testOrder(){ Function<String, String> convertToUpper = new Function<String, String>() { @Override public String apply(String input) { if(input == null || input == "") return null; return input.toUpperCase(); } }; //當閱讀鏈式調用產生的排序器時,應該從後往前讀。 Ordering<String> ordering = Ordering.natural().nullsLast().onResultOf(convertToUpper); List<String> strings = Arrays.asList("b", "c", null, "a"); List<String> expectedString = ordering.sortedCopy(strings); List<String> actualString = Arrays.asList("a", "b", "c", null); assertEquals(expectedString, actualString); //擷取可迭代對象中最大的k個元素。 List<String> string2 = Arrays.asList("a", "b", "d"); assertEquals(ordering.greatestOf(string2, 2), Arrays.asList("d", "b")); //返回兩個參數中最小的那個。如果相等,則返回第一個參數。 List<String> string3 = Arrays.asList("e", "f", "g"); assertEquals(ordering.min(string3), "e"); //返回最小的的k個原生 ordering.leastOf(string3, 2); }