Guava简介
一、简介
Guava是一个开源的Java库,它提供了许多用于集合(collections)、字符串处理(string processing)、缓存(caching)、并发(concurrency)等的很有用的方法,可以方便编程,提高效率。
二、安装
Guava的Maven配置:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.1-jre</version>
</dependency>
三、常用方法
1、基本工具
- 前置条件(Preconditions)
可以使用Preconditions
类的静态方法来检查调用函数的参数值是否合适。
import com.google.common.base.Preconditions;
public class Math {
public Integer div(Integer a, Integer b){
Preconditions.checkNotNull(a, "Dividend can't be null!");
Preconditions.checkNotNull(b, "Divisor can't be null!");
Preconditions.checkArgument(b > 0, "Argument 'b' was %s but expected positive", b);
return a / b;
}
}
math.div(null, null);
:
java.lang.NullPointerException: Dividend can't be null!
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:897)
at com.mycompany.app.test.Math.div(Math.java:8)
math.div(8, 0);
:
java.lang.IllegalArgumentException: Argument 'b' was 0 but expected positive
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:217)
at com.mycompany.app.test.Math.div(Math.java:10)
- Optional
Optional<T>
可以表示一个可能为null的T类型的引用,一个Optional实例用存在或缺失来表示是否包含非null对象的引用。
Optional<String> optional = Optional.of(null);
System.out.println(optional.isPresent());//java.lang.NullPointerException
Optional<String> optional = Optional.fromNullable(null);
System.out.println(optional.isPresent());//false
Optional<String> optional = Optional.of("Hello World!");
System.out.println(optional.isPresent());//true
if(optional.isPresent()){
System.out.println(optional.get());//Hello World!
}
- Objects
System.out.println(Objects.equal("Hi", "Hi"));//true
System.out.println(Objects.equal(null, null));//true
System.out.println(Objects.equal(null, "Hi"));//false
System.out.println(Objects.equal("Hi", null));//false
- Ordering
Ordering
是一个特殊的Comparator实例,它提供了链式调用方法来定制和增强现有的比较器,可以使用Ordering
类来构建复杂的比较器。
Ordering<String> ordering = Ordering.natural();
List<String> names = new ArrayList<String>();
names.add("Sophie");
names.add("James");
names.add("Jennifer");
names.add("Karen");
names.add("Stan Lee");
System.out.println(ordering.isOrdered(names));//false
Collections.sort(names, ordering);
System.out.println(names);//[James, Jennifer, Karen, Sophie, Stan Lee]
System.out.println(ordering.isOrdered(names));//true
Collections.sort(names, ordering.reverse());
System.out.println(names);//[Stan Lee, Sophie, Karen, Jennifer, James]
names.add(null);
Collections.sort(names, ordering.nullsFirst());
System.out.println(names);//[null, James, Jennifer, Karen, Sophie, Stan Lee]
2、区间
Range表示一个区间或序列:
//创建不同区间类型的Range
//0<=x<=5
Range<Integer> range = Range.closed(0, 5);
//0<x<5
range = Range.open(0, 5);
//0<x<=5
range = Range.openClosed(0, 5);
//0<=x<5
range = Range.closedOpen(0, 5);
//x>=5
range = Range.greaterThan(5);
//x<=5
range = Range.atMost(5);
Range<Integer> range1 = Range.closed(0, 5);
Range<Integer> range2 = Range.open(3, 8);
System.out.println(range1);//[0..5]
System.out.println(range2);//(3..8)
System.out.println(range1.intersection(range2));//(3..5]
System.out.println(range2.contains(3));//false
System.out.println(range1.lowerEndpoint() + " " + range1.upperEndpoint());//0 5
System.out.println(Range.openClosed(6, 6).isEmpty());//true
//是否相连
System.out.println(Range.closed(0, 5).isConnected(Range.open(5, 10)));//true
//span方法返回包括两个参数区间的最小区间
System.out.println(Range.closed(3, 5).span(Range.open(8, 10)));//[3..10)
3、集合
- 不可变集合
创建对象的不可变拷贝是一种很好的防御性编程技巧,不可变对象在被其他库调用或多线程调用时,由于是不可变的,所以是安全的。
通常用copyOf
、of
或builder
方法创建:
Set<String> set = new HashSet<String>();
set.add("A");
set.add("C");
ImmutableSet<String> immutableSet = ImmutableSet.copyOf(set);
System.out.println(immutableSet);//[A, C]
ImmutableMap<String, String> immutableMap = ImmutableMap.of("name", "Jack", "age", "30");
System.out.println(immutableMap);//{name=Jack, age=30}
immutableSet = ImmutableSet.<String>builder().add("foo").add("bar").build();
System.out.println(immutableSet);//[foo, bar]
可以看到ImmutableCollection抽象类中的add、remove等方法都会直接抛异常:
-
新集合类型
- Multiset
Multiset允许添加相同的元素,并提供了处理这些重复元素相关的方法。
Multiset<String> multiset = HashMultiset.create(); multiset.add("a"); multiset.add("b"); multiset.add("c"); multiset.add("a"); multiset.add("c"); //统计a出现的次数 System.out.println("Occurrence of 'a':" + multiset.count("a"));//Occurrence of 'a':2 //分别打印每种元素出现的次数 for(Entry<String> entry : multiset.entrySet()){ System.out.println(String.format("Occurrence of '%s':%s", entry.getElement(), entry.getCount())); }
Occurrence of 'a':2 Occurrence of 'b':1 Occurrence of 'c':2
- Multimap
Multimap允许一个key对应多个value,类似于
Map<K, Collection<V>>
。Multimap<String, String> multimap = ArrayListMultimap.create(); multimap.put("fruit", "apple"); multimap.put("fruit", "mango"); multimap.put("fruit", "coconut"); multimap.put("fruit", "strawberry"); multimap.put("animal", "cat"); multimap.put("animal", "dog"); multimap.put("animal", "fish"); Collection<String> fruits = multimap.get("fruit"); System.out.println(fruits);//[apple, mango, coconut, strawberry] fruits.add("pineapple"); Map<String, Collection<String>> map = multimap.asMap(); System.out.println(map);//{fruit=[apple, mango, coconut, strawberry, pineapple], animal=[cat, dog, fish]} for(Entry<String, Collection<String>> entry : map.entrySet()){ System.out.println(String.format("Key: %s, Value: %s", entry.getKey(), entry.getValue())); } //Key: fruit, Value: [apple, mango, coconut, strawberry, pineapple] //Key: animal, Value: [cat, dog, fish]
- BiMap
可以使用BiMap实现键值对的双向映射(key和value都是唯一的):
BiMap<String, Integer> biMap = HashBiMap.create(); //name -- id biMap.put("Bob", 101); //get username by id System.out.println(biMap.inverse().get(101));//Bob
- Table
Table支持使用多个键作索引,并提供多种视图供使用:
/* * ID Name Sex * 001 Fanny female * 002 Charles male */ Table<Integer, String, String> table = HashBasedTable.create(); table.put(1, "ID", "001"); table.put(1, "Name", "Fanny"); table.put(1, "Sex", "female"); table.put(2, "ID", "002"); table.put(2, "Name", "Charles"); table.put(2, "Sex", "male"); System.out.println(table.row(1));//{ID=001, Name=Fanny, Sex=female} System.out.println(table.row(2));//{ID=002, Name=Charles, Sex=male} System.out.println(table.column("ID"));//{1=001, 2=002} System.out.println(table.get(2, "Name"));//Charles
- RangeSet
RangeSet表示一组不相连的非空区间,如果把一个区间添加到可变的RangeSet时,所有相连的区间会被合并(空区间会被忽略):
RangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(1, 3));//[1..3] rangeSet.add(Range.closedOpen(5, 8));//[5..8) rangeSet.add(Range.openClosed(4, 4));//空区间 rangeSet.add(Range.closedOpen(8, 20));//[8..20) System.out.println(rangeSet);//[[1..3], [5..20)] rangeSet.remove(Range.open(2, 10)); System.out.println(rangeSet);//[[1..2], [10..20)]
- RangeMap
RangeMap表示不相交的非空区间到特定值的映射,与RangeSet不同,RangeMap不会合并相邻的映射:
RangeMap<Integer, String> rangeMap = TreeRangeMap.create(); rangeMap.put(Range.closed(0, 60), "seven students"); rangeMap.put(Range.openClosed(60, 80), "seven students"); rangeMap.put(Range.open(80, 100), "ten students"); System.out.println(rangeMap); rangeMap.remove(Range.closed(75, 95)); System.out.println(rangeMap);
[[0..60]=seven students, (60..80]=seven students, (80..100)=ten students] [[0..60]=seven students, (60..75)=seven students, (95..100)=ten students]
-
集合工具类
- Lists
Lists为List类型的对象提供了一些工具方法:
List<Integer> nums = Ints.asList(1, 3, 2, 4, 7, 5, 9); //反转 System.out.println(Lists.reverse(nums));//[9, 5, 7, 4, 2, 3, 1] //按指定大小分割 System.out.println(Lists.partition(nums, 3));//[[1, 3, 2], [4, 7, 5], [9]]
- Sets
Sets提供了很多标准的集合运算方法,例如:交集、并集、差集等,这些方法接受Set类型的参数并返回SetView对象,SetView对象可以直接当作Set来使用,也可以调用其
copyInto(Set)
方法拷贝到另一个可变集合中或者调用其immutableCopy()
方法做不可变拷贝。Set<String> set1 = Sets.newHashSet("A", "B", "C", "D"); Set<String> set2 = Sets.newHashSet("X", "Y", "C", "D"); //并集 System.out.println(Sets.union(set1, set2));//[A, B, C, D, X, Y] //交集 System.out.println(Sets.intersection(set1, set2));//[C, D] //差集:set1与set2相比 System.out.println(Sets.difference(set1, set2));//[A, B] //差集:set2与set1相比 System.out.println(Sets.difference(set2, set1));//[X, Y] //只在两个集合其中之一的元素组成的集合 System.out.println(Sets.symmetricDifference(set1, set2));//[A, B, X, Y]
- Maps
Maps为Map对象提供了一些工具方法:
如果想要对一组对象(这些对象的某个属性值是唯一的),按某个唯一值属性查找,则可以使用
Maps.uniqueIndex()
方法:List<String> values = Lists.newArrayList("I", "He", "You", "They"); ImmutableMap<Integer, String> stringsByIndex = Maps.uniqueIndex(values, new Function<String, Integer>() { public Integer apply(String input) { return input.length(); } }); System.out.println(stringsByIndex.get(1)); System.out.println(stringsByIndex.get(3));
Maps.difference(Map, Map)
方法用来比较两个Map的不同点:Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3); Map<String, Integer> right = ImmutableMap.of("x", 7, "b", 2, "c", 10); MapDifference<String, Integer> diff = Maps.difference(left, right); //key和value都相同的项 System.out.println(diff.entriesInCommon());//{b=2} //key只在左边Map的项 System.out.println(diff.entriesOnlyOnLeft());//{a=1} //key只在右边Map的项 System.out.println(diff.entriesOnlyOnRight());//{x=7} //key相同但value不同的项 Map<String, ValueDifference<Integer>> differing = diff.entriesDiffering(); System.out.println(differing);//{c=(3, 10)}
-
扩展工具类
可以使用Iterators.peekingIterator(Iterator)
将Iterator包装为PeekingIterator,此类提供了peek()
方法可以获取下一次调用next()
方法的返回值:
List<String> arr = Lists.newArrayList();
arr.add("A");
arr.add("B");
arr.add("B");
arr.add("B");
arr.add("C");
PeekingIterator<String> iter = Iterators.peekingIterator(arr.iterator());
//打印集合时跳过相邻且重复的元素
while(iter.hasNext()){
String current = iter.next();
while(iter.hasNext() && iter.peek().equals(current)){
iter.next();
}
System.out.println(current);
}
A
B
C
4、字符串处理
- 连接器
可以使用Joiner将字符串用指定的连接符连接起来(Joiner实例都是不可变的,因此是线程安全的):
String[] parts = new String[]{"Tom", "Lucy", null, "Jack"};
Joiner joiner = Joiner.on(" - ").skipNulls();
System.out.println(joiner.join(parts));//Tom - Lucy - Jack
String ret = Joiner.on(" ").join(Arrays.asList(1, 3, 4, 5, 8, 7));
System.out.println(ret);//1 3 4 5 8 7
- 拆分器(Splitter)
Splitter支持按单个字符、正则表达式、固定长度做拆分,同时可以对拆分结果做处理:
String words = "foo,bar,hi, hello, ,world,";
//使用split
System.out.println(Arrays.asList(words.split(",")));//[foo, bar, hi, hello, , world]
Splitter splitter = Splitter.on(",");
System.out.println(splitter.split(words));//[foo, bar, hi, hello, , world, ]
System.out.println(splitter.trimResults().split(words));//[foo, bar, hi, hello, , world, ]
System.out.println(splitter.trimResults().omitEmptyStrings().split(words));//[foo, bar, hi, hello, world]
- 字符匹配器
CharMatcher实例代表某一类字符(数字或空白字符),它提供了一系列方法来对字符作特定的操作:trim(修剪)、collapse(折叠)、remove(移除)、retain(保留)等。
//去除空白字符
System.out.println(CharMatcher.whitespace().removeFrom(" a b c d e "));//abcde
//统计字符出现的次数
System.out.println(CharMatcher.anyOf("abc").countIn("I am a student, I want be a teacher!"));//7
//字符串中不是'-'的部分都替换为'X'
System.out.println(CharMatcher.isNot('-').replaceFrom("I-Love-You", "X"));//X-XXXX-XXX
- 大小写格式
CaseFormat可以很方便在命名规范或大小写规则间转换字符串:
System.out.println(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, "const_name"));//CONST_NAME
System.out.println(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "const_name"));//constName
System.out.println(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "const_name"));//ConstName
System.out.println(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, "const_name"));//const-name