1. 概述
在项目开发过程中,一般我们都会用到很多类库,比如 spring,guava,hutool,apache io/commons等等等等相关一堆类库。本文就来介绍一下常见的类库以及使用方式,以作备忘和学习。
1.1 为什么学习类库?
1.1.1 提高效率
这是使用类库最重要的原因!
使用别人写好的类库可以很大程度上提高开发效率,在Java开发中我们自己写的代码(这里指的是偏工具类型的代码)是很少的,更多的代码是由各种类库来提供的,否则重复造轮子,开发周期会非常的长。
1.1.2 提高安全性
使得代码安全性更高
各种的经典类库被非常多的公司引用,并且运行了无数次,很少出现bug,但是我们自己实现这些功能浪费时间不说,并且还容易出现一些意想不到的bug,说不定什么时候就暴雷了,而经典的类库都是经过了时间的考验相对来说更稳定一些。
1.1.3 学习设计思想
可以学习好的设计思想
一般比较出名的、使用广泛的类库,都是由比较出名的组织或者大佬编写的,其中很多考虑到了扩展,健壮,安全,稳定,易用性等等这些,可以从中学习到一些思想,从而给自己助力&提升。
下边我们介绍一下guava 这个类库,guava这个类库很优秀,非常值的我们去使用&学习。
2. Guava
2.1 概述
Guava是一个基于Java的开源库,包含许多Google核心库,这些库在许多项目中都有使用
使用他有助于我们去学习最佳编码方式,并且帮助我们减少编码错误, 它为集合,缓存,并发,通用注释,字符串处理,I/O和验证等相关编程过程中的需求, 提供了大量开箱即用的方法。
2.1.1 Guava的优点
- 高效设计良好的API,被Google的开发者设计,实现和推广使用。
- 遵循高效的java语法实践。
- 使代码更简练,简洁,简单。
- 节约时间,资源,提高生产力。
2.1.2 源码结构
源码包包含了以下这些工具,可以根据需求使用,其中比较经典的有cache,collect,eventbus,concurrent,等等, 具体见下边:
- com.google.common.annotations:普通注解类型。
- com.google.common.base:基本工具类库和接口。
- com.google.common.cache:缓存工具包,非常简单易用且功能强大的JVM缓存。
- com.google.common.collect:带泛型的集合接口扩展和实现,以及工具类,这里你会发现很多好玩的集合。
- com.google.common.eventbus:发布订阅风格的事件总线。
- com.google.common.graph:对“图”数据结构的支持。
- com.google.common.hash: 哈希工具包。
- com.google.common.io:I/O工具包。
- com.google.common.math:数学相关工具包。
- com.google.common.net:网络工具包。
- com.google.common.primitives:八种原始类型和无符号类型的静态工具包。
- com.google.common.reflect:反射工具包。
- com.google.common.util.concurrent:多线程工具包。
- com.google.common.escape:提供了对字符串内容中特殊字符进行替换的框架,并包括了Xml和Html的两个实现。
- com.google.common.html:HtmlEscapers封装了对html中特殊字符的替换。
- com.google.common.xml:XmlEscapers封装了对xml中特殊字符的替换。
2.1.3 引入坐标
我们可以在maven的pom中引入最新的坐标和版本,然后就可以使用了
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.1-jre</version> </dependency>
2.2 基础工具类
Guava的经典很大一部分原因来源于对于基础工具类的封装,使用这些类能够让我们的代码更加优雅且完善,这些类大部分都在
com.google.common.base
包下
2.2.1 注意事项
JDK有很多借鉴
guava
的地方,这里只讲guava
,并且JDK在不断的完善,如果JDK中有已经存这些工具类,建议就不要用guava
了
2.2.2 Optional(注意这里说的是Guava 中的 Optional)
2.2.2.1 作用
在构造对象的时候就明确申明该对象是否可能为null,快速失败拒绝null值,可以避免空指针异常。
2.2.2.2 使用
public class OptionTest { public static void main(String[] args) { Integer a = null; Integer b = 10; //支持传入null以及非null的数据 Optional<Integer> optional_a = Optional.fromNullable(a); Optional<Integer> optional_b = Optional.fromNullable(b); //of方式支支持非null的数据 //Optional<Integer> optional_c = Optional.fromNullable(a); //创建一个空的没有对象引用的Option Optional<Integer> optional_d = Optional.absent(); //不存在对象实例不进入 if (optional_a.isPresent()) { System.out.println("A:" + optional_a.get()); } //存在对象实例进入 if (optional_b.isPresent()) { System.out.println("B:" + optional_b.get()); } //不存在对象实例不进入 if (optional_d.isPresent()) { System.out.println("D:" + optional_d.get()); } } }
2.2.2.3 源码结构
Optional封装了Absent对象以及Present对象,如果参数为空,则Optional封装
Absent
否则封装Present
2.2.2.4 JDK8替代
在JDK8以及更高版本,可以使用
java.util.Optional
来代替使用
2.2.3 Preconditions
2.2.3.1 作用
封装了前置条件校验,让方法中的条件检查更简单
实际开发中需要做入参校验的情况比比皆是,比如开发一个rest接口,肯定要对参数各种校验,防止错误的输入导致程序出错,我们可以使用Preconditions(前置条件),这样我们自己代码中就不会出现大段的if代码了
2.2.3.2 以前的做法
以前我们都是大段的用if写各种判断,如果入参很多,或者校验逻辑很复杂,这个函数中if会越来越多,圈复杂度越来越高
public static void query(String name, int age) { if (name == null || name.equals("")) { throw new IllegalArgumentException("name should not be empty."); } if (age <= 0||age>=100) { throw new IllegalArgumentException("age should not be negative."); } }
2.2.3.3 代码优化
使用Preconditions对我们的代码进行优化
public static void query(String name, int age) { Preconditions.checkNotNull(name,"name should not be empty."); Preconditions.checkArgument(!"".equals(name),"name should not be empty."); Preconditions.checkArgument(age >= 0 && age < 100,"age should not be negative."); }
使用Preconditions就可以消除代码中的if了,当然也可以使用Assert ,后边我们会讲。
2.2.3.4 常见的一些校验
- checkArgument: 检查boolean是否为真,用作方法中检查参数,失败时抛出的异常类型: IllegalArgumentException
- checkNotNull:检查value不为null, 直接返回value,失败时抛出的异常类型:NullPointerException
- checkState:检查对象的一些状态,不依赖方法参数,失败时抛出的异常类型:IllegalStateException
- checkElementIndex:检查index是否为在一个长度为size的list, string或array合法的范围,失败时抛出的异常类型:IndexOutOfBoundsException
- checkPositionIndex:检查位置index是否为在合法的范围,index的范围区间是[0, size]失败时抛出的异常类型:IndexOutOfBoundsException
2.2.4 Splitter
2.2.4.1 作用
Splitter 可以让你使用一种非常简单流畅的模式来控制字符分割的行为
2.2.4.2 String.split的问题
Java 中关于分词的工具类会有一些古怪的行为,
String.split
函数会悄悄地丢弃尾部的分割符,下边做个演示:
2.2.4.3 Splitter优化
而使用 Splitter 可以让你使用一种非常简单流畅的模式来解决这些令人困惑的行为
public static void guavaSplit(String str) { List<String> strings = Splitter.on(","). //omitEmptyStrings(). splitToList(str); strings.forEach(x -> System.out.print(x + ";")); }
这样尾部空格不会被跳过,可以正常显示尾部空串
2.2.4.4 去除空格
Splitter还支持自定义分割字符串,比如去掉空格、去掉空字符串等等,上面代码可以优化为
public static void guavaSplit(String str) { List<String> strings = Splitter.on(","). //将结果中的空格删除(如果有的话) trimResults(). //移去结果中的空字符串 omitEmptyStrings(). //需要分割的字符串 splitToList(str); strings.forEach(x -> System.out.print(x + ";")); }
执行后将会去除空格(如果有的话)以及空字符串
2.2.4.5 MapSplitter
Splitter除了可以对字符进行拆分,还可以对URL参数进行拆分,比如URL参数
id=123&name=green
public static void guavaSplit3(String str) { //分割字符串,获取URL`?`后面的参数部分 String param = str.split("\?")[1]; Map<String, String> paramMap = Splitter. //先按照`&`符号进行分割 on("&"). //在分割的符号里面在按照`=`进行分割 withKeyValueSeparator("="). //需要切分的字符串 split(str); System.out.println(paramMap); }
2.2.5 Joiner
2.2.5.1 作用
Guava 的 Joiner 让字符串连接变得极其简单,即使字符串中包含 null,也很容易处理
Joiner相当于spliter的反操作,可以将数组或者集合等可遍历的数据转换成使用分隔符连接的字符串
2.2.5.2 Java实现方式
对于这样的list进行数据进行拼接,需要排除空字符串和null的数据
List<String> list = new ArrayList<String>() { { add("1"); add("2"); add(null); add("3"); }};
如果只使用Java方式需要使用以下的方式进行实现
public static String javaJoin(List<String> strList, String delimiter) { StringBuilder builder = new StringBuilder(); for (String str : strList) { if (null != str) { builder.append(str).append(delimiter); } } builder.setLength(builder.length() - delimiter.length()); return builder.toString(); }
实现方式很简单,但是很繁琐
2.2.5.3 Joiner方式优化
我们不在考虑更多的细节,并且很有语义的告诉代码的阅读者,用什么分隔符,需要过滤null值再join
public static String guavaJoin1(List<String> strList, String delimiter) { return Joiner.on(delimiter).skipNulls().join(strList); }
2.2.5.4 MapJoinner
Joiner还可以处理URL编码的生成,将MAP数据转换成对应的URL参数
Map<String, String> map = ImmutableMap.of("id", "123", "name", "green"); //第一个分隔符使用&,第二个参数分割符使用 = String joinStr = Joiner.on("&").withKeyValueSeparator("=").join(map); System.out.println(joinStr);
2.2.6 StopWatch
StopWatch用来计算经过的时间(精确到纳秒)
2.2.6.1 原始的计时方式
原始的方式代码复杂,并且很不美观,性能也存在问题
public static void task() throws InterruptedException { long currentTime = System.currentTimeMillis(); //业务代码 Thread.sleep(1000); long duration = System.currentTimeMillis() - currentTime; System.out.println("执行耗时:" + duration + "ms"); }
2.2.6.2 优化代码
我们发现优化后从代码上来看优雅很多,并且使用起来也比较简单
public static vo标签:类库,总结,google,String,common,2.2,com,第三方 From: https://blog.csdn.net/wjianwei666/article/details/140766422