[Java]-Guava工具库简介


Guava库中包含了一系列方便使用的工具库,如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等等。

字符串

Guava中提供了丰富的字符串分割、连接、填充方法。

Jointer

用分隔符将多个**字符串(或数组元素)**连接成一个字符串:

  1. on(String):静态工厂方法,生成一个新的 Joiner 对象,参数为连接符;
  2. skipNulls():如果元素为空,则跳过;
  3. useForNull(String):如果元素为空,则用这个字符串代替;
  4. join(数组/链表):要连接的数组/链表;
  5. appendTo(String,数组/链表):在第一个参数后面新加上 拼接后的字符串;
  6. withKeyValueSeparator(String):得到 MapJoiner,Map键、值的连接符;
List<String> lstTest = Arrays.asList("aa", "bb", "cc", null, "dd");
System.out.println(Joiner.on("; ").useForNull("<null>").join(lstTest)); // aa; bb; cc; <null>; dd

Map map = ImmutableMap.of("k1", "v1", "k2", "v2");
System.out.println(Joiner.on("; ").withKeyValueSeparator("=").join(map)); // k1=v1; k2=v2

Splitter

Splitter 将一个字符串按照分隔符生成字符串集合。

String strList = "aa; bb; cc; <null>; dd";
System.out.println(Splitter.on(";").trimResults().split(strList)); // [aa, bb, cc, <null>, dd]

String strMap = "k1=v1; k2=v2";
System.out.println(Splitter.on(";").trimResults().withKeyValueSeparator("=").split(strMap)); // {k1=v1, k2=v2}

拆分器工厂

方法描述范例
Splitter.on(char)按单个字符拆分Splitter.on(‘;’)
Splitter.on(CharMatcher)按字符匹配器拆分Splitter.on(CharMatcher.BREAKING_WHITESPACE)
Splitter.on(String)按字符串拆分Splitter.on(“, “)
Splitter.on(Pattern) Splitter.onPattern(String)按正则表达式拆分Splitter.onPattern(“\r?\n”)
Splitter.fixedLength(int)按固定长度拆分;最后一段可能比给定长度短,但不会为空。Splitter.fixedLength(3)
Splitter.fixedLength(3).split("1234567");
// [123, 456, 7]

拆分器修饰符

方法描述
omitEmptyStrings()从结果中自动忽略空字符串
trimResults()移除结果字符串的前导空白和尾部空白
trimResults(CharMatcher)给定匹配器,移除结果字符串的前导匹配字符和尾部匹配字符
limit(int)限制拆分出的字符串数量

CharMatcher

CharMatcher(只处理char类型代表的字符)提供了一系列方法对字符作特定类型的操作:修剪[trim]、折叠[collapse]、移除[remove]、保留[retain]等等。

工厂方法

方法描述
anyOf(CharSequence)枚举匹配字符。如CharMatcher.anyOf(“aeiou”)匹配小写英语元音
is(char)匹配指定字符
isNot(char)不匹配指定字符
noneOf(CharSequence)等价anyOf(sequence).negate()
inRange(char, char)给定字符范围匹配,如CharMatcher.inRange(‘a’, ‘z’)

CharMatcher还可通过negate()、and(CharMatcher)和or(CharMatcher)方法组合。

操作方法

CharMatcher提供了多种多样的方法操作CharSequence中的特定字符:

方法描述
collapseFrom(CharSequence, char)把连续的匹配字符替换为特定字符
matchesAllOf(CharSequence)
matchesAnyOf
matchesNoneOf
测试字符序列的匹配
removeFrom(CharSequence)从字符序列中移除所有匹配字符
retainFrom(CharSequence)在字符序列中保留匹配字符,移除其他字符
trimFrom(CharSequence)
trimLeadingFrom
trimTrailingFrom
移除字符序列的前导匹配字符、尾部匹配字符
replaceFrom(CharSequence, CharSequence)用特定字符序列替代匹配字符
countIn(CharSequence)统计目标字符出现次数
indexIn
lastIndexIn
查找字符出现位置
String strAll = " a   b   c def  ";
CharMatcher spaceMatcher = CharMatcher.whitespace();
System.out.println(strAll);
String result = spaceMatcher.collapseFrom(strAll, ' ');
System.out.println(result);
result = spaceMatcher.removeFrom(strAll);
System.out.println(result);
result = spaceMatcher.trimFrom(strAll);
System.out.println(result);
result = spaceMatcher.trimTrailingFrom(strAll);
System.out.println(result);

