当前位置: 首页 > 科技观察

GoogleGuava,优秀的脚手架

时间:2023-03-15 13:12:20 科技观察

本文转载自微信公众号《沉默之王二》,可通过以下二维码关注。转载本文请联系沉默王二公众号。01.前世你好,我是番石榴。1995年,我的“公明”弟弟Java诞生了。经过20年的发展,他已经成为世界上最流行的编程语言,请允许我不公平地给“一个”。尽管他经常遭受各种抱怨,但他从未停止过前进的脚步。除了自己不断进化,他的大大小小的兄弟们也在不断更新迭代。我就是在这样的背景下出生的。我简单好用,对弟弟来说是一个很好的补充。可以说,只要你有使用我哥作为开发语言的项目,几乎都能看到我的身影。我是谷歌开源的,目前我在GitHub上有39.9k的粉丝,这证明了我的受欢迎程度。我的主体主要包含这几个常用模块:集合[collections]、缓存[caching]、原生类型支持[primitivessupport]、并发库[concurrencylibraries]、常用注解[commonannotations]、字符串处理[stringprocessing]、I/o等我已经直接引入新版JDK了。可想而知,我有多优秀,不禁得意。这么说吧,学会用好我,会让你编程更快乐,写出更优雅的代码!02.引入Guava如果想在Maven项目中使用我,需要先在pom.xml文件中引入我的依赖。com.google.guavaguava30.1-jre一个要求,JDK版本需要在8.03以上。基础工具java.util.concurrent包的作者DougLea曾经说过:“null真的很糟糕”。TonyHoare,图灵奖得主,快速排序算法的作者,当然也是null的创造者,说过类似的话:“null的使用让我损失了十亿美元。”出于这个原因,我使用Optional来表示一个可能为空的对象。代码示例如下所示。Optionalpossible=Optional.of(5);possible.isPresent();//returnstruepossible.get();//returns5大哥在JDK8中添加了Optional类,明显是我借的,但是他的和我的有点不同。我的Optional是抽象的,这意味着我可以有子类对象;我哥哥的是最终的,这意味着没有子类对象。我的Optional实现了Serializable接口,可以被序列化;我哥哥的没有。我的一些方法也与我哥哥的不同。除了赋予空语义和增加可读性之外,使用Optional的最大优势在于它是一种万无一失的保护。Optional迫使您积极思考缺少的引用,因为您必须明确地从Optional获取引用。除了Optional,我还提供了:参数验证CommonObject方法,比如Objects.equals,Objects.hashCode,JDK7引入的Objects类也提供了同样的方法,当然也是受到了我的启发。更强大的比较器04.Sets首先说一下为什么需要immutablesets。保证线程安全。在并发程序中,不可变集合的使用不仅保证了线程的安全,而且大大提升了并发的效率(与并发锁相比)。如果一个对象不需要支持修改操作,不可变集合会节省空间和时间开销。可以当作一个常量,集合中的对象以后不会改变。与JDK中提供的不可变集合相比,我提供的Immutable是真正的不可变。我为什么这么说?看看下面的例子。下面的代码使用JDK的Collections.unmodifiableList(list)得到一个不可修改的集合unmodifiableList。Listlist=newArrayList();list.add("雷军");list.add("乔布斯");ListunmodifiableList=Collections.unmodifiableList(list);unmodifiableList.add("马云");运行代码时会出现以下异常:.main(NullTest.java:29)很好,执行unmodifiableList。在add()期间抛出UnsupportedOperationException,表明Collections.unmodifiableList()返回了一个不可变集合。但事实真的如此吗?您可以将unmodifiableList.add()替换为list.add()。Listlist=newArrayList();list.add("雷军");list.add("乔布斯");ListunmodifiableList=Collections.unmodifiableList(list);list.add("马云");再次执行,程序并没有报错,你会发现unmodifiableList中真的多了一个元素。这是什么意思?Collections.unmodifiableList(…)不是真正的不可变集合。当原始集合被修改时,不可变集合中的元素也会发生变化。我不会犯这个错误,看看下面的代码。ListstringArrayList=Lists.newArrayList("雷军","乔布斯");ImmutableListimmutableList=ImmutableList.copyOf(stringArrayList);immutableList.add("马云");当您尝试immutableList.add()时抛出UnsupportedOperationException。我已弃用源代码中的add()方法。/***Guaranteedtothrowanexceptionandleavethecollectionunmodified.**@throwsUnsupportedOperationException();}尝试抛出newUnsupportedOperationException();}尝试在stringArrayList.add(时修改原集合。除了不可变集合,我还提供了新的集合类型,比如:Multiset,可以多次添加相等的元素。当Multiset看成一个普通的Collection时,它表现得像一个无序的ArrayList;当Multiset看成一个MapMultimap时,一个键可以很容易地映射到多个值。BiMap,一种特殊的ofMapthatcanbereversewithinverse()BiMap05,字符串处理字符串代表了一个一旦创建就不能改变的不可变字符序列,在我们日常工作中,字符串的使用频率很高,熟练的操作它们可以大大提高我们的工作效率.我提供了一个连接器——Joiner,它可以连接带分隔符的字符串序列。下面的代码会返回“LeiJun;Jobs”,可以使用useForNull(String)方法将null替换为字符串,而不是像skipNulls()方法那样直接忽略null。Joinerjoiner=Joiner.on(";").skipNulls();returnjoiner.join("雷军",null,"乔布斯");我还提供了一个拆分器——Splitter,可以将字符串按照指定的分隔符进行拆分。Splitter.on(',').trimResults().omitEmptyStrings().split("雷军,乔布斯,沉默之王II");06.CacheCache在很多场景下都非常有用。您应该意识到检索一个值的成本很高,尤其是当您需要多次提取该值时,您应该考虑使用缓存。我提供的Cache和ConcurrentMap类似,但不完全一样。基本区别在于ConcurrentMap保留所有添加的元素,直到明确删除。相比之下,我提供的Cache通常设置为自动回收元素,以限制内存使用。如果你愿意消耗一些内存空间来提高速度,你可以预期一些key会被查询不止一次,并且缓存中存储的数据总量不会超过内存容量,你可以使用Cache。举个例子大家感受一下。@TestpublicvoidtestCache()throwsExecutionException,InterruptedException{CacheLoadercacheLoader=newCacheLoader(){//如果找不到元素,会在这里调用@OverridepublicAnimalload(Strings){returnull;}};LoadingCacheloadingCache=CacheBuilder.newBuilder().maximumSize(1000)//capacity.expireAfterWrite(3,TimeUnit.SECONDS)//过期时间.removalListener(newMyRemovalListener())//失败listener.build(cacheLoader);//loadingCache.put("狗",newAnimal("旺财",1));loadingCache.put("猫",newAnimal("汤姆",3));loadingCache.put("狼",newAnimal("灰太狼",4));loadingCache.invalidate("cat");//手动失效Animalanimal=loadingCache.get("wolf");System.out.println(animal);Thread.sleep(4*1000);//Wolf自动通过,get空值报错System.out.println(loadingCache.get("Wolf"));}/***缓存移除监听器*/classMyRemovalListenerimplementsRemovalListener{@OverridepublicvoidonRemoval(RemovalNotificationnotification){Stringreason=String.format("key=%s,value=%s,reason=%s",notification.getKey(),notification.getValue(),notification.getCause());System.out.println(reason);}}classAnimal{privateStringname;privateIntegerage;publicAnimal(Stringname,Integerage){this.name=name;this.age=age;}}CacheLoader重写了load方法,当查询缓存未命中。我这里直接返回了null。其实这样在没有命中的情况下会抛出CacheLoaderreturnednullforkey异常信息。MyRemovalListener用作缓存元素失效时的监听类。该方法是一种同步方法。如果这里耗时较长,就会阻塞,直到处理完成。LoadingCache是??缓存的主要操作对象,常用的有put和get方法。07.最后,我已经介绍了上面最常用的功能。作为Google开源的Java开发核心库,个人觉得还是很实用的(不然呢?嘿嘿嘿)。引入到你的项目中后,不仅可以快速实现一些开发中常用的功能,还可以让代码更加优雅简洁。我认为它适用于每一个Java项目。至于其他的功能,比如哈希、事件总线、数学运算、反射等,就等你去发现了。