使用Optional类避免null
null代表不确定性,有可能这个对象不存在(大多数情况);有可能是成功或失败;有可能是对象存在但对象为空(在集合中的情况)。任何不确定性因素都可能会给程序埋下隐患。Optional类强迫你思考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立即返回空指针异常
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
避免抛出空指针异常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);
}