//  a   b   c def  
//  a b c def 
// abcdef
// a   b   c def
//  a   b   c def

Strings

Strings 类主要提供了对字符串的一些操作:

  1. nullToEmpty(String string) :null字符串转空字符串;
  2. emptyToNull(String string):空字符串转null字符串;
  3. isNullOrEmpty(String string):判断字符串为null或空字符串;
  4. padStart(String string, int minLength, char padChar):如果string的长度小于minLeng,在string前添加padChar,直到字符串长度为minLeng。

集合

Guava中引入了一些JDK中没有的集合:

可变集合接口JDK/Guava不可变版本
CollectionJDKImmutableCollection
ListJDKImmutableList
SetJDKImmutableSet
SortedSet/NavigableSetJDKImmutableSortedSet
MapJDKImmutableMap
SortedMapJDKImmutableSortedMap
MultisetGuavaImmutableMultiset
SortedMultisetGuavaImmutableSortedMultiset
MultimapGuavaImmutableMultimap
ListMultimapGuavaImmutableListMultimap
SetMultimapGuavaImmutableSetMultimap
BiMapGuavaImmutableBiMap
ClassToInstanceMapGuavaImmutableClassToInstanceMap
TableGuavaImmutableTable

不可变集合

不可变集合可避免元素被意外修改,创建对象的不可变拷贝是一项很好的防御性编程技巧:

  • 当对象被不可信的库调用时,不可变形式是安全的;
  • 不可变对象被多个线程调用时,不存在竞态条件问题;
  • 不可变集合不需要考虑变化,因此可以节省时间和空间;
  • 不可变对象因为有固定不变,可以作为常量来安全使用;

通过of可方便地根据参数生成集合,copyOf可以从可迭代集合中生成新的集合:

ImmutableSortedSet sortedSet = ImmutableSortedSet.of("a", "c", "b", "e", "d", "c");
System.out.println(sortedSet);

List<Integer> lstNum = Lists.newArrayList(1,2,3,4,5);
ImmutableList immutableList = ImmutableList.copyOf(lstNum);
System.out.println(immutableList);

// [a, b, c, d, e]
// [1, 2, 3, 4, 5]

新型集合

Guava中提供了很多新型集合,方便使用。

  • BiMap:保证键与值都是唯一的;inverse可翻转键与值(biMap.inverse.get(v),通过值获取键);
  • Table:支持两个键(行与列,类似Excel表格)来获取值;通过rowXX获取基于行的集合,columnXX获取基于列的集合(效率相对row低些),cellSet获取元素集合;
  • RangeMap:是键为Range的Map;

Multiset

Multiset可多次添加相等的元素(即,允许重复元素)。如统计文档中单词的数量,即可方便地使用Multiset.count获取数量。

方法描述
count(E)给定元素在Multiset中的计数
elementSet()Multiset中不重复元素的集合(Set)
entrySet()获取Set<Multiset.Entry>(Entry中包含元素与数量)
add(E, int)增加给定元素在Multiset中的计数
remove(E, int)减少给定元素在Multiset中的计数
setCount(E, int)设置给定元素在Multiset中的计数,不可以为负数
size()返回集合元素的总个数(包括重复的元素)
Multiset<String> multiset = HashMultiset.create();
multiset.add("one");
multiset.add("two");
multiset.add("two");
multiset.setCount("three", 3);
System.out.println(multiset);
multiset.entrySet().forEach(z -> {
    System.out.println(z.getElement() + ":" + z.getCount());
});

