Guava工具库

        Guava主要包含的常用的模块:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等。新版的 JDK 中已经直接引入了。

引入 Guava

在 pom.xml 文件中引入依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1-jre</version>
</dependency>

基本工具

用 Optional 来表示可能为 null 的对象

 

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

Java 在 JDK 8 中新增了Optional类

  • Guava中Optional 是 abstract 的,意味着可以有子类对象;Java的是 final 的,意味着没有子类对象。
  • Guava中 Optional 实现了 Serializable 接口,可以序列化;Java的没有。

        使用 Optional 除了赋予 null 语义,增加了可读性,最大的优点在于它是一种傻瓜式的防护。Optional 迫使你积极思考引用缺失的情况,因为你必须显式地从 Optional 获取引用。        

集合

先说一下为什么需要不可变集合?

  • 保证线程安全。在并发程序中,使用不可变集合既保证线程的安全性,也大大地增强了并发时的效率(跟并发锁方式相比)。
  • 如果一个对象不需要支持修改操作,不可变的集合将会节省空间和时间的开销。
  • 可以当作一个常量来对待,并且集合中的对象在以后也不会被改变。

        下面的先代码利用 JDK 的Collections.unmodifiableList(list)得到一个不可修改的集合 unmodifiableList。

List list = new ArrayList();
list.add("雷军");
list.add("乔布斯");

List unmodifiableList = Collections.unmodifiableList(list);
unmodifiableList.add("马云");

运行代码将会出现以下异常:

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.Collections$UnmodifiableCollection.add(Collections.java:1060)
	at com.itwanger.guava.NullTest.main(NullTest.java:29)

        执行 unmodifiableList.add() 的时候抛出了 UnsupportedOperationException 异常,说明 Collections.unmodifiableList() 返回了一个不可变集合。

        把 unmodifiableList.add() 换成 list.add()

List list = new ArrayList();
list.add("雷军");
list.add("乔布斯");

List unmodifiableList = Collections.unmodifiableList(list);
list.add("马云");

        再次执行的话,程序并没有报错,并且你会发现 unmodifiableList 中真的多了一个元素。Collections.unmodifiableList(list)实现的不是真正的不可变集合,当原始集合被修改后,不可变集合里面的元素也是跟着发生变化。

ImmutableList不会有这种错误:

List<String> stringArrayList = Lists.newArrayList("雷军","乔布斯");
ImmutableList<String> immutableList = ImmutableList.copyOf(stringArrayList);
immutableList.add("马云");

尝试 immutableList.add() 的时候会抛出 UnsupportedOperationException。Guava源码中已经把 add() 方法废弃了

/**
  * Guaranteed to throw an exception and leave the collection unmodified.
  *
  * @throws UnsupportedOperationException always
  * @deprecated Unsupported operation.
  */
@CanIgnoreReturnValue
@Deprecated
@Override
public final boolean add(E e) {
  throw new UnsupportedOperationException();
}

        尝试 stringArrayList.add() 修改原集合的时候 immutableList 并不会因此而发生改变。

除了不可变集合以外,还提供了新的集合类型,比如说:

  • Multiset,可以多次添加相等的元素。当把 Multiset 看成普通的 Collection 时,它表现得就像无序的 ArrayList;当把 Multiset 看作 Map<E, Integer> 时,它也提供了符合性能期望的查询操作。
  • Multimap,可以很容易地把一个键映射到多个值。
  • BiMap,一种特殊的 Map,可以用 inverse() 反转
    BiMap<K, V> 的键值映射;保证值是唯一的,因此 values() 返回 Set 而不是普通的 Collection

 字符串处理

        字符串表示字符的不可变序列,创建后就不能更改。在我们日常的工作中,字符串的使用非常频繁,熟练的对其操作可以极大的提升我们的工作效率。

        Joiner,可以用分隔符把字符串序列连接起来。下面的代码将会返回“雷军; 乔布斯”,你可以使用 useForNull(String) 方法用某个字符串来替换 null,而不像 skipNulls() 方法那样直接忽略 null

Joiner joiner = Joiner.on("; ").skipNulls();
return joiner.join("雷军", null, "乔布斯");

 拆分器—— Splitter,可以按照指定的分隔符把字符串序列进行拆分

Splitter.on(',')
        .trimResults()
        .omitEmptyStrings()
        .split("雷军,乔布斯,,   沉默王二");

缓存

        缓存在很多场景下都是相当有用的。你应该知道,检索一个值的代价很高,尤其是需要不止一次获取值的时候,就应当考虑使用缓存。

        Guava提供的 Cache 和 ConcurrentMap 很相似,但也不完全一样。最基本的区别是 ConcurrentMap 会一直保存所有添加的元素,直到显式地移除。相对地,Guava提供的 Cache 为了限制内存占用,通常都设定为自动回收元素。

@Test
public void testCache() throws ExecutionException, InterruptedException {

    CacheLoader cacheLoader = new CacheLoader<String, Animal>() {
        // 如果找不到元素,会调用这里
        @Override
        public Animal load(String s) {
            return null;
        }
    };
    LoadingCache<String, Animal> loadingCache = CacheBuilder.newBuilder()
        .maximumSize(1000) // 容量
        .expireAfterWrite(3, TimeUnit.SECONDS) // 过期时间
        .removalListener(new MyRemovalListener()) // 失效监听器
        .build(cacheLoader); //
    loadingCache.put("狗", new Animal("旺财", 1));
    loadingCache.put("猫", new Animal("汤姆", 3));
    loadingCache.put("狼", new Animal("灰太狼", 4));

    loadingCache.invalidate("猫"); // 手动失效

    Animal animal = loadingCache.get("狼");
    System.out.println(animal);
    Thread.sleep(4 * 1000);
    // 狼已经自动过去,获取为 null 值报错
    System.out.println(loadingCache.get("狼"));
}

/**
 * 缓存移除监听器
 */
class MyRemovalListener implements RemovalListener<String, Animal> {

    @Override
    public void onRemoval(RemovalNotification<String, Animal> notification) {
        String reason = String.format("key=%s,value=%s,reason=%s", notification.getKey(), notification.getValue(), notification.getCause());
        System.out.println(reason);
    }
}

class Animal {
    private String name;
    private Integer age;

    public Animal(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

        CacheLoader 中重写了 load 方法,这个方法会在查询缓存没有命中时被调用,我这里直接返回了 null,其实这样会在没有命中时抛出 CacheLoader returned null for key 异常信息。

        MyRemovalListener 作为缓存元素失效时的监听类,在有元素缓存失效时会自动调用 onRemoval 方法,这里需要注意的是这个方法是同步方法,如果这里耗时较长,会阻塞直到处理完成。

集合工具

创建空集合

        用Lists的newArrayList方法

List<Integer> list = Lists.newArrayList();

快速初始化集合

List<Integer> list = Lists.newArrayList(1, 2, 3);

笛卡尔积

如果你想将两个集合做笛卡尔积,Lists的cartesianProduct方法可以帮你实现

List<Integer> list1 = Lists.newArrayList(1, 2, 3);
List<Integer> list2 = Lists.newArrayList(4,5);
List<List<Integer>> productList = Lists.cartesianProduct(list1,list2);
System.out.println(productList);

执行结果:

[[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5]]

分页

如果你想将一个大集合分成若干个小集合,可以使用Lists的partition方法:

List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);
List<List<Integer>> partitionList = Lists.partition(list, 2);
System.out.println(partitionList);

执行结果:

[[1, 2], [3, 4], [5]]

流处理

如果我们想把某个集合转换成另外一个接口,可以使用Lists的 transform方法。例如:

List<String> list = Lists.newArrayList("a","b","c");
List<String> transformList = Lists.transform(list, x -> x.toUpperCase());
System.out.println(transformList);

将小写字母转换成了大写字母。

颠倒顺序

List<Integer> list = Lists.newArrayList(3, 1, 2);
List<Integer> reverseList = Lists.reverse(list);
System.out.println(reverseList);

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值