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 开发核心库,个人觉得实用性还是很高的(不然呢?嘿嘿嘿)。引入到你的项目后不仅能快速的实现一些开发中常用的功能,而且还可以让代码更加的优雅简洁。

我觉得适用于每一个 Java 项目,至于其他的一些功能,比如说散列、事件总线、数学运算、反射,就等待你去发掘了。

另外,我为你准备了一份中文版的官方文档(部分目录见上图),一共 190 页,写得非常详细,强烈建议你通过下面的方式下载一份放在桌面上!

链接:https://pan.baidu.com/s/1hrfaArC3UH6_ZNZEWCKzXA 密码:684a

推荐阅读:

自学java,学多久可以自己找到工作?

看完谷歌学长的刷题笔记,我决定 2021 年手撕这101道 Leetcode 算法题

如果内容对你有所帮助的话,请给我点个赞吧,笔芯~,你最美你最帅,你 2021 年发大财。

Guava - 拯救垃圾代码,写出优雅高效,效率提升N倍相关推荐

  1. Guava - 拯救垃圾代码,写出优雅高效,效率提升N倍

    Guava 项目是 Google 公司开源的 Java 核心库,它主要是包含一些在 Java 开发中经常使用到的功能,如数据校验.不可变集合.计数集合,集合增强操作.I/O.缓存.字符串操作等.并且 ...

  2. jvm大局观之内存管理篇: 理解jvm安全点,写出更高效的代码

    jvm大局观之内存管理篇: 理解jvm安全点,写出更高效的代码 - 知乎 前言 本篇是java内存区域管理系列教程之一 - 在得知GC Root的组成之后,如何在垃圾回收发生的时刻,找到GC Root ...

  3. 程序员如何写出优雅的代码?

    作者 | 老峰 责编 | 郭芮 一直以来,关于"代码规范"的话题都备受关注,业界甚至有很多流传甚广的段子不断调侃之.既然代码规范能引起这么大的共鸣,那么今天我们谈谈一个程序员的自我 ...

  4. 如何写出优雅的代码?

    希望你的代码如同你本人一样优雅.:) 我们编写的代码,除了用于机器执行产生我们预期的效果以外,更多的时候是给人读的,这个读代码的可能是后来的维护人员,更多时候是一段时间后的作者本人. 如何能够写出优雅 ...

  5. 如何写出优雅的 Golang 代码

    Go 语言是一门简单.易学的编程语言,对于有编程背景的工程师来说,学习 Go 语言并写出能够运行的代码并不是一件困难的事情,对于之前有过其他语言经验的开发者来说,写什么语言都像自己学过的语言其实是有问 ...

  6. 如何写出优雅的 Go 语言代码

    如何写出优雅的 Go 语言代码 查看全文 http://www.taodudu.cc/news/show-3196428.html 相关文章: 写日志的那些事儿 写有价值的单元测试 腾讯私有云MySQ ...

  7. 谈代码整洁之道,如何写出优雅的代码

    最近为了制定团队的代码规范,拜读了鲍勃大叔的<代码整洁之道>,读完之后,在如何写出整洁优雅的高质量代码方面有很大的启发.我认为<代码整洁之道>是我们提高编程能力和自我修养必读之 ...

  8. 优雅写mysql_如何写出优雅的代码?

    我 18 年在 PyCon 做过一次类似的分享 ,目的是如何写出优雅的代码.希望能部分回答这个问题,也希望与大家多多讨论.<聊聊编程原则>​zhuanlan.zhihu.com 要成为合格 ...

  9. php代码如何写得好看,如何写出优雅的PHP代码

    如何写出优雅的PHP代码 导语:PHP是一种通用开源脚本语言.语法吸收了C语言.Java和Perl的特点,利于学习,使用广泛,主要适用于Web开发领域.下面我们来看看如何写出优雅的PHP代码,希望对大 ...

最新文章

  1. html5开发windows8应用 windows8介绍
  2. nginx 入门配置
  3. 用Python分析元旦旅游热门城市,告诉你哪些景点性价比更高
  4. webstom设置和monokia配色方案
  5. 直男的浪漫有多可怕?
  6. java 项目做多级缓存_【开源项目系列】如何基于 Spring Cache 实现多级缓存(同时整合本地缓存 Ehcache 和分布式缓存 Redis)...
  7. leetcode612. 平面上的最近距离(SQL)
  8. Java国际化资源绑定-----示例
  9. mysql查询按值多的排序_MySQL查询结果按某值排序
  10. XJOI网上同步训练DAY6 T2
  11. VS2015镜像安装教程
  12. Java、对字符串中的字符排序
  13. 软件测试项目案例.pdf,【精选】最经典软件测试案例.pdf
  14. AV1:比HEVC/H.265更有效率的视频编码格式?
  15. 罗技无线键盘Windows和Ubuntu下锁定Fn键方法
  16. 使用Python开发小说下载器,不再为下载小说而发愁
  17. 投 资 网 站 建 设 方 案
  18. weiui使用jquery infinite无限滚动加载,数据重复自执行
  19. 【转】主板上的电压符号:vdd,vddq,5vsb,3.3sb,vcc3.3,Vdimm
  20. 4g全网通SMD贴片内置天线怎么选择?

热门文章

  1. 一道面试题:StringBuffer a=new StringBuffer (A); StringBuffer b=new StringBuffer
  2. 北大计算机图灵班,北大首期“图灵班”开班
  3. python 爬虫软件第一个程序
  4. 科学计算机如何进行复数运算,教你如何用你的卡西欧学生计算器进行复数运算!...
  5. Python的Request函数用法
  6. 【linux】僵尸进程(Defunct进程)的产生与避免
  7. 译文Deep Learning in Bioinformatics --深度学习在生物信息学领域的应用(1)
  8. Linux 离线安装 autoformat
  9. ArcGIS API for JavaScript 图层顺序
  10. 清北师哥推荐的CV/NLP 算法工程师培养计划,强无敌!