Google Guava,牛逼的脚手架

01、前世今生

你好呀,我是 Guava。

1995 年的时候,我的“公明”哥哥——Java 出生了。经过 20 年的发展,他已经成为世界上最流行的编程语言了,请允许我有失公允的把“之一”给去了。

虽然他时常遭受着各种各样的吐槽,但他始终没有停下前进的脚步。除了他本身的不断进化,围绕着他的大大小小的兄弟们也在不断地更新迭代。我正是在这样的背景下应运而生的,我简单易用,对我大哥是一个非常好的补充,可以说,只要你有使用我哥作为开发语言的项目,几乎都能看到我的身影。

我由 Google 公司开源,目前在 GitHub 上已经有 39.9k 的铁粉了,由此可以证明我的受欢迎程度。

我的身体里主要包含有这些常用的模块:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等。新版的 JDK 中已经直接把我引入了,可想而知我有多优秀,忍不住骄傲了。

这么说吧,学好如何使用我,能让你在编程中变得更快乐,写出更优雅的代码!

02、引入 Guava

如果你要在 Maven 项目使用我的话,需要先在 pom.xml 文件中引入我的依赖。

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

一点要求,JDK 版本需要在 8 以上。

03、基本工具

Doug Lea,java.util.concurrent 包的作者,曾说过一句话:“null 真糟糕”。Tony Hoare,图灵奖得主、快速排序算法的作者,当然也是 null 的创建者,也曾说过类似的话:“null 的使用,让我损失了十亿美元。”鉴于此,我用 Optional 来表示可能为 null 的对象。

代码示例如下所示。

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

我大哥在 JDK 8 中新增了 Optional 类,显然是从我这借鉴过去的,不过他的和我的有些不同。

  • 我的 Optional 是 abstract 的,意味着我可以有子类对象;我大哥的是 final 的,意味着没有子类对象。

  • 我的 Optional 实现了 Serializable 接口,可以序列化;我大哥的没有。

  • 我的一些方法和我大哥的也不尽相同。

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

除了 Optional 之外,我还提供了:

  • 参数校验

  • 常见的 Object 方法,比如说 Objects.equals、Objects.hashCode,JDK 7 引入的 Objects 类提供同样的方法,当然也是从我这借鉴的灵感。

  • 更强大的比较器

04、集合

首先我来说一下,为什么需要不可变集合。

  • 保证线程安全。在并发程序中,使用不可变集合既保证线程的安全性,也大大地增强了并发时的效率(跟并发锁方式相比)。

  • 如果一个对象不需要支持修改操作,不可变的集合将会节省空间和时间的开销。

  • 可以当作一个常量来对待,并且集合中的对象在以后也不会被改变。

与 JDK 中提供的不可变集合相比,我提供的 Immutable 才是真正的不可变,我为什么这么说呢?来看下面这个示例。

下面的代码利用 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.UnsupportedOperationExceptionat 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<String> stringArrayList = Lists.newArrayList("雷军","乔布斯");
ImmutableList<String> immutableList = ImmutableList.copyOf(stringArrayList);
immutableList.add("马云");

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

  /*** Guaranteed to throw an exception and leave the collection unmodified.** @throws UnsupportedOperationException always* @deprecated Unsupported operation.*/@CanIgnoreReturnValue@Deprecated@Overridepublic 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。

05、字符串处理

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

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

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

我还提供了拆分器—— Splitter,可以按照指定的分隔符把字符串序列进行拆分。

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

06、缓存

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

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

如果你愿意消耗一些内存空间来提升速度,你能预料到某些键会被查询一次以上,缓存中存放的数据总量不会超出内存容量,就可以使用 Cache。

来个示例你感受下吧。

