前言
Guava 包含我们在基于Java的项目中依赖的Google的几个核心库:集合,缓存,原语支持,并发库,通用批注,字符串处理,I / O等。
这些工具中的每一种都会被Google员工用于生产服务中,国内很多公司都在使用,它的封装极大加快了Java开发者的开发速度。
我们日常开发中 遇到最多的Exception 可能就是NullPointException 了,那么 guava 如何来优化这个问题呢?
避免使用null
粗心地使用null可能会导致各种错误。通过研究Google代码库,我们发现不应该有95%的集合中包含任何null值,而让它们快速失败而不是静默接受它们null将对开发人员有所帮助。
null 本身的含义就是模棱两可的,在不同的语境下表达的含义都不相同。
例如,当 Map.get返回null时,可能意味着该值不存在,或者该值存在且为null。最关键的是,null不能表示null值的含义。
解决方案:
Optional
静态方法:
**案列:** /** * 为空快速失败 */ public static void ofTest(){ Integer value2 = null; Optional<Integer> b = Optional.of(value2); System.out.println(b); }
Exception in thread "main" java.lang.NullPointerException at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:877) at com.google.common.base.Optional.of(Optional.java:103) at com.sf.guava.basic.UseNullTest.ofTest(UseNullTest.java:51) at com.sf.guava.basic.UseNullTest.main(UseNullTest.java:24) :UseNullTest.main() FAILED
/** * 返回一个 空的 Optional 对象 */ public static void absentTest(){ Optional<Integer> b1 = Optional.absent(); Optional<String> b2 = Optional.absent(); Optional<List> b3 = Optional.absent(); System.out.println(b1.isPresent()); System.out.println(b2.isPresent()); System.out.println(b3.isPresent()); } false false false
/** * 将 null 引用的对象 转换成 Optional对象 */ public static void fromNullAble(){ Integer value2 = null; Optional<Integer> b = Optional.fromNullable(value2); System.out.println(b.isPresent()); } false
非静态方法:
这些都是针对特定Optional<T>
值的非静态方法。
案列:
public static void select(){ Optional optional = Optional.of("123"); //判断是否为 null, System.out.println(optional.isPresent()); //获取值 System.out.println(optional.get()); // 不为空返回 值,为空 返回默认值 System.out.println(optional.or("this is default")); //不为空返回 值,为空返回 null System.out.println(optional.orNull()); // 返回含有值的 Set 集合 System.out.println(optional.asSet()); // 转换成 用户想要的对象类型 Optional transform = optional.transform(new Function() { @Nullable @Override public Object apply(@Nullable Object input) { return input+"ok"; } }); System.out.println(transform.get()); // 转成 java 提供的 Options 对象 System.out.println(optional.toJavaUtil().get()); }
console:true 123 123 123 [123] 123ok 123
Strings 方法使用
public static void StringsTest(){ // 判断 是否为null 或是 Empty System.out.println(Strings.isNullOrEmpty(null)); // 如果是 null 或是 "" 转换成 null System.out.println(Strings.emptyToNull("123")); // null 转成 "" System.out.println(Strings.nullToEmpty(null)); // 构建 重复 count 个数的值 System.out.println(Strings.repeat("a",10)); // 按长度填充,补充在前面 System.out.println(Strings.padStart("123456",10,'a')); // 按长度填充,补充在后面 System.out.println(Strings.padEnd("12345",10,'a')); // 返回匹配的前缀 System.out.println(Strings.commonPrefix("ac2345","acvbfdgsdf")); // 返回匹配的后缀 System.out.println(Strings.commonSuffix("asdasdasef","acvbfdgsdf")); // 模板填充 System.out.println(Strings.lenientFormat("this is %s","ak47")); }
MoreObjects 使用
- 定制 toString()
/** * 1. 返回两个参数中 不为空的一个 * 2. 如果都是空则抛出NullPointerException。 * 3. 如果两个都不为空 则返回 第一个 * * 作用 定制 toString */ public static void MoreObjectsTest(){ System.out.println(MoreObjects.firstNonNull("321","123")); User user = new User(); MoreObjects.ToStringHelper result = MoreObjects.toStringHelper(user) .add("age", "18") .add("userName", null); result.addValue("ok"); System.out.println(result); //去除空值 result.omitNullValues(); System.out.println(result); }
User{age=18, userName=null, ok} User{age=18, ok}
\2. 对比
/** * Objects 比较 */ public static void objectsTest(){ String str1 = "123"; String str2 = new String("123"); // 检查 可能为空 的对象时 不会出现 NullPointException System.out.println(Objects.equal("a", "a"));// 打印 true System.out.println(Objects.equal(null, "a"));// 打印 false System.out.println(Objects.equal("a", null));// 打印 false System.out.println(Objects.equal(null, null)); // 打印 true System.out.println(Objects.equal(str1, str2)); // 打印 true }
3.利用 比较链的方式 实现比较
package com.sf.guava.basic; import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.collect.ComparisonChain; import com.google.common.collect.Ordering; /** * @Classname ObjectsTest * @Description Objects 使用 * @Date 2019/12/15 0015 17:48 * @Created by 埔枘 */ public class ObjectsTest { public static void main(String[] args) { Person person1 = new Person(); person1.setFirstName("321"); person1.setLastName("123"); person1.setZipCode(3); Person person2 = new Person(); person2.setFirstName("321"); person2.setLastName("123"); person2.setZipCode(2); System.out.println(person1.compareTo(person2)); } } class Person implements Comparable<Person>{ private String lastName; private String firstName; private int zipCode; public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public int getZipCode() { return zipCode; } public void setZipCode(int zipCode) { this.zipCode = zipCode; } @Override public int compareTo(Person other) { //JDK 方式 实现 // int cmp = lastName.compareTo(other.lastName); // if (cmp != 0) { // return cmp; // } // cmp = firstName.compareTo(other.firstName); // if (cmp != 0) { // return cmp; // } // return Integer.compare(zipCode, other.zipCode); // 通过 比较链的方式 比较 return ComparisonChain.start() .compare(this.lastName, other.lastName) .compare(this.firstName, other.firstName) .compare(this.zipCode, other.zipCode, Ordering.natural().nullsLast()) .result(); } }
参数检查
package com.sf.guava.basic; import com.google.common.base.Preconditions; /** * @Classname PreconditionsTest * @Description 参数检查 * @Date 2019/12/6 0006 18:22 * @Created by 埔枘 */ public class PreconditionsTest { public static void main(String[] args) { try { System.out.println(sqrt(-3.0)); }catch(IllegalArgumentException e){ System.out.println(e.getMessage()); } try { System.out.println(sum(null,3)); }catch(NullPointerException e){ System.out.println(e.getMessage()); } try { System.out.println(getValue(6)); }catch(IndexOutOfBoundsException e){ System.out.println(e.getMessage()); } } public static double sqrt(double input) throws IllegalArgumentException { Preconditions.checkArgument(input > 0.0, "Illegal Argument passed: Negative value %s.", input); return Math.sqrt(input); } public static int sum(Integer a, Integer b){ a = Preconditions.checkNotNull(a, "Illegal Argument passed: First parameter is Null."); b = Preconditions.checkNotNull(b, "Illegal Argument passed: Second parameter is Null."); return a+b; } public static int getValue(int input){ int[] data = {1,2,3,4,5}; Preconditions.checkElementIndex(input,data.length, "Illegal Argument passed: Invalid index."); return 0; } }
Ordering 排序
package com.sf.guava.basic; import com.google.common.collect.Ordering; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * @Classname OrderingTest * @Description 排序 * @Date 2019/12/6 0006 18:27 * @Created by 埔枘 */ public class OrderingTest { public static void main(String[] args) { } private static void addList(List<Integer> numbers) { numbers.add(new Integer(5)); numbers.add(new Integer(2)); numbers.add(new Integer(15)); numbers.add(new Integer(51)); numbers.add(new Integer(53)); numbers.add(new Integer(35)); numbers.add(new Integer(45)); numbers.add(new Integer(32)); numbers.add(new Integer(43)); numbers.add(new Integer(16)); } //自然排序 public static void natural(){ List<Integer> numbers = new ArrayList<Integer>(); addList(numbers); //自然排序 Ordering ordering = Ordering.natural(); System.out.println("Input List: "); System.out.println(numbers); Collections.sort(numbers,ordering ); System.out.println("Sorted List: "); System.out.println(numbers); } //是否已经排序 public static void isOrdered(){ List<Integer> numbers = new ArrayList<Integer>(); Ordering ordering = Ordering.natural(); addList(numbers); //判断是否已经排序完成 System.out.println("List is sorted: " + ordering.isOrdered(numbers)); } //获取最值 public static void maxOrMin(){ List<Integer> numbers = new ArrayList<Integer>(); Ordering ordering = Ordering.natural(); System.out.println("Minimum: " + ordering.min(numbers)); } //反序 public static void reverse(){ List<Integer> numbers = new ArrayList<Integer>(); Ordering ordering = Ordering.natural(); Collections.sort(numbers,ordering.reverse()); System.out.println("Reverse: " + numbers); } //把 null 排到第一个 public static void firstNull(){ List<Integer> numbers = new ArrayList<Integer>(); Ordering ordering = Ordering.natural(); Collections.sort(numbers,ordering.nullsFirst()); System.out.println("Null first Sorted List: "); System.out.println(numbers); } }
异常处理
// 如果是 InvalidInputException 才抛出
Throwables.throwIfInstanceOf(e, InvalidInputException.class);
// 抛出不检查的异常
Throwables.throwIfUnchecked(e);
package com.sf.guava.basic; import com.google.common.base.Throwables; import java.io.IOException; /** * @Classname ThrowablesTest * @Description 异常 * @Date 2019/12/11 0011 17:07 * @Created by 埔枘 */ public class ThrowablesTest { public static void main(String[] args) { ThrowablesTest throwablesTest = new ThrowablesTest(); try { throwablesTest.showcaseThrowables(); } catch (InvalidInputException e) { //get the root cause System.out.println(Throwables.getRootCause(e)); }catch (Exception e) { //get the stack trace in string format System.out.println(Throwables.getStackTraceAsString(e)); } } public void showcaseThrowables() throws InvalidInputException{ try { sqrt(-3.0); } catch (Throwable e) { //此方法 已不推荐 使用 // Throwables.propagateIfInstanceOf(e, InvalidInputException.class); // 如果是 InvalidInputException 才抛出 Throwables.throwIfInstanceOf(e, InvalidInputException.class); // 抛出不检查的异常 Throwables.throwIfUnchecked(e); } } public void showcaseThrowables1(){ try { int[] data = {1,2,3}; getValue(data, 4); } catch (Throwable e) { Throwables.propagateIfInstanceOf(e, IndexOutOfBoundsException.class); Throwables.propagate(e); } } public double sqrt(double input) throws InvalidInputException{ if(input < 0) throw new InvalidInputException(); return Math.sqrt(input); } public double getValue(int[] list, int index) throws IndexOutOfBoundsException { return list[index]; } public void dummyIO() throws IOException { throw new IOException(); } } class InvalidInputException extends Exception { }
Joiner 联接器
用分隔符将字符串序列连接在一起通常会很棘手,一般做法是通过for循环拼接,但事实并非如此。如果您的序列包含空值,则可能会更加困难。
Joiner使其变得简单。
线程安全问题:
Joiner 的实例本身是不可变的,on 方法每次都会返回一个新的实例,这使得Joiner 线程安全,可用于 static final 修饰的常量。
字符串的拼接
链式编程方式完美处理了字符串拼接问题,并提供了各种特性
List<Integer> eleList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, null); //分隔符 //线程安全--不可变类 String joinStr = Joiner.on("#") // 替换 null 内容 or skipNulls 二选一 .useForNull("ak47") //过滤null元素 // .skipNulls() //要分割的集合 .join(eleList); //console : 1#2#3#4#5#6#7 System.out.println(joinStr);
文件内容拼接
要求被拼接的Class 实现了 Appendable(可追加)接口
FileWriter fileWriter = new FileWriter(new File("path.txt")); List<String> dateList = new ArrayList<>(); dateList.add("123"); dateList.add("abc"); Joiner joiner = Joiner.on("#").useForNull(" "); //returns the FileWriter instance with the values appended into it FileWriter fileWriter1 = joiner.appendTo(fileWriter, dateList); fileWriter1.write("test context"); fileWriter1.flush();
完成效果如下
Map 拼接
Map<String, String> testMap = Maps.newLinkedHashMap(); testMap.put("Washington D.C", "Redskins"); testMap.put("New York City", "Giants"); testMap.put("Philadelphia", "Eagles"); testMap.put("Dallas", "Cowboys"); String returnedString = Joiner.on("#").withKeyValueSeparator("=").join(testMap); // Washington D.C=Redskins#New York City=Giants#Philadelphia=Eagles#Dallas=Cowboys System.out.println(returnedString);
Splitter 分离器
用于拆分字符串的内置Java实用程序具有一些古怪的行为。
线程安全:
Splitter 的实例本身是不可变的,on 方法每次都会返回一个新的实例,这使得Splitter 线程安全,可用于 static final 修饰的常量。
比如:
String[] split = ",a,,b,".split(",");
结果如下: 发现没有b 后面的被忽略了… 我滴个亲娘额
使用Splitter 完美解决,并提供了更多的操作特性
字符串拆分成List集合
String str="1,2,3,4,5,6,7 "; List<String> stringList = Splitter.on(",") // 去空格 // .trimResults() .trimResults(new CharMatcher() { @Override public boolean matches(char c) { //忽略 符合条件的 if(c == 49){ return true; } return false; } }) //过滤空字符串 .omitEmptyStrings() //分路器,类似分页 // .limit(2) .splitToList(str); //[2, 3, 4, 5, 6, 7 ] System.out.println(stringList);
字符串拆分成Map 集合
**
**
String str2="name=zhang&age=18"; Map<String, String> split = Splitter.on("&") .withKeyValueSeparator("=") .split(str2); //{name=zhang, age=18}System.out.println(split);
1
CaseFormat CaseFormat
CaseFormat是一个方便的小类,用于在ASCII大小写约定之间进行转换,例如,编程语言的命名约定。支持的格式包括:
简单用法
//constantName 大写下划线 转 小写驼峰 System.out.println(CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "CONSTANT_NAME")); //abcDfg 小写连字符 转小写驼峰 System.out.println(CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, "abc-dfg")); "_a ,_b_ ,c__")`返回`"a ", "b_ ", "c"`。