Hutool工具(一)

HuTool

image-20200617202110372

一、简介

准备环境

Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。

Hutool中的工具方法来自于每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;

Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。

1. 名称由来

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

2. Hutool如何改变我们的coding方式

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

以计算MD5为例:

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

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


二、包含组件

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

模块介绍
hutool-aopJDK动态代理封装,提供非IOC下的切面支持
hutool-bloomFilter布隆过滤,提供一些Hash算法的布隆过滤
hutool-cache简单缓存实现
hutool-core核心,包括Bean操作、日期、各种Util等
hutool-cron定时任务模块,提供类Crontab表达式的定时任务
hutool-crypto加密解密模块,提供对称、非对称和摘要算法封装
hutool-dbJDBC封装后的数据操作,基于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-jsonJSON实现
hutool-captcha图片验证码实现
hutool-poi针对POI中Excel和Word的封装
hutool-socket基于Java的NIO和AIO的Socket封装

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


三、使用HuTool

HuTool使用非常简单直接在项目中引入如下依赖即可:

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.3.7</version>
</dependency>

四、克隆操作

对于浅拷贝来说,当成员变量引用类型时,浅拷贝拷贝的是地址;当成员变量基本类型时,浅拷贝拷贝的是

对于深拷贝来说,无论成员变量是基本类型还是引用类型,采用的都是值传递,而不是拷贝了一个地址。

1. 以前如何克隆

浅拷贝
  • 实现JDK中的Cloneable接口,并重写**clone()**方法

JDK中的Cloneable接口只是一个空接口,并没有定义成员,它存在的意义仅仅是指明一个类的实例化对象支持位复制(就是对象克隆),Object中有clone()方法,我们需要实现重写clone()方法并且我们需要自己强转下类型

深拷贝
  • 方法一:
    • 对于引用类型的成员变量也实现浅拷贝就好了,也就是无限递归下去
  • 方法二:
    • 通过对象序列化和反序列化首先深拷贝(推荐)
    • 实现Serializable接口,然后自定义拷贝方法deepClone(),详细见深拷贝

2. Hutools中如何克隆

浅拷贝
  • 方法一:Cloneable 接口

    cn.hutool.core.clone.Cloneable接口,此接口定义了一个返回泛型的成员方法,这样,实现此接口后会提示必须实现一个public的clone方法,调用父类clone方法即可:

    /**
     * 猫猫类,使用实现Cloneable方式
     */
    private static class Cat implements Cloneable<Cat>{
        private String name = "miaomiao";
        private int age = 2;
        
        @Override
        public Cat clone() {
            try {
                return (Cat) super.clone();
            } catch (CloneNotSupportedException e) {
                throw new CloneRuntimeException(e);
            }
        }
    }
    
  • 方法二:继承 CloneSupport 类

    实现cn.hutool.core.clone.Cloneable接口实现浅拷贝依旧有不方便之处,就是必须自己实现一个public类型的clone()方法,还要调用父类(Object)的clone方法并处理异常。于是cn.hutool.clone.CloneSupport类产生,这个类帮我们实现了上面的clone方法,因此只要继承此类,不用写任何代码即可使用clone()方法:

    /**
     * 狗狗类,用于继承CloneSupport类
     *
     */
    private static class Dog extends CloneSupport<Dog>{
        private String name = "wangwang";
        private int age = 3;
    }
    

    上面两种方式肯定继承CloneSupport类更方便,但是如果需要实现克隆的类已经继承了其他类,无法再继承CloneSupport 类,那么只能实现Cloneable 接口了,因为java只支持单继承,但是支持多实现

  • 方法三:

深拷贝
  • 方法一:直接调用hutools的cloneByStream()方法,前提是对象必须实现Serializable接口,如果对象中的一些属性也是对象的话,属性对象所属的类也必须实现 Serializable接口

    ObjectUtil.cloneByStream(obj)
    
  • 方法二:直接调用hutools的clone方法,前提是对象必须实现Serializable接口,当然如果对象中的一些属性也是对象的话,属性对象所属的类也必须实现 Serializable接口

    ObjectUtil.clone(obj)
    

五、Convert类型转换

1. 痛点

在Java开发中我们要面对各种各样的类型转换问题,尤其是从命令行获取的用户参数、从HttpRequest获取的Parameter等等,这些参数类型多种多样,我们怎么去转换他们呢?常用的办法是先整成String,然后调用XXX.parseXXX方法,还要承受转换失败的风险,不得不加一层try catch,这个小小的过程混迹在业务代码中会显得非常难看和臃肿。

2. Convert类

Convert类可以说是一个工具方法类,里面封装了针对Java常见类型的转换,用于简化类型转换。Convert类中大部分方法为toXXX,参数为Object,可以实现将任意可能的类型转换为指定类型。同时支持第二个参数defaultValue用于在转换失败时返回一个默认值。

3. 如何使用

1. 转换为字符串
int a = 1;
//aStr为"1"
String aStr = Convert.toStr(a);

long[] b = {1,2,3,4,5};
//bStr为:"[1, 2, 3, 4, 5]"
String bStr = Convert.toStr(b);
2. 转换为指定类型数组
String[] b = { "1", "2", "3", "4" };
//结果为Integer数组
Integer[] intArray = Convert.toIntArray(b);