@Test
public void testCache() throws ExecutionException, InterruptedException {CacheLoader cacheLoader = new CacheLoader<String, Animal>() {// 如果找不到元素,会调用这里@Overridepublic 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> {@Overridepublic 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 方法,这里需要注意的是这个方法是同步方法,如果这里耗时较长,会阻塞直到处理完成。

LoadingCache 就是缓存的主要操作对象了,常用的就是其中的 put 和 get 方法了。

07、尾声

上面介绍了我认为最常用的功能,作为 Google 公司开源的 Java 开发核心库,个人觉得实用性还是很高的(不然呢?嘿嘿嘿)。引入到你的项目后不仅能快速的实现一些开发中常用的功能,而且还可以让代码更加的优雅简洁。


往期推荐

Google 开源的依赖注入库,比 Spring 更小更快!


我去,这几个Linux指令太装B了|动图展示


Spring 事务失效的 8 大场景,面试官直呼666...


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544947.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ruby 将字符转数字计算_Ruby程序计算一个数字中的位数

ruby 将字符转数字计算计算位数 (Counting the number of digits) Ruby does not provide you any predefined direct method through which you can find the number of digits in a number. Though one method can be implemented by converting the number into a string an…

python_L2_operator

1. i/j – division – if both are ints, result is int, represen9ng quo9ent without remainder e.g. 3/2 1 3.0/2 1.5  but   -3/2 -2 2. --2 >>> 2 3. a * 2 >>> aa 4 . abc[-1] returns c 5. world[:-1] returns worl转载于:https://www.cnbl…

Android Call requires API level 11 (current min is 8)的解决方案

【错误描述】 在用Eclipse开发过程中&#xff0c;为了兼容Android2.2和4.0以上版本&#xff0c;我在使用Notification类时做了2个版本的代码&#xff0c;代码根据系统版本不同执行相应模块&#xff0c;结果&#xff0c;等我输完代码&#xff0c;发现系统提示了一个这么的错误。…

阿里巴巴Druid,轻松实现MySQL数据库加密!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;为什么要加密&#xff1f;现在的开发习惯&#xff0c;无论是公司的项目还是个人的项目&#xff0c;都会选择将源码上传到 Gi…

计算机图形学图形旋转_计算机图形学中的平板显示

计算机图形学图形旋转平板显示器 (Flat Panel Display) It is generally known as FPD, the flat-panel display is such a display technology which overtakes Cathode Ray Tube as a new standard of computer desktop displays. Unlike monitors through CRT, flat-panel d…

一文掌握Redisson分布式锁原理|干货推荐

ReentrantLock 重入锁在说 Redisson 之前我们先来说一下 JDK 可重入锁: ReentrantLockReentrantLock 保证了 JVM 共享资源同一时刻只允许单个线程进行操作实现思路ReentrantLock 内部公平锁与非公平锁继承了 AQS[AbstractQueuedSynchronizer]1、AQS 内部通过 volatil 修饰的 in…

android创建文件夹和文件的一些经验教训

这几天做一个功能需要在手机上创建一个文件夹&#xff0c;然后往里面存储一些文件&#xff0c;首先得考虑用户有没有sdcard&#xff0c;如果有就在sdcard上创建一个指定的文件夹&#xff0c;如果没有则在你的工程所在的目录“/data/data/你的包名”下创建文件夹。用到的方法是&…

7种分布式事务的解决方案,一次讲给你听

本文约5300字&#xff0c;阅读时长「5分钟」什么是分布式事务分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器「分别位于不同的分布式系统的不同节点之上」。一个大的操作由N多的小的操作共同完成。而这些小的操作又分布在不同的服务上。针对于这些操…

js中的转译_JavaScript中的填充和转译

js中的转译JavaScript is rapidly advancing. Today its the most popular programming/scripting language that devs use to code logic and applications and is used in umpteen number of places. The community behind its development hasnt stopped creating and addin…

css @media 响应式布局

2019独角兽企业重金招聘Python工程师标准>>> &#xfeff;1、在 html 标签中 <link rel"stylesheet" type"text/css" href"style1.css" media"screen and (min-width: 600px) and (max-width: 800px)"> 2、在样式表中…

Apache JK Tomcat 集群问题

2019独角兽企业重金招聘Python工程师标准>>> 这几天被集群并发问题快折腾死了&#xff0c;望哪位高人看下到底是哪里出现了问题。 Apache Server是正常的&#xff0c;各服务器的Tomcat 也是正常的&#xff0c;但当Apache的连接数达到 300左右的时候&#xff0c;JK就…

Redis实现分布式锁的7种方案,及正确使用姿势!

种方案前言日常开发中&#xff0c;秒杀下单、抢红包等等业务场景&#xff0c;都需要用到分布式锁。而Redis非常适合作为分布式锁使用。本文将分七个方案展开&#xff0c;跟大家探讨Redis分布式锁的正确使用方式。如果有不正确的地方&#xff0c;欢迎大家指出哈&#xff0c;一起…

c#中的long类型示例_C#中带示例的无符号字节数组

c#中的long类型示例C&#xff03;中的无符号字节数组 (Unsigned Byte Array in C#) In C#.Net, we can create an unsigned byte array by using byte, byte is used to store only positive values between the range of 0 to 255 (Unsigned 8 bits integer). 在C&#xff03;…

Android软件开发之盘点所有Dialog对话框大合集(一)

转&#xff1a;http://xys289187120.blog.51cto.com/3361352/657562/ 雨松MOMO带大家盘点Android 中的对话框 今天我用自己写的一个Demo 和大家详细介绍一个Android中的对话框的使用技巧。 1.确定取消对话框 对话框中有2个按钮 通过调用 setPositiveButton 方法 和 setNegat…

JDK 9 对字符串 String 的优化,挺有意思!

String类可以说是Java编程中使用最多的类了&#xff0c;如果能对String字符串的性能进行优化&#xff0c;那么程序的性能必然能大幅提升。这不JDK9就对String字符串进行了改进升级&#xff0c;在某些场景下可以让String字符串内存减少一半&#xff0c;进而减少JVM的GC次数。Str…

PHP将数组存入数据库中的四种方式

PHP将数组存入数据库中的四种方式 最近突然遇到了一个问题&#xff0c;如何用PHP将数组存入到数据库中&#xff0c;经过自己的多方查找和研究&#xff0c;总结了以下四种方法&#xff1a;1.implode()和explode()方式2.print_r()和自定义函数方式3.serialize()和unserialize()方…

c#中.clear()作用_清单 .Clear()方法以及C#中的示例

c#中.clear()作用C&#xff03;List <T> .Clear()方法 (C# List<T>.Clear() Method) List<T>.Clear() method is used to clear the list, it remove all elements from the list. List <T> .Clear()方法用于清除列表&#xff0c;它从列表中删除所有元…

Android开发:利用Activity的Dialog风格完成弹出框设计

转&#xff1a;http://www.linuxidc.com/Linux/2011-08/41933.htm 在我们使用Dialog时&#xff0c;如果需要用到很多自己设计的控件&#xff0c;虽然可以让弹出框显示出我们需要的界面&#xff0c;但却无法找到地方完成控制代码的编写&#xff0c;如何解决这个问题呢,我们可以将…

Java中实现定时任务的3种方法!

今天我们不用任何框架&#xff0c;用最朴素的 Java API 来实现定时任务&#xff0c;本文会介绍 3 种实现方案&#xff0c;我们一起来看...1、 sleep 这也是我们最常用的 sleep 休眠大法&#xff0c;不只是当作休眠用&#xff0c;我们还可以利用它很轻松的能实现一个简单的定时任…

回文子序列_计算回文子序列的总数

回文子序列Problem statement: 问题陈述&#xff1a; Given a string str, find total number of possible palindromic sub-sequences. A sub-sequence does not need to be consecutive, but for any xixj i<j must be valid in the parent string too. Like "icl&q…