Commons类库

commons: 一套开发源码、免费使用、商业友好的优秀API作为Java自带API的补充,大多数都是一些工具类
包括

  • Commons BeanUtils,针对Bean的一个工具集。由于Bean往往是有一堆get和set组成,所以BeanUtils也是在此基础上进行一些包装。
  • Commons CLI,这是一个处理命令的工具。比如main方法输入的string[]需要解析。你可以预先定义好参数的规则,然后就可以调用CLI来解析。
  • Commons Codec,这个工具是用来编码和解码的,包括Base64,URL,Soundx等等。
  • Commons Collections,可以把这个工具看成是java.util的扩展。
  • Commons Configuration,这个工具是用来帮助处理配置文件的,支持很多种存储方式
  • Commons DbUtils,DbUtils就是把数据库操作单独做一个包这样的工具,以后开发不用再重复这样的工作了。这个工具并不是现在流行的OR-Mapping工具(比如Hibernate),只是简化数据库操作
  • Commons FileUpload,文件上传。
  • Commons HttpClient,这个工具可以方便通过编程的方式去访问网站
  • Commons IO,可以看成是java.io的扩展
  • Commons JXPath,JXpath就是基于Java对象的Xpath,也就是用Xpath对Java对象进行查询
  • Commons Lang,这个工具包可以看成是对java.lang的扩展。提供了诸如StringUtils, StringEscapeUtils, RandomStringUtils, Tokenizer, WordUtils等工具类
  • Commons Logging,提供了log4j
  • Commons Math,这个包提供的功能有些和Commons Lang重复,但是这个包更专注于做数学工具,功能更强大
  • Commons Net,这个包还是很实用的,封装了很多网络协议
  • Commons Validator,用来帮助进行验证的工具。比如验证Email字符串,日期字符串等是否合法。
  • Commons virtual File System 提供对各种资源的访问接口。支持的资源类型包括

平时常用的是commons-lang、commons-collection、commons-beanutils、commons-codec、commons-io,Commons Logging。

commons-lang

Lang 主要是一些公共的工具集合,比如对字符、数组的操作等等
1.ArrayUtils

  1. // 有时我们需要将两个数组合并为一个数组,用ArrayUtils就非常方便,示例如下:
  2. private void testArr() {
  3. String[] s1 = new String[] { "1", "2", "3" };
  4. String[] s2 = new String[] { "a", "b", "c" };
  5. String[] s = (String[]) ArrayUtils.addAll(s1, s2);
  6. Stream.of(s).forEach(System.out::println);
  7. String str = ArrayUtils.toString(s);
  8. System.out.println(str + ">>" + str.length());
  9. }

2. StringUtils

private void testStringUtils() {
        // 截取FROM之后的内容,并去掉空格
        String testTrim = StringUtils.substringAfter("SELECT * FROM PERSON ", "FROM").trim();
        System.out.println("截取FROM之后的内容,并去掉空格:" + testTrim);
        // 只能正整数.
        System.out.println("是否是正整数:" + StringUtils.isNumeric("454534"));
        System.out.println("判断是否相等:" + StringUtils.equals("454534", "454534"));
        System.out.println("判断忽略大小写之后是否相等:" + StringUtils.equalsIgnoreCase("ABC534", "abc534"));
        // 判断是否是空格和null
        System.out.println("判断是否是空格和null:" + StringUtils.isBlank("   "));
        List<String> list = Lists.newArrayList("a", "b", "c");
        // 将数组中的内容以,分隔
        System.out.println("将数组中的内容以,分隔:" + StringUtils.join(list, ","));
        // 在右边加下字符,使之总长度为6
        System.out.println("在右边加下字符,使之总长度为6:" + StringUtils.rightPad("123", 6, '0'));
        // 首字母大写
        System.out.println("首字母大写:" + StringUtils.capitalize("abc"));
        // 删除所有空格
        System.out.println("删除所有空格:" + StringUtils.deleteWhitespace("   ab  c  "));
        // 判断是否包含这个字符
        System.out.println("判断是否包含这个字符:" + StringUtils.contains("abc", "ba"));
        // 表示左边两个字符
        System.out.println("表示左边两个字符:" + StringUtils.left("abc", 2));
    }

3.ClassUtils

private void testClassUtils() {
    System.out.println("短类名:" + ClassUtils.getShortClassName(TestMglApplicationTests.class));  
    System.out.println("包名:" + ClassUtils.getPackageName(TestMglApplicationTests.class));  
}

4.NumberUtils

// math
    private void testNumberUtils() {
        // 可以识别正负小数等 就别用stringutils里的isnumberic.
        System.out.println(NumberUtils.toInt("a", 0));
        System.out.println(NumberUtils.isNumber("-2.5"));
        System.out.println(NumberUtils.isNumber("2.5"));
    }

5.RandomStringUtils

private void testRandomStringUtils() {
        // 字母加数字
        System.out.println("字母加数字:" + RandomStringUtils.randomAlphanumeric(5));
        // 字母
        System.out.println("字母:" + RandomStringUtils.randomAlphabetic(5));
        // 数字
        System.out.println("数字:" + RandomStringUtils.randomNumeric(5));
    }

6.StringEscapeUtils

private void testStringEscapeUtils() {
        // 转义反转义
        System.out.println("转义:" + StringEscapeUtils.escapeHtml("<html>"));
        System.out.println("反转义:" + StringEscapeUtils.unescapeHtml("&lt;html&gt;"));
    }

7.DateFormatUtils

// 日期格式化
    org.apache.commons.lang3.time.DateFormatUtils.format(final Date date, final String pattern)

8.DateUtils

// 是否是同一天(忽略时间)
org.apache.commons.lang3.time.DateUtils.isSameDay(final Date date1, final Date date2)
// 是否同一时间点
org.apache.commons.lang3.time.DateUtils.isSameInstant(final Date date1, final Date date2)
// 解析日期字符串为 Date
org.apache.commons.lang3.time.DateUtils.parseDate(final String str, final String... parsePatterns)
// 日期的加减
org.apache.commons.lang3.time.DateUtils.addYears(final Date date, final int amount)

org.apache.commons.lang3.time.DateUtils.addMonths(final Date date, final int amount)

org.apache.commons.lang3.time.DateUtils.addWeeks(final Date date, final int amount)

org.apache.commons.lang3.time.DateUtils.addDays(final Date date, final int amount)

org.apache.commons.lang3.time.DateUtils.addHours(final Date date, final int amount)

org.apache.commons.lang3.time.DateUtils.addMinutes(final Date date, final int amount)

org.apache.commons.lang3.time.DateUtils.addSeconds(final Date date, final int amount)

org.apache.commons.lang3.time.DateUtils.addMilliseconds(final Date date, final int amount)

commons-collection

Collections 对java.util的扩展封装,处理数据还是挺灵活的。
org.apache.commons.collections – Commons Collections自定义的一组公用的接口和工具类

  • bag – 实现Bag接口的一组类
  • bidimap – 实现BidiMap系列接口的一组类
  • buffer – 实现Buffer接口的一组类
  • collection – 实现java.util.Collection接口的一组类
  • comparators – 实现java.util.Comparator接口的一组类
  • functors – Commons Collections自定义的一组功能类
  • iterators – 实现java.util.Iterator接口的一组类
  • keyvalue – 实现集合和键/值映射相关的一组类
  • list – 实现java.util.List接口的一组类
  • map – 实现Map系列接口的一组类
  • set – 实现Set系列接口的一组类
    private void testOrderedMap() {
          // 得到集合里按顺序存放的key之后的某一Key
          OrderedMap map = new LinkedMap();
          map.put("FIVE", "5");
          map.put("SIX", "6");
          map.put("SEVEN", "7");
          System.out.println(map.firstKey());
          System.out.println(map.nextKey("FIVE"));
          System.out.println(map.nextKey("SIX"));
      }
    
    private void testBidiMap() {
          BidiMap bidi = new TreeBidiMap();
          bidi.put("SIX", "6");
          // 通过key得到value
          System.out.println(bidi.get("SIX"));
          // 通过value得到key
          System.out.println(bidi.getKey("6"));
          // 将map里的key和value对调
          BidiMap inverse = bidi.inverseBidiMap();
          System.out.println(inverse);
      }
    
    private void testList() {
           // 得到两个集合中相同的元素
           List<String> list1 = Lists.newArrayList("1", "2", "3");
           List<String> list2 = Lists.newArrayList("5", "2", "3");
           // 交集 map
           System.out.println("交集:" + CollectionUtils.intersection(list1, list2));
           // 交集,ListUtils
           System.out.println("交集:" + CollectionUtils.retainAll(list1, list2));
           // 并集
           System.out.println("并集:" + CollectionUtils.union(list1, list2));
           // 减
           System.out.println("集合1减集合2:" + CollectionUtils.subtract(list1, list2));
           // 加
           CollectionUtils.addAll(list1, list2.iterator());
           System.out.println("集合1加集合2:" + list1);
           list2.add(null);
           System.out.println("集合2加NULL:" + list2);
           // 不为空才加
           list2.forEach(key -> CollectionUtils.addIgnoreNull(list1, key));
           System.out.println("不为空才加:" + list1);
      }
    
    CollectionUtils
    // 集合判空
    org.apache.commons.collections.CollectionUtils.isEmpty(Collection coll)
    org.apache.commons.collections.CollectionUtils.isNotEmpty(Collection coll)
    
    ``` 判断两个集合是否有交集 org.apache.commons.collections.CollectionUtils.containsAny(final Collection coll1, final Collection coll2)

对 collection 集合元素执行 closure 中定义的操作 org.apache.commons.collections.CollectionUtils.forAllDo(Collection collection, Closure closure)

通过 predicate 判断是否返回 true/false ,可判断某个元素是否存在 org.apache.commons.collections.CollectionUtils.exists(Collection, Predicate)

通过 predicate 对集合元素进行过滤,注意是在原来的集合上操作 org.apache.commons.collections.CollectionUtils.filter(Collection collection, Predicate predicate)

查找符合 predicate 条件的元素,注意是返回新创建的集合 org.apache.commons.collections.CollectionUtils.select(Collection inputCollection, Predicate predicate)

对集合元素进行转换 org.apache.commons.collections.CollectionUtils.transform(Collection collection, Transformer transformer)

注意这些方法:都会执行集合元素的遍历,时间复杂度为 O(n),集合数据量太大要优化请使用其它方法 ps: Predicate , Transformer, Closure 这些不就是所谓的函数式接口嘛

转换为不能修改的集合 org.apache.commons.collections.CollectionUtils.unmodifiableCollection(Collection collection)


**MapUtils**

// Map 判空 org.apache.commons.collections.MapUtils.isEmpty(Map map) org.apache.commons.collections.MapUtils.isNotEmpty(Map map) // Map 取值 避免类型转换和空指针问题 org.apache.commons.collections.MapUtils.getString(final Map map, final Object key) org.apache.commons.collections.MapUtils.getBoolean(final Map map, final Object key) org.apache.commons.collections.MapUtils.getInteger(final Map map, final Object key) org.apache.commons.collections.MapUtils.getString( Map map, Object key, String defaultValue ) // 转换为不能修改的Map org.apache.commons.collections.MapUtils.unmodifiableMap(Map map)

<a name="c14a6"></a>
## commons-beanutils
**BeanUtils** 提供了对于JavaBean进行各种操作, 比如对象,属性复制等等。<br />**1、对象的克隆**

private void testBeanutils() { Book book = new Book(); book.setXh(Lists.newArrayList(“1”, “2”)); book.setName(“论语”); book.setPrice(100); book.setContent(Lists.newArrayList(“己所不欲,勿施于人。”, “不患人之不己知,患不知人也。”)); try { // 克隆,没克隆属性. Book cloneBook = (Book)BeanUtils.cloneBean(book); System.out.println(“克隆:” + cloneBook.toString()); // 不建议用apache赋值,会抛出异常,可用spring提供的不用try.注意参数顺序 Book cloneBook2 = new Book(); org.springframework.beans.BeanUtils.copyProperties(book, cloneBook2); System.out.println(“赋值:” + cloneBook2.toString()); } catch (Exception e) { e.printStackTrace(); } }

**2、 将一个Map对象转化为一个Bean,通过Java的反射机制来做的。**<br />不建议自己去写过多的反射Util,可以从以下工具类方法中去找适合自己的:

- PropertyUtils
- BeanUtils
- ClassUtils
- FieldUtils
- ArtertyClassUtil
- ReflectUtil

private void testMap2Bean() { // 这个Map对象的key必须与Bean的属性相对应. Map map = Maps.newHashMap(); map.put(“xh”, Lists.newArrayList(“1”)); map.put(“name”, “论语”); map.put(“price”, 100); map.put(“content”, Lists.newArrayList(“己所不欲,勿施于人。”)); try { // 将map转化为对象属性. Book book = new Book(); BeanUtils.populate(book, map); System.out.println(“Map2Bean :” + book.toString()); // 将对象转换为map. Map newMap = BeanUtils.describe(book); System.out.println(“Bean2Map :” + newMap); } catch (Exception e) { e.printStackTrace(); } }

<a name="uv2rZ"></a>
## commons-codec
**Codec** 提供了一些公共的编解码实现,比如Base64, Hex, MD5,Phonetic and URLs等等。

System.out.println(Base64.encodeBase64String(“test”.getBytes())); System.out.println(new String(Base64.decodeBase64(“dGVzdA==”), StandardCharsets.UTF_8)); System.out.println(DigestUtils.md5Hex(“asdfasdfasdfasfdasdfasdfasfasd”)); // 可以直接使用spring 提供的 System.out.println(Base64Utils.encodeToString(“absd”.getBytes())); System.out.println(new String(Base64Utils.decodeFromString(“YWJzZA==”), StandardCharsets.UTF_8));

<a name="clnHF"></a>
## common-io
**IO** 对java.io的扩展 操作文件非常方便。

//1.读取Stream //标准代码:
try (InputStream in = new URL( “http://jakarta.apache.org“ ).openStream()) { InputStreamReader inR = new InputStreamReader(in); BufferedReader buf = new BufferedReader(inR); String line; while ((line = buf.readLine()) != null) { System.out.println(line); } }

**使用IOUtils**

try (InputStream in = new URL( “http://www.baidu.com").openStream()) { System.out.println( IOUtils.toString(in, StandardCharsets.UTF_8)); } //比较两个流是否相等 InputStream in = new URL(“http://www.baidu.com").openStream(); InputStream in2 = new URL(“http://www.baidu.com").openStream(); System.out.println(IOUtils.contentEquals(in, in2)); //将字节从InputStream复制到OutputStream或者是ByteArrayOutputStream File src = new File(“D:/test.txt”); InputStream inputStream = new FileInputStream(src); File dest = new File(“D:/blank.txt”); OutputStream outputStream = new FileOutputStream(dest); IOUtils.copy(inputStream, outputStream); //从输入流中读取字节(通常返回输入流的字节数组的长度) InputStream in4 = new URL(“http://www.baidu.com").openStream(); byte[] buffer = new byte[100000]; System.out.println(IOUtils.read(in4, buffer)); //获得输入流的内容放回一个List类型的容器,每一行为这个容器的一个入口,使用特定的字符集(如果为空就使用默认的字符集) InputStream in5 = new URL(“http://www.baidu.com").openStream(); List list = IOUtils.readLines(in5, StandardCharsets.UTF_8); Iterator iter = list.iterator(); while(iter.hasNext()){ System.out.println(iter.next()); }

```
// 关闭流
org.apache.commons.io.IOUtils.closeQuietly(InputStream input)
org.apache.commons.io.IOUtils.closeQuietly(OutputStream output)

// 输入流转字节数组, 需要手动关闭 input
org.apache.commons.io.IOUtils.toByteArray(InputStream input)
// 将字节数组写到输出流,需要手动关闭 output
org.apache.commons.io.IOUtils.write(byte[] data, OutputStream output)
// 从输入流复制到输出流,由于返回值复制的字节数为 int ,流数据需小于2GB,否则返回 -1
org.apache.commons.io.IOUtils.copy(InputStream input, OutputStream output)
// 从输入流复制到输出流,流数据大于2GB
org.apache.commons.io.IOUtils.copyLarge(InputStream input, OutputStream output)

使用FileUtils

File src = new File("D:/test.txt");
    List lines = FileUtils.readLines(src, "UTF-8");
    System.out.println(lines);
    File dest = new File("D:/blank.txt");
    //拷贝文件 --这里会覆盖--而非追加
    FileUtils.copyFile(src, dest);
    //拷贝文件到某一路径
    FileUtils.copyFileToDirectory(src, new File("E:/"));
    //写字符串到一个文件--此种为覆盖的方法
    String string = "Blah blah blah";
    FileUtils.writeStringToFile(dest, string, "ISO-8859-1");
    // 向文件追加内容.
    FileUtils.write(dest, "hhhhhhhhh", StandardCharsets.UTF_8, true);
    //删除文件实例
    File file = new File( ("E:/test.txt") );
    FileUtils.forceDelete(file);
 ------------------------------------------------------------------------------------
 // 打开一个文件流
 org.apache.commons.io.FileUtils.openInputStream(File file)
 // 列出目录下的文件
 org.apache.commons.io.FileUtils.listFiles(File directory, String[] extensions, boolean recursive)
 // 删除文件或目录和目录下的所有文件(包含目录)
 org.apache.commons.io.FileUtils.forceDelete(File file)
 // 清空目录下的所有文件和目录(不包括需要清空的目录,意思是目录下的内容清空)
 org.apache.commons.io.FileUtils.cleanDirectory(File dir)
 // jvm 正常退出时调用 shutdown hook 执行清除文件操作(一般不用,如果要用,请三思而后行)
 org.apache.commons.io.FileUtils.forceDeleteOnExit(File file)

使用FilenameUtils

  • 获取文件扩展名

    foo.txt      --> "txt"
    a/b/c.jpg    --> "jpg"
    a/b.txt/c    --> ""
    a/b/c        --> ""
    org.apache.commons.io.FilenameUtils.getExtension(String filename)
    
  • 删除文件扩展名

    foo.txt    --> foo
    a\b\c.jpg  --> a\b\c
    a\b\c      --> a\b\c
    a.b\c      --> a.b\c
    org.apache.commons.io.FilenameUtils.removeExtension(String)
    
  • 判断是否匹配给定的文件扩展名 ``` FilenameUtils.isExtension(“a.txt”, new String[]{“txt”}) = true FilenameUtils.isExtension(“a/b.doc”, new String[]{“docx”,”doc”}) = true FilenameUtils.isExtension(“a/c”, new String[]{“”}) = true

org.apache.commons.io.FilenameUtils.isExtension(String, String[])

org.apache.commons.io.FilenameUtils.isExtension(String, String)


---

<a name="Cd72S"></a>
# Guava
<a name="tfQqa"></a>
## Guava是什么?

- java开源库,提供用于集合,缓存,支持原语,并发性,常见注解,字符串处理,I/O和验证的实用方法。
- 标准化-由google托管
- 高效、可靠
- 优化-经过高度优化

com.google.guava guava

<a name="HHZ9L"></a>
## 常用类与接口
<a name="bf9ke"></a>
##### 1.集合的创建

// 普通Collection的创建 List list = Lists.newArrayList(); Set set = Sets.newHashSet(); Map map = Maps.newHashMap(); // 不变Collection的创建 ImmutableList iList = ImmutableList.of(“a”, “b”, “c”); ImmutableSet iSet = ImmutableSet.of(“e1”, “e2”); ImmutableMap iMap = ImmutableMap.of(“k1”, “v1”, “k2”, “v2”);

_**不可变集合**_

- 在多线程操作下,是线程安全的。
- 所有不可变集合会比可变集合更有效的利用资源。
- 中途不可改变。

**示例**

//以前 Map> map = new HashMap>(); List list = new ArrayList(); list.add(1); list.add(2); map.put(“aa”, list); S System.out.println(map.get(“aa”));//[1, 2]

```
Multimap<String,Integer> map = ArrayListMultimap.create(); 
map.put("aa", 1); 
map.put("aa", 2); 
System.out.println(map.get("aa")); //[1, 2]
  • MultiSet:无序+可重复 count()方法获取重复的次数 增强了可读性+操作简单 创建方式: Multiset set = HashMultiset.create();
  • Multimap:key-value key可以重复 创建方式: Multimap teachers = ArrayListMultimap.create();
  • BiMap:双向Map(Bidirectional Map) 键与值都不能重复 创建方式: BiMap biMap = HashBiMap.create();
  • Table:双键的Map Map—> Table—>rowKey+columnKey+value //和sql中的联合主键有点像 创建方式: Table tables = HashBasedTable.create();

    2.将集合转换为特定规则的字符串
    List<String> list = Lists.newArrayList("aa","bb","cc"); 
    System.out.println(Joiner.on("-").join(list));
    

    3.将String转换为特定的集合
    String str = "1-2-3-4-5-6"; 
    List<String> list = Splitter.on("-").splitToList(str);
    

    4.将String转换为map
    String str = "xiaoming=11,xiaohong=23"; 
    Map<String,String> map = Splitter.on(",").withKeyValueSeparator("=").split(str);
    

    5.guava还支持多个字符切割,或者特定的正则分隔
    String input = "aa.dd,,ff,,.";
    List<String> result = Splitter.onPattern("[.|,]").omitEmptyStrings().splitToList(input);
    

    其它

    // 判断匹配结果 
    boolean result = CharMatcher.inRange('a', 'z').or(CharMatcher.inRange('A', 'Z')).matches('K'); //true 
    // 保留数字文本 
    String s1 = CharMatcher.digit().retainFrom("abc 123 efg"); //123
    // 删除数字文本 
    String s2 = CharMatcher.digit().removeFrom("abc 123 efg"); //abc efg
    

    6.set的交集, 并集, 差集
    HashSet setA = newHashSet(1, 2, 3, 4, 5); 
    HashSet setB = newHashSet(4, 5, 6, 7, 8); 
    SetView union = Sets.union(setA, setB);  //union:12345867 
    SetView difference = Sets.difference(setA, setB); //difference:123678
    SetView intersection = Sets.intersection(setA, setB); //intersection:45
    

    7.检查参数
    //use java 
    (str !=null && !str.isEmpty()) 
    //use guava 
    if(!Strings.isNullOrEmpty(str)) 
    //use java 
    if (count <= 0) { throw new IllegalArgumentException("must be positive: " + count); } 
    //use guava 
    Preconditions.checkArgument(count > 0, "must be positive: %s", count);
    

    8.计算中间代码的运行时间
    Stopwatch stopwatch = Stopwatch.createStarted();
    for (int i = 0; i < 10000000; i++) {
      // watch
    }
    long nanos = stopwatch.elapsed(TimeUnit.MILLISECONDS);
    System.out.println(nanos);
    

    9.文件操作
    File from=...;  
    File to=...;  
    Files.copy(from,to); //复制文件
    Files.move(File from, File to); //移动文件 
    URL url = Resources.getResource("abc.xml"); //获取classpath根下的abc.xml文件url
    

    10.Optional

    Guava库设计了Optional来解决null含义模糊的问题(1).静态方法

  • Optional.of(T): 获得一个Optional对象,其内部包含了一个非null的T数据类型实例,若T=null,则立刻报错。  

  • Optional.absent(): 获得一个Optional对象,其内部包含了空值  
  • Optional.fromNullable(T): 将一个T的实例转换为Optional对象,T的实例可以不为空,也可以为空[Optional.fromNullable(null)],和Optional.absent()等价。

(2).实例方法

  • boolean isPresent(): 果Optional包含的T实例不为null,则返回true;若T实例为null,返回false
  • T get(): 返回Optional包含的T实例,该T实例必须不为空;否则,对包含null的Optional实例调用get()会抛出一个IllegalStateException异常
  • or(T): ptional实例中包含了传入的T的相同实例,返回Optional包含的该T实例,否则返回输入的T实例作为默认值
  • T orNull(): 返回Optional实例中包含的非空T实例,如果Optional中包含的是空值,返回null,逆操作是fromNullable()
  • Set asSet(): 不可修改的Set,该Set中包含Optional实例中包含的所有非空存在的T实例,且在该Set中,每个T实例都是单态,如果Optional中没有非空存在的T实例,返回的将是一个空的不可修改的Set。

    private void testOptional(){
      Optional<Long> value = method();
      if(value.isPresent()==true){
          System.out.println("获得返回值: " + value.get());     
      }else{
          System.out.println("获得返回值: " + value.or(-12L));    
      }
      System.out.println("获得返回值 orNull: " + value.orNull());
      Optional<Long> valueNoNull = methodNoNull();
      if(valueNoNull.isPresent()==true){
          Set<Long> set=valueNoNull.asSet();
          System.out.println("获得返回值 set 的 size : " + set.size());    
          System.out.println("获得返回值: " + valueNoNull.get());     
      }else{
          System.out.println("获得返回值: " + valueNoNull.or(-12L));    
      }
      System.out.println("获得返回值 orNull: " + valueNoNull.orNull());
    }
    private Optional<Long> method() {
      return Optional.fromNullable(null);
    }
    private Optional<Long> methodNoNull() {
      return Optional.fromNullable(15L);
    }
    
  • 参考资料:https://www.yiibai.com/guava

**


Hutool

简介

Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。
Hutool中的工具方法来自于每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;
Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。

Hutool名称的由来

Hutool = Hu + tool,是原公司项目底层代码剥离后的开源库,“Hu”是公司名称的表示,tool表示工具。Hutool谐音“糊涂”,一方面简洁易懂,一方面寓意“难得糊涂”。

Hutool如何改变我们的coding方式

Hutool的目标是使用一个工具方法代替一段复杂代码,从而最大限度的避免“复制粘贴”代码的问题,彻底改变我们写代码的方式。
以计算MD5为例:

  • 【以前】打开搜索引擎 -> 搜“Java MD5加密” -> 打开某篇博客-> 复制粘贴 -> 改改好用
  • 【现在】引入Hutool -> SecureUtil.md5()

Hutool的存在就是为了减少代码搜索成本,避免网络上参差不齐的代码出现导致的bug。

包含组件

一个Java基础工具类,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类,同时提供以下组件:

模块 介绍
hutool-aop JDK动态代理封装,提供非IOC下的切面支持
hutool-bloomFilter 布隆过滤,提供一些Hash算法的布隆过滤
hutool-cache 简单缓存实现
hutool-core 核心,包括Bean操作、日期、各种Util等
hutool-cron 定时任务模块,提供类Crontab表达式的定时任务
hutool-crypto 加密解密模块,提供对称、非对称和摘要算法封装
hutool-db JDBC封装后的数据操作,基于ActiveRecord思想
hutool-dfa 基于DFA模型的多关键字查找
hutool-extra 扩展模块,对第三方封装(模板引擎、邮件、Servlet、二维码、Emoji、FTP、分词等)
hutool-http 基于HttpUrlConnection的Http客户端封装
hutool-log 自动识别日志实现的日志门面
hutool-script 脚本执行封装,例如Javascript
hutool-setting 功能更强大的Setting配置文件和Properties封装
hutool-system 系统参数调用封装(JVM信息等)
hutool-json JSON实现
hutool-captcha 图片验证码实现
hutool-poi 针对POI中Excel和Word的封装
hutool-socket 基于Java的NIO和AIO的Socket封装

可以根据需求对每个模块单独引入,也可以通过引入hutool-all方式引入所有模块。

  • hutool-json

image.png
处理效率要比阿里巴巴的fastjson效率高,fastjson低版本有安全漏铜
image.pngimage.gif
参考资料:https://hutool.cn/


Mvel

Mvel是什么

简单来说是一种强大的表达式解析器。我们可以自己写一些表达式,交给mvel进行解析计算,得到这个表达式计算的值。
比如我们要进行一个加法运算。在java中我们这样写:

int res = 1+1;  // 2

若我用mvel则这样写:

Object res = MVEL.eval("1+1");  //2

是不是很吃惊😱。“1+1”就是一个表达式,第一种我们是硬编码实现的计算结果,但是第二种方案,直接给evel函数传递一个表达式字符串,直接能计算出结果。这样如果想计算1-1。直接传人不同的表达式即可。现在要计算’(2+2)*3+5/2’或’2>1?1+1:2+2’。来吧你硬编码试试这些计算?是不是又要多写几行代码,而且不便扩展。
你以为mvel只能做这些了?那就真的是太年轻了。目前mvel支持大量的语法,条件,循环等。还可以支持自定义函数,这就🐂了。那么我们工作中用这东西来干嘛?

  • 在自定义数据流转中的使用
    数据流转就是不同对象间数据的转换。比如a对象数据通过某些规则转化为b对象数据。这说的是不是数据清洗?对,说的没错,但是数据清洗只是其中的一个具体项罢了。👍,来个图:
    对象a ———————-> 转换 —————————-> 对象b

image.png
由图可以看出两个对象name和age都是一对一映射,但是目标对象不需要sex字段,但是多了一个出生年的字段,而且是通过年龄计算而来。下面我们就以代码来模拟一下这个转换过程,在这里我对象都用map来定义。
但是代码不够优雅。

// 对象a
HashMap<Object, Object> a = Maps.newHashMap();
a.put("name", "zs");
a.put("age", 10);
a.put("sex", "女");
// 字段映射关系
HashMap<String, String> mapping = Maps.newHashMap();
mapping.put("name", "name");
mapping.put("age", "age");
mapping.put("birthYear", "2020-age");
// 目标对象
HashMap<Object, Object> b = Maps.newHashMap();
// k为目标表字段,v为转换规则
b.forEach((k, v) -> {
    Object reValue = MVEL.eval((String)v, a);
    b.put(k, reValue);
});
System.out.println("源对象" + a);
System.out.println("目标对象" + b);
  • 将自定义函数注册

    static ParserContext context = new ParserContext();
    static {
      //MvelTest是getCurrentYear函数的类
      Method[] declaredMethods = MvelTest.class.getDeclaredMethods();
      for(Method method : declaredMethods){
          context.addImport(method.getName(),method);
      }
    }
    
    /**
    * 获取当前年份方法
    * @return
    */
    public static Object getCurrentYear(){
      Calendar date = Calendar.getInstance();
      String year = String.valueOf(date.get(Calendar.YEAR));
      return year;
    }
    

    重构一下:

    // 对象a
    HashMap<Object, Object> a = Maps.newHashMap();
    a.put("name", "zs");
    a.put("age", 10);
    a.put("sex", "女");
    // 字段映射关系
    HashMap<String, String> mapping = Maps.newHashMap();
    mapping.put("name", "name");
    mapping.put("age", "age");
    mapping.put("birthYear", "getCurrentYear()-age");
    // 目标对象
    HashMap<Object, Object> b = Maps.newHashMap();
    // k为目标表字段,v为转换规则
    mapping.forEach((k, v) -> {
      Object reValue = MVEL.executeExpression(MVEL.compileExpression(v, context), a);
      b.put(k, reValue);
    });
    System.out.println("源对象" + a);
    System.out.println("目标对象" + b);
    

    compileExpression的作用就是将我们的规则进行编译成mvel可以识别的一个过程
    birthYear规则替换为mapping.put("birthYear","getCurrentYear()-age");执行得到相同的结果。
    有了这些我们可以自定义更多的转换规则,还可以借此开发一套用户配置工具,根据用户自己的配置,进行相应的资源映射。得到想要的目标数据。

    绩效考核项目中的运用

    场景:绩效考核系统中有大量的计算指标是要做各式各样的统计计算,且这些指标的计算规则每年都要变

  • 引入计算引擎表达式,大大减少人工维护成本

image.png
没有引入之前:绩效系统的计算类
image.png
引入之后:
image.png

  • 指标维护
    指标1:
    image.png

指标2:
image.png