// [one, two x 2, three x 3]
// one:1
// two:2
// three:3

Multimap

Multimap允许一个键映射多个值

方法签名描述
put(K, V)添加
putAll(K, Iterable)依次添加集合中的值
remove(K, V)移除键与值的映射
removeAll(K)清除键对应的所有值
replaceValues(K, Iterable)清除键对应的所有值,把新的集合映射到键

RangeSet

RangeSet描述了一组不相连的、非空的区间。当把一个区间添加到可变的RangeSet时,所有相连的区间会被合并,空区间会被忽略。

RangeSet<Integer> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(1, 10)); // {[1,10]}
rangeSet.add(Range.closedOpen(11, 15));//不相连区间:{[1,10], [11,15)}
rangeSet.add(Range.closedOpen(15, 20)); //相连区间; {[1,10], [11,20)}
rangeSet.add(Range.openClosed(0, 0)); //空区间; {[1,10], [11,20)}
rangeSet.remove(Range.open(5, 10)); //分割[1, 10]; {[1,5], [10,10], [11,20)}

RangeSet的实现支持非常广泛的视图:

  • complement():返回RangeSet的补集;
  • subRangeSet(Range<C>):返回RangeSet与给定Range的交集;
  • asRanges():用Set<Range>表现RangeSet,这样可以遍历其中的Range。
  • asSet(DiscreteDomain<C>)(仅ImmutableRangeSet支持):用ImmutableSortedSet表现RangeSet,以区间中所有元素的形式而不是区间本身的形式查看。

为了方便操作,RangeSet直接提供了若干查询方法,其中最突出的有:

  • contains(C):判断RangeSet中是否包含给定元素。
  • rangeContaining(C):返回包含给定元素的区间;若没有这样的区间,则返回null。
  • encloses(Range<C>):判断RangeSet中是否有任何区间包括给定区间。
  • span():返回包括RangeSet中所有区间的最小区间。

工具类

工具类(一般是集合名+s:Collection除外,为与标准库中区分,使用Collections2)中提供了一系列静态方法,方便使用:

集合接口Guava工具类
CollectionCollections2
ListLists
Set/SortedSetSets
Map/SortedMap/BiMapMaps
QueueQueues
MultisetMultisets
MultimapMultimaps
TableTables

Lists

Lists为List对象提供工具方法:

方法描述
partition(list, size)把list按size大小分割(除最后一块为,每块大小为size)
reverse(List)返回给定List的反转视图。若List是不可变,需使用:ImmutableList.reverse()
newArrayList(E... eles)使用给定的参数构造List

Maps

Maps中也封装了很多很酷的方法:

uniqueIndex

Maps.uniqueIndex(Iterable,Function):在对象的某个唯一属性上构造Map。

List<String> lstDiffLen = Lists.newArrayList("a", "bb", "ccc", "dddd");
Map<Integer, String> mapLen = Maps.uniqueIndex(lstDiffLen, String::length);
System.out.println(mapLen);

// {1=a, 2=bb, 3=ccc, 4=dddd}
difference

Maps.difference(Map, Map)用来比较两个Map以获取所有不同点,返回MapDifference对象:

视图说明
entriesInCommon()两个Map中都有的映射项:包括匹配的键与值
entriesDiffering()键相同但是值不同值映射项。返回的Map的值类型为MapDifference.ValueDifference(包含左右不同的值)
entriesOnlyOnLeft()键只存在于左边Map的映射项
entriesOnlyOnRight()键只存在于右边Map的映射项
Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3, "d", 4);
Map<String, Integer> right = ImmutableMap.of("b", 2, "c", 4, "d", 5, "e",6);
MapDifference<String, Integer> diff = Maps.difference(left, right);
System.out.println(diff.entriesInCommon());
System.out.println(diff.entriesDiffering());
System.out.println(diff.entriesOnlyOnLeft());
System.out.println(diff.entriesOnlyOnRight());

// {b=2}
// {c=(3, 4), d=(4, 5)}
// {a=1}
// {e=6}

扩展工具集

