guava学习
guava的基础使用
一、maven配置
1 2 3 4 5 | <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version> 30.0 -jre</version> </dependency> |
二、guava的几种常见的方法
1、非空判断、
使用guava使用Preconditions.checkNotNull
进行非空判断的好处,一是语义清晰代码优雅;二是你也可以自定义报错信息,这样如果参数为空,报错的信息清晰,可以直接定位到具体参数。
1 2 | String param2 = null ; String name2 = Preconditions.checkNotNull(param2, "param2 is null" ); |
2、预期值判断
和非空判断类似,可以比较当前值和预期值,如果不相等可以自定义报错信息抛出
1 2 3 4 | String param = "www.wdbyte.com2" ; String wdbyte = "www.wdbyte.com" ; Preconditions.checkArgument(wdbyte.equals(param), "[%s] 404 NOT FOUND" , param); // java.lang.IllegalArgumentException: [www.wdbyte.com2] 404 NOT FOUND |
3、是否越界
Preconditions
类还可以用来检查数组和集合的元素获取是否越界。
1 2 3 4 5 | // Guava 中快速创建ArrayList List<String> list = Lists.newArrayList( "a" , "b" , "c" , "d" ); // 开始校验 int index = Preconditions.checkElementIndex( 5 , list.size()); // java.lang.IndexOutOfBoundsException: index (5) must be less than size (4) |
4、不可变的集合
创建一个不能删除、不能修改、不能增加元素的集合
优点:
- 线程安全,因为不能修改任何元素,可以随意多线程使用且没有并发问题。
- 可以无忧的提供给第三方使用,反正修改不了。
- 减少内存占用,因为不能改变,所以内部实现可以最大程度节约内存占用。
- 可以用作常量集合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // 创建方式1:of ImmutableSet<String> immutableSet = ImmutableSet.of( "a" , "b" , "c" ); immutableSet.forEach(System.out::println); // a // b // c // 创建方式2:builder ImmutableSet<String> immutableSet2 = ImmutableSet.<String>builder() .add( "hello" ) .add( new String( "未读代码" )) .build(); immutableSet2.forEach(System.out::println); // hello // 未读代码 // 创建方式3:从其他集合中拷贝创建 ArrayList<String> arrayList = new ArrayList(); arrayList.add( "www.wdbyte.com" ); arrayList.add( "https" ); ImmutableSet<String> immutableSet3 = ImmutableSet.copyOf(arrayList); immutableSet3.forEach(System.out::println); // www.wdbyte.com // https |
5、集合操作工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 创建一个 ArrayList 集合 List<String> list1 = Lists.newArrayList(); // 创建一个 ArrayList 集合,同时塞入3个数据 List<String> list2 = Lists.newArrayList( "a" , "b" , "c" ); // 创建一个 ArrayList 集合,容量初始化为10 List<String> list3 = Lists.newArrayListWithCapacity( 10 ); LinkedList<String> linkedList1 = Lists.newLinkedList(); CopyOnWriteArrayList<String> cowArrayList = Lists.newCopyOnWriteArrayList(); HashMap<Object, Object> hashMap = Maps.newHashMap(); ConcurrentMap<Object, Object> concurrentMap = Maps.newConcurrentMap(); TreeMap<Comparable, Object> treeMap = Maps.newTreeMap(); HashSet<Object> hashSet = Sets.newHashSet(); HashSet<String> newHashSet = Sets.newHashSet( "a" , "a" , "b" , "c" ); |
6、集合交集并集差集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Set<String> newHashSet1 = Sets.newHashSet( "a" , "a" , "b" , "c" ); Set<String> newHashSet2 = Sets.newHashSet( "b" , "b" , "c" , "d" ); // 交集 SetView<String> intersectionSet = Sets.intersection(newHashSet1, newHashSet2); System.out.println(intersectionSet); // [b, c] // 并集 SetView<String> unionSet = Sets.union(newHashSet1, newHashSet2); System.out.println(unionSet); // [a, b, c, d] // newHashSet1 中存在,newHashSet2 中不存在 SetView<String> setView = Sets.difference(newHashSet1, newHashSet2); System.out.println(setView); // [a] |
7、字符拼接
可以看到使用 skipNulls()
可以跳过空值,使用 useFornull(String)
可以为空值自定义显示文本。
1 2 3 4 5 6 | ArrayList<String> list = Lists.newArrayList( "a" , "b" , "c" , null ); String join = Joiner.on( "," ).skipNulls().join(list); System.out.println(join); // a,b,c String join1 = Joiner.on( "," ).useForNull( "空值" ).join( "旺财" , "汤姆" , "杰瑞" , null ); System.out.println(join1); // 旺财,汤姆,杰瑞,空值 |
8、字符串分割
Guava 提供了 Splitter 类,并且有一系列的操作方式可以直观的控制分割逻辑。
1 2 3 4 5 6 | String str = ",a ,,b ," ; Iterable<String> split = Splitter.on( "," ) .omitEmptyStrings() // 忽略空值 .trimResults() // 过滤结果中的空白 .split(str); split.forEach(System.out::println); |
9、缓存
在开发中我们可能需要使用小规模的缓存,来提高访问速度。这时引入专业的缓存中间件可能又觉得浪费。现在可以了, Guava 中提供了简单的缓存类,且可以根据预计容量、过期时间等自动过期已经添加的元素。即使这样我们也要预估好可能占用的内存空间,以防内存占用过多。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | @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( "狼" )); /** * key=猫,value=Animal{name='汤姆', age=3},reason=EXPLICIT * Animal{name='灰太狼', age=4} * key=狗,value=Animal{name='旺财', age=1},reason=EXPIRED * key=狼,value=Animal{name='灰太狼', age=4},reason=EXPIRED * * com.google.common.cache.CacheLoader$InvalidCacheLoadException: CacheLoader returned null for key 狼. */ } /** * 缓存移除监听器 */ 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; @Override public String toString() { return "Animal{" + "name='" + name + '\ '' + ", age=" + age + '}' ; } public Animal(String name, Integer age) { this .name = name; this .age = age; } } |
这个例子中主要分为 CacheLoader、MyRemovalListener、LoadingCache。
CacheLoader 中重写了 load
方法,这个方法会在查询缓存没有命中时被调用,我这里直接返回了 null
,其实这样会在没有命中时抛出 CacheLoader returned null for key
异常信息。
MyRemovalListener 作为缓存元素失效时的监听类,在有元素缓存失效时会自动调用 onRemoval
方法,这里需要注意的是这个方法是同步方法,如果这里耗时较长,会阻塞直到处理完成。
LoadingCache 就是缓存的主要操作对象了,常用的就是其中的 put
和 get
方法了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话