前言
Guava 包含我们在基于Java的项目中依赖的Google的几个核心库:集合,缓存,原语支持,并发库,通用批注,字符串处理,I / O等。
这些工具中的每一种都会被Google员工用于生产服务中,国内很多公司都在使用,它的封装极大加快了Java开发者的开发速度。
我们日常开发中 遇到最多的Exception 可能就是NullPointException 了,那么 guava 如何来优化这个问题呢?
避免使用null
粗心地使用null
可能会导致各种错误。通过研究Google代码库,我们发现不应该有95%的集合中包含任何null值,而让它们快速失败而不是静默接受它们null
将对开发人员有所帮助。
null 本身的含义就是模棱两可的,在不同的语境下表达的含义都不相同。
例如,当 Map.get
返回null时,可能意味着该值不存在,或者该值存在且为null。最关键的是,null不能表示null值的含义。
解决方案:
Optional
静态方法:
方法 | 描述 |
---|---|
Optional.of(T) | 如果给定的值不为null,直接返回,为null 抛出 NullPointException 快速失败。 |
Optional.absent() | 返回一个空Optional对象,isPresent() 将会返回false |
Optional.fromNullable(T) | 将 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>
值的非静态方法。
方法 | 描述 |
---|---|
boolean isPresent() | 判断是否为 null 实例 |
T get() | 不为空,返回实例,为空 抛出 IllegalStateException |
T or(T) | 返回this中的当前值Optional,如果没有,则返回指定的默认值。 |
T orNull() | 返回此值的当前值Optional,如果没有,则返回null。的逆运算fromNullable。 |
Set<T> asSet() | 返回一个Set包含this中的实例的不可变单例Optional(如果有一个实例),否则返回一个空的不可变集。 |
T transform() | 转成成 用户需要的对象 |
java.util.Options toJavaUtil() | 转换成 java的 Options 对象 |
案列:
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 使用
/**
* 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);
方法 | 描述 | 例 |
---|---|---|
Splitter.on(char) | 在出现特定的个性角色时拆分。 | Splitter.on(';') |
Splitter.on(CharMatcher) | 在某个类别中出现任何字符时进行拆分。 | Splitter.on(CharMatcher.BREAKING_WHITESPACE) Splitter.on(CharMatcher.anyOf(";,.")) |
Splitter.on(String) | 按字面量拆分String。 | Splitter.on(", ") |
Splitter.on(Pattern) Splitter.onPattern(String) | 按正则表达式拆分。 | Splitter.onPattern("\r?\n") |
Splitter.fixedLength(int) | 将字符串拆分为指定固定长度的子字符串。最后一块可以小于length,但永远不会为空。 | Splitter.fixedLength(3) |
方法 | 描述 | 例 |
---|---|---|
omitEmptyStrings() | 自动从结果中删除空字符串。 | Splitter.on(',').omitEmptyStrings().split("a,,c,d") 结果"a", "c", "d" |
trimResults() | 从结果中修剪空格;相当于trimResults(CharMatcher.WHITESPACE)。 | Splitter.on(',').trimResults().split("a, b, c, d") 结果"a", "b", "c", "d" |
trimResults(CharMatcher) | 修剪CharMatcher与结果中指定的字符匹配的字符。 | Splitter.on(',').trimResults(CharMatcher.is('_')).split("_a ,_b_ ,c__")返回"a ", "b_ ", "c"。 |
limit(int) | 返回指定数目的字符串后停止拆分。 | Splitter.on(',').limit(3).split("a,b,c,d") 结果 "a", "b", "c,d" |
CaseFormat CaseFormat
CaseFormat是一个方便的小类,用于在ASCII大小写约定之间进行转换,例如,编程语言的命名约定。支持的格式包括:
Format | Example |
---|---|
LOWER_CAMEL | lowerCamel |
LOWER_HYPHEN | lower-hyphen |
LOWER_UNDERSCORE | lower_underscore |
UPPER_CAMEL | UpperCamel |
UPPER_UNDERSCORE | UPPER_UNDERSCORE |
简单用法
//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"`。