Guava为集合提供了扩展工具集:

  • ForwardingXXX装饰器:方便对集合扩展(继承),对所有方法提供了默认实现,只需修改扩展的类即可;
  • PeekingIterator:通过Iterators.peekingIterator(Iterator)方法,可把Iterator包装为PeekingIterator,能通过peek来获取下一个值;
  • AbstractIterator:通过扩展AbstractIterator可实现自己的iterator;

Forwarding

针对所有类型的集合接口,Guava都提供了对应的Forwarding抽象类。要扩展集合,只需继承对应Forwarding类,并:

  • 重载delegate()方法:delegate返回操作集合对象,所有其他方法都会自动委托给他;
  • 重载其他任何想要扩展的集合方法;

以实现有默认值的List为例(当对应值为null时,返回默认值),覆盖get与iterator方法:

public static class ListWithDefault<E> extends ForwardingList<E> {
    final E defaultValue;
    final List<E> delegate;

    ListWithDefault(List<E> delegate, E defaultValue) {
        this.delegate = delegate;
        this.defaultValue = defaultValue;
    }

    @Override
    protected List delegate() {
        return delegate;
    }

    @Override
    public E get(int index) {
        E v = super.get(index);
        return (v == null ? defaultValue : v);
    }

    @Override
    public Iterator<E> iterator() {
        final Iterator<E> iter = super.iterator();
        return new ForwardingIterator<E>() {
            @Override
            protected Iterator<E> delegate() {
                return iter;
            }

            @Override
            public E next() {
                E v = super.next();
                return (v == null ? defaultValue : v);
            }
        };
    }
}

// 使用
List<String> names = new ListWithDefault<String>(
        Arrays.asList("Alice", null, "Bob", "Carol", null),
        "UNKNOWN"
);
for (String name : names) {
    System.out.println(name);
}

Preconditions

Preconditions 提供了判断条件是否合法的静态方法,如果不符合要求会抛出异常(类似断言)。

方法声明描述检查失败时抛出的异常
checkArgument(boolean)检查boolean是否为true,用来检查传递给方法的参数IllegalArgumentException
checkNotNull(T)检查value是否为null,该方法直接返回value,因此可以内嵌使用checkNotNullNullPointerException
checkState(boolean)用来检查对象的某些状态。IllegalStateException
checkElementIndex(int index, int size)检查index作为索引值对某个列表、字符串或数组是否有效。index>=0 && index<sizeIndexOutOfBoundsException
checkPositionIndex(int index, int size)检查index作为位置值对某个列表、字符串或数组是否有效。index>=0 && index<=sizeIndexOutOfBoundsException
checkPositionIndexes(int start, int end, int size)检查[start, end]表示的位置范围对某个列表、字符串或数组是否有效IndexOutOfBoundsException

Ordering

排序器Ordering可用来构建复杂的比较器(实现了链式调用),以完成集合排序。

Ordering<Comparable> natural = Ordering.natural();
List<Integer>  lstNum = Lists.newArrayList(2,4,1,5,7,9,4,null);
System.out.println(natural.compare(1,2));
System.out.println(natural.nullsFirst().leastOf(lstNum, 2));
List<Integer> lstResult = natural.onResultOf(Objects::toString).sortedCopy(lstNum);
System.out.println(lstResult);

// -1
// [null, 1]
// [1, 2, 4, 4, 5, 7, 9, null]

创建排序器

Ordering中提供以下静态排序方法:

方法描述
natural()做自然排序,如:数字按大小,日期按先后等
usingToString()按对象的字符串形式做字典排序
from(Comparator)使用给定的Comparator排序

链式调用

通过链式调用,可通过给定的排序器衍生出其他排序器:

方法描述
reverse()反序排序器
nullsFirst()把null值排到最前面
nullsLast()把null值排到最后面
compound(Comparator)在当前排序器基础上,组合一个新的比较器(处理当前排序器中相等的情况)
lexicographical()基于处理类型T的排序器,返回该类型的可迭代对象Iterable的排序器。
onResultOf(Function)对集合中元素调用Function,再按返回值用当前排序器排序

使用

排序器个操作集合与元素的方法:

方法描述类似方法
greatestOf(Iterable iterable, int k)获取可迭代对象中最大的k个元素leastOf
isOrdered(Iterable)判断可迭代对象是否已按排序器排序:允许有排序值相等的元素。isStrictlyOrdered
sortedCopy(Iterable)返回一个排序的副本immutableSortedCopy
min(E, E)返回两个参数中最小的那个。如果相等,则返回第一个参数。max(E, E)
min(E, E, E, E...)返回多个参数中最小的那个。max(E, E, E, E...)
min(Iterable)返回迭代器中最小的元素。如果可迭代对象中没有元素,则抛出NoSuchElementException。max(Iterable)

缓存LoadingCache

在计算或检索一个值的代价很高,并且对同样的输入需要不止一次获取值的时候,就需要考虑缓存;Guava Cache适用于:

  • 愿意消耗一些内存空间来提升速度。
  • 预料到某些键会被查询一次以上。
  • 缓存中存放的数据总量不会超出内存容量。

CacheLoader

CacheLoader用于构建缓存,通过简单地重载load即可实现,并可灵活地控制失效(过期与刷新是在get时重新loading):

  • expireAfterWrite:指定项在一定时间内没有创建/覆盖时移除该key,下次取时重新load;
  • expireAfterAccess:指定项在一定时间内没有读写时移除该key,下次取时重新load;
  • refreshAfterWrite:指定时间内没有被创建/覆盖,再次访问时(超过指定时间),会去刷新该缓存;在新值没有到来之前,始终返回旧值

:expire过期后会移除key,在下次访问是同步去获取返回新值(一定获取到的是新值);refresh过期后不会移除key,而是下次访问会触发刷新,新值没有回来时返回旧值。

// LoadingCache在缓存项不存在时可以自动加载缓存
LoadingCache<Integer, Student> studentCache
        // CacheBuilder的构造函数是私有的,只能通过其静态方法newBuilder()来构造实例
        = CacheBuilder.newBuilder()
        .concurrencyLevel(2) // 并发级别为2,并发级别是指可以同时写缓存的线程数
        .expireAfterWrite(30, TimeUnit.SECONDS) // 写缓存后30秒钟过期
        .initialCapacity(10)// 初始容量为10
        .maximumSize(100) // 最大容量,超过100之后就会按照LRU最近虽少使用算法来移除缓存项
        .recordStats() // 要统计缓存的命中率
        .removalListener(new RemovalListener<Object, Object>() { // 缓存的移除通知
            @Override
            public void onRemoval(RemovalNotification<Object, Object> notification) {
                System.out.println(notification.getKey() + " removed as " + notification.getCause());
            }
        })
        //build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
        .build(new CacheLoader<Integer, Student>() {
                   @Override
                   public Student load(Integer key) throws Exception {
                       System.out.println("load student " + key);
                       return new Student(key, "name-" + key);
                   }
               }
        );

缓存回收

通过设定最大容量,以及过期时间可以让缓存自动回收(实际上缓存不会"自动"执行清理和回收工作,也不会在某个缓存项过期后马上清理;而是在写操作时顺带做少量的维护工作,或者偶尔在读操作时做——如果写操作实在太少的话)。

此外还可通过使用弱引用键值,让垃圾回收器自动回收:

  • CacheBuilder.weakKeys():使用弱引用存储键。当键没有其它(强或软)引用时,缓存项可以被垃圾回收;
  • CacheBuilder.weakValues():使用弱引用存储值。当值没有其它(强或软)引用时,缓存项可以被垃圾回收;
  • CacheBuilder.softValues():使用软引用存储值。在需要时(内存不足),按照全局最近最少使用的顺序回收。

除此之外,还可以显式地清除缓存项:

  • 个别清除:Cache.invalidate(key)
  • 批量清除:Cache.invalidateAll(keys)
  • 清除所有缓存项:Cache.invalidateAll()
  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值