long[] c = {1,2,3,4,5};
//结果为Integer数组
Integer[] intArray2 = Convert.toIntArray(c);
3. 转换为日期对象
String str = "2012-12-12";
// 以前这样将字符串转为日期
Date parse = new SimpleDateFormat("yyyy-MM-dd").parse(str);

// 现在这样将字符串转为日期
Date date = Convert.toDate(str);
System.out.println(date);
String str1 = "2012/12/12";
Date date1 = Convert.toDate(str1);
System.out.println(date1);
4.转换为集合
Object[] a = {"a", "你", "好", "", 1};
List<?> list = Convert.convert(List.class, a);
//从4.1.11开始可以这么用
List<?> lists = Convert.toList(a);

5. 普通字符串与16进制字符串之间的转换

在很多加密解密,以及中文字符串传输(比如表单提交)的时候,会用到16进制转换,就是Hex转换,为此Hutool中专门封装了HexUtil工具类,考虑到16进制转换也是转换的一部分,因此将其方法也放在Convert类中,便于理解和查找,使用同样非常简单:

// 普通字符串转为16进制字符串
String a = "我是一个小小的可爱的字符串";
//结果:"e68891e698afe4b880e4b8aae5b08fe5b08fe79a84e58fafe788b1e79a84e5ad97e7aca6e4b8b2"
String hex = Convert.toHex(a, CharsetUtil.CHARSET_UTF_8);
// 将16进制(Hex)字符串转为普通字符串
String hex = "e68891e698afe4b880e4b8aae5b08fe5b08fe79a84e58fafe788b1e79a84e5ad97e7aca6e4b8b2";
//结果为:"我是一个小小的可爱的字符串"
String raw = Convert.hexStrToStr(hex, CharsetUtil.CHARSET_UTF_8);

//注意:在4.1.11之后hexStrToStr将改名为hexToStr
String raw = Convert.hexToStr(hex, CharsetUtil.CHARSET_UTF_8);

因为字符串牵涉到编码问题,因此必须传入编码对象,此处使用UTF-8编码。 toHex方法同样支持传入byte[],同样也可以使用hexToBytes方法将16进制转为byte[]。

6. Unicode和字符串转换

与16进制类似,Convert类同样可以在字符串和Unicode之间轻松转换:

String a = "我是一个小小的可爱的字符串";

//结果为:"\\u6211\\u662f\\u4e00\\u4e2a\\u5c0f\\u5c0f\\u7684\\u53ef\\u7231\\u7684\\u5b57\\u7b26\\u4e32"    
String unicode = Convert.strToUnicode(a);

//结果为:"我是一个小小的可爱的字符串"
String raw = Convert.unicodeToStr(unicode);
7. 编码之间的转换

在接收表单的时候,我们常常被中文乱码所困扰,其实大多数原因是使用了不正确的编码方式解码了数据。于是Convert.convertCharset方法便派上用场了,它可以把乱码转为正确的编码方式:

String a = "我不是乱码";
//转换后result为乱码
// 将utf-8编码转为ISO_8859_1编码
String result = Convert.convertCharset(a, CharsetUtil.UTF_8, CharsetUtil.ISO_8859_1);
// 将ISO_8859_1编码转为utf-8编码
String raw = Convert.convertCharset(result, CharsetUtil.ISO_8859_1, "UTF-8");
Assert.assertEquals(raw, a);

注意 经过测试,UTF-8编码后用GBK解码再用GBK编码后用UTF-8解码会存在某些中文转换失败的问题。

8. 时间单位转换

Convert.convertTime方法主要用于转换时长单位,比如一个很大的毫秒,我想获得这个毫秒数对应多少分:

long a = 4535345;

//结果为:75
// 将毫秒转为秒
long minutes = Convert.convertTime(a, TimeUnit.MILLISECONDS, TimeUnit.MINUTES);
9. 金额大小写转换

面对财务类需求,Convert.digitToChinese将金钱数转换为大写形式:

double x = 123.13;
// 结果为:壹佰贰拾叁元壹角叁分
String s = Convert.digitToChinese(x);

注意 转换为大写只能精确到分(小数点儿后两位),之后的数字会被忽略。

10. 数字转换
  1. 数字转为英文表达

    // ONE HUNDRED AND TWENTY THREE ONLY
    String format = Convert.numberToWord(123);
    
  2. 数字简化

    // 1.2k
    String format1 = Convert.numberToSimple(1200, false);
    
  3. 数字转中文

    数字转中文方法中,只保留两位小数

    // 一万零八百八十九点七二
    String f1 = Convert.numberToChinese(10889.72356, false);
    
    // 使用金额大写
    // 壹万贰仟陆佰伍拾叁
    String f1 = Convert.numberToChinese(12653, true);
    
  4. 数字中文表示转换为数字

    // 1012
    String f1 = Convert.numberToChinese("一千零一十二");
    
11. 原始类和包装类转换

有的时候,我们需要将包装类和原始类相互转换(比如Integer.class 和 int.class),这时候我们可以:

//去包装
Class<?> wrapClass = Integer.class;

//结果为:int.class
Class<?> unWraped = Convert.unWrap(wrapClass);

//包装
Class<?> primitiveClass = long.class;

//结果为:Long.class
Class<?> wraped = Convert.wrap(primitiveClass);

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值