精华内容
下载资源
问答
  • Java作为编程语言中的NO.1,选择入行做IT做编程开发的人,基本都把它作为首选语言,进大厂拿高薪也是小伙伴们的梦想。 但很多小伙伴没有正确的学习方法与完整的知识体系图谱,很容易忽视一些Java基础知识,如Java...

    图片

    Java作为编程语言中的NO.1,选择入行做IT做编程开发的人,基本都把它作为首选语言,进大厂拿高薪也是小伙伴们的梦想。

    但很多小伙伴没有正确的学习方法与完整的知识体系图谱,容易忽视一些Java基础知识,如Java注解、IO流、反射机制等。地基没打牢,就容易导致学习的过程中容易进入误区,影响学习进度,到从入门到放弃......

    其实,理解Java反射机制的原理与作用,掌握IO流的使用并不难。

    对于Java基础掌握不牢固的小伙伴们,我们推出了C站软件工程师能力认证,帮助大家进行系统化学习,充分建立编码学习思维,扎实编码能力。

    我们提供免费训练,在训练过程中采用基于“明确路径+领取任务+刻意练习+小组学习+大咖指导”的学习模型,让大家实现面向实践、任务驱动、共同成长的目标。

    图片

    欢迎大家可以加入我们的学习小组一起学习!学好Java,打好基础,为进大厂做准备!

    点击链接(https://t.csdnimg.cn/tk6g来C认证模拟大赛完成测试,即可获取80篇点击破万,收藏过千的【Java技能】学习资料总结,包含语法基础、字符串、集合类型、异常处理、类与对象等知识点。

    部分资料展示:

    图片

    资料太多,无法一一截图,欢迎大家完成模拟考试后,扫码进入C认证考试福利群,资料会在每天下午5点进行更新~

    速速点击此链接来C认证模拟大赛测试一下!

    https://t.csdnimg.cn/tk6g

    完成后添加小龙女领取资料哟

     

    下图是C站(CSDN)软件工程师能力认证标准中的C1/C4-能力认证图分为基础能力和项目能力两大模块,可以看到模块中的技能点能够一线大厂开发工程师的招聘JD要求。 

    以上根据C认证核心知识点,系统整理CSDN点击破万,收藏过千的硬核干货文章合集,每日分享至群内,汇集成系统性百万知识库,帮助大家自主学习!

     二、Java好书免费领

    学习Java,书籍是必不可少的学习工具之一,尤其是对于自学者而言。今天给在校的小伙伴们带来学习Java必看的6本好书,非常全面。

    扫描海报二维码参与C认证模拟测试,即可领取含以下图书在内的CSDN电子书!考完后,电子书月卡会在3个月工作日内发放至您的账户。

    图片

    百万知识库等你领取!

    目前已梳理Java识库600篇、Python知识库600篇、前端知识库600篇,it软件工程师基础能力500篇,既包含小白+1的基础能力学习,也包含进大厂需要拥有的项目能力学习教程。知识库持续更新中,欢迎加入我们一起学习吧!

    C站知识库覆盖以下知识点,每日更新中,欢迎进群一起系统学习!

    图片

    图片

    图片

    图片

    部分资料预览:

    图片

    图片

    图片

     资料太多,无法一一截图,欢迎大家完成模拟考试后,扫码进入C认证考试福利群,资料会在每天下午5点进行更新~

    速速点击此链接来C认证模拟大赛测试一下!

    https://t.csdnimg.cn/tk6g

    完成后添加小龙女领取资料哟

     

     

    下图是C站(CSDN)软件工程师能力认证标准中的C1/C4-能力认证图分为基础能力和项目能力两大模块,可以看到模块中的技能点能够一线大厂开发工程师的招聘JD要求。

    通过以上,大家可以清晰地看到大厂招聘要求与能力认证一一对应、紧密相连。

    C认证企业奖学金计划为梦想加持,让努力发光。同时,C认证的成功离不开以下合作企业的赞助,感谢一路相伴~

    CSDN软件工程师能力认证(以下简称C系列认证)是由中国软件开发者网CSDN制定并推出的一个能力认证标准。C系列认证历经近一年的实际线下调研、考察、迭代、测试,并梳理出软件工程师开发过程中所需的各项技术技能,结合企业招聘需求和人才应聘痛点,基于公开、透明、公正的原则,甑别人才时确保真实业务场景、全部上机实操、所有过程留痕、存档不可篡改。

    C系列认证步骤

    1.打开官网(https://t.csdnimg.cn/tk6g),预约认证,报名成功。

    2.扫描下方二维码,进群领取学习资料和学习任务,群内还有任务直播讲解以及答疑,一起来记录自己的成长过程吧~

    预约后可进入C认证任务小组

    小组内有:

    1、C认证每阶段学习资料

    2、C认证每阶段实践任务,完成后还可收获合作企业赞助奖学金红包!

    3、任务直播讲解以及大咖答疑

    4、每天更新系统化的干货文章合集,汇集成系统性知识库,帮助大家自主学习

    快快添加小龙女,一起来记录自己的成长过程吧~

     

    展开全文
  • Java开发常用类库之Hutool

    万次阅读 多人点赞 2021-02-19 20:33:13
    Java 开发常用类库之Hutool

    本文的所有代码均已上传GitHub,HuTool学习

    学习交流q群:470464545,大家一起学习进步,CSDN博客:lolly1023

    文章目录

    简介与安装

    简介

    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。


    上述摘自HuTool官网

    安装

    在Maven项目中
    在项目的pom.xml的dependencies中加入以下内容:

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

    非Maven项目中
    点击以下任一链接,下载hutool-all-X.X.X.jar即可:

    注意 Hutool 5.x支持JDK8+,对Android平台没有测试,不能保证所有工具类或工具方法可用。 如果你的项目使用JDK7,请使用Hutool 4.x版本

    常用方法

    本文的所有代码均已上传GitHub,HuTool学习

    类型转换

    类型转换的工具类为Convert

    转为字符串

    		// int类型转换
    		int aInt = 1023;
    		String aStr = Convert.toStr(aInt);
    		// aStr结果为1023
    		System.out.println(aStr);
    		// 数组进行转换
    		int[] bArray = {1,2,3,4,5};
    		String bStr = Convert.toStr(bArray);
    		// bStr结果为[1, 2, 3, 4, 5]
    		System.out.println(bStr);
    

    转为指定类型数组

    		String[] strArray = { "1", "0", "2", "3" };
    		//结果为Integer数组
    		Integer[] intArray = Convert.toIntArray(strArray);
    		System.out.println(Convert.toStr(intArray));
    		
    		Integer[] intArray2 = {1,0,2,3};
    		//结果为String数组
    		String[] strArray2 = Convert.toStrArray(intArray2);
    		System.out.println(Convert.toStr(strArray2));
    

    转换为Date日期对象

    		String date = "2000-10-23";
    		//结果为Date日期对象
    		Date value = Convert.toDate(date);
    		System.out.println(value);
    

    转化为List集合

    		Object[] objectArray = {"lolly1023","lolly",1023};
    		List<?> list = Convert.convert(List.class, objectArray);
    		System.out.println(list);
    		// 4.1.11版本之后可使用toList
    		List<?> list2 = Convert.toList(objectArray);
    		System.out.println(list2);
    

    日期时间

    日期时间的工具类为DateUtil

    多种获取日期的方式

    		// 获取当前时间的Date对象
    		Date nowDate = DateUtil.date();
    		System.out.println(nowDate);
    		
    		// 使用Calendar获取当前时间的Date对象
    		Date nowDate2 = DateUtil.date(Calendar.getInstance());
    		System.out.println(nowDate2);
    		
    		// 使用当前时间戳获取当前时间的Date对象
    		Date nowDate3 = DateUtil.date(System.currentTimeMillis());
    		System.out.println(nowDate3);
    		
    		// 使用工具类获取当前时间的字符串,格式为:yyyy-MM-dd HH:mm:ss
    		String nowDateStr = DateUtil.now();
    		System.out.println(nowDateStr);
    		
    		// 使用工具类获取当前时间的字符串,格式为:yyyy-MM-dd
    		String todayDateStr= DateUtil.today();
    		System.out.println(todayDateStr);
    

    输出样式为:

    2021-02-19 21:04:12
    2021-02-19 21:04:12
    2021-02-19 21:04:12
    2021-02-19 21:04:12
    2021-02-19
    

    字符串转换为Date对象

    字符串转为Date对象使用到了DateUtil工具类中的parse方法,该方法会自动识别一些日期的常用格式,例如:

    1. yyyy-MM-dd HH:mm:ss.SSS
    2. yyyy-MM-dd HH:mm:ss
    3. yyyy-MM-dd HH:mm
    4. yyyy-MM-dd
    5. HH:mm:ss
    		// 字符串转为Date对象 
    		String dateStr = "2000-10-23 12:30";
    		Date date = DateUtil.parse(dateStr);
    		// 输出2000-10-23 12:30:00
    		System.out.println(date);
    		
    		// 也可以在转的时候指定格式
    		Date date2 = DateUtil.parse(dateStr,"yyyy-MM-dd");
    		// 输出2000-10-23 00:00:00
    		System.out.println(date2);
    

    格式化Date对象

    		//格式化Date日期对象
    		Date date4 = DateUtil.date();
    		
    		String format = DateUtil.format(date4, "yyyy年MM月dd日");
    		// 输出为2021年02月19日
    		System.out.println(format);
    		
    		String formatDate = DateUtil.formatDate(date4);
    		// 常用格式化,输出为2021-02-19
    		System.out.println(formatDate);
    		
    		String formatDateTime = DateUtil.formatDateTime(date4);
    		// 精确到秒,结果为2021-02-19 21:16:09
    		System.out.println(formatDateTime);
    		
    		String formatTime = DateUtil.formatTime(date4);
    		// 只保留时分秒,结果为21:16:09
    		System.out.println(formatTime);
    

    获取Date对象的年月日

    		// 获取Date对象的年月日
    		Date date5 = DateUtil.date();
    		// 获取年,结果为2021
    		System.out.println(DateUtil.year(date5));
    		// 获取月,结果为1(从0开始计数,0则为一月)
    		System.out.println(DateUtil.month(date5));
    		// 获取日(在本年)
    		System.out.println(DateUtil.dayOfYear(date5));
    		// 获取日(在本月)
    		System.out.println(DateUtil.dayOfMonth(date5));
    		// 获取日(在本周)
    		System.out.println(DateUtil.dayOfWeek(date5));
    

    开始和结束日期

    用于计算开始时间和结束时间,有每天的,每月的,等等

    		Date date3 = DateUtil.date();
    
    		//一天的开始,结果:2021-02-19 00:00:00
    		Date beginOfDay = DateUtil.beginOfDay(date3);
    		System.out.println(beginOfDay);
    		//一天的结束,结果:2021-02-19 23:59:59
    		Date endOfDay = DateUtil.endOfDay(date3);
    		System.out.println(endOfDay);
    		//一月的开始,结果:2021-02-01 00:00:00
    		Date beginOfMonth = DateUtil.beginOfMonth(date3);
    		System.out.println(beginOfMonth);
    		//一月的结束,结果:2021-02-28 23:59:59
    		Date endOfMonth = DateUtil.endOfMonth(date3);
    		System.out.println(endOfMonth);
    

    日期时间的偏移

    日期的减少或者添加,可以对时分秒天周月等进行更改

    		String dateStr2 = "2000-10-23 12:30";
    		Date date6 = DateUtil.parse(dateStr2);
    		
    		// 偏移10天
    		DateTime newDate = DateUtil.offsetDay(date, 10);
    		// 结果为2000-11-02 12:30:00
    		System.out.println(newDate);
    		// 偏移-10天
    		DateTime newDate2 = DateUtil.offsetDay(date, -10);
    		// 结果为2000-10-13 12:30:00
    		System.out.println(newDate2);
    		
    		/**常用的偏移还有
    		 * 月份 :DateUtil.offsetMonth(newDate2, offset)
    		 * 周:DateUtil.offsetWeek(newDate2, offset)
    		 */
    		
    		// 对比这种偏移,还有一种较简单的偏移方法
    		//昨天
    		System.out.println(DateUtil.yesterday());
    		//明天
    		System.out.println(DateUtil.tomorrow());
    		//上周
    		System.out.println(DateUtil.lastWeek());
    		//下周
    		System.out.println(DateUtil.nextWeek());
    		//上个月
    		System.out.println(DateUtil.lastMonth());
    		//下个月
    		System.out.println(DateUtil.nextMonth());
    

    日期时间差

    用于计算两个日期直接的时间差

    		String dateStr3 = "2000-10-23 12:30:00";
    		Date date7 = DateUtil.parse(dateStr3);
    
    		Date date8 = DateUtil.date();
    
    		// 计算2000-10-23距今多久:7424天
    		long betweenDay = DateUtil.between(date7, date8, DateUnit.DAY);
    		System.out.println(betweenDay);
    

    计时器

    		TimeInterval timer = DateUtil.timer();
    		
    		try {
    			// 模拟耗时操作
    			Thread.sleep(2000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		//花费毫秒数
    		System.out.println(timer.interval());
    		//返回花费时间,并重置开始时间
    		System.out.println(timer.intervalRestart());
    		//花费分钟数
    		System.out.println(timer.intervalMinute());
    

    星座与属相

    这个功能还是挺出乎意料的,没想到还有这种

    		// "天秤座"
    		String zodiac = DateUtil.getZodiac(Month.OCTOBER.getValue(), 23);
    		System.out.println(zodiac);
    		// "龙"
    		String chineseZodiac = DateUtil.getChineseZodiac(2000);
    		System.out.println(chineseZodiac);
    

    年龄与闰年判断

    不得不说,这个工具类小玩意还挺多

    		//年龄
    		System.out.println(DateUtil.ageOfNow("2000-10-23"));
    
    		//是否闰年
    		System.out.println(DateUtil.isLeapYear(2000));
    

    IO流相关

    文件的拷贝

    		// 文件的拷贝
    		BufferedInputStream in = FileUtil.getInputStream("d:/桌面/HuTool学习.md");
    		BufferedOutputStream out = FileUtil.getOutputStream("d:/桌面/HuTool学习复制.md");
    		long copySize = IoUtil.copy(in, out, IoUtil.DEFAULT_BUFFER_SIZE);
    		// 拷贝文件的大小
    		System.out.println(copySize);
    		System.out.println("拷贝成功");
    		in.close();
    		out.close();
    

    文件类型判断

    用于文件类型的判断,返回值为文件的类型

    		File file = FileUtil.file("d:/桌面/HuTool学习.md");
    		String type = FileTypeUtil.getType(file);
    		//输出的是文件的格式
    		Console.log(type);
    

    文件监听

    在以前,我们需要监听文件的变化:创建修改删除等,需要进行遍历来定时检查文件,效率很低,性能很差,所以有了这个工具类。
    监听指定事件

    		File file2 = FileUtil.file("example.properties");
    		//这里只监听文件或目录的修改事件
    		WatchMonitor watchMonitor = WatchMonitor.create(file2, WatchMonitor.ENTRY_MODIFY);
    		watchMonitor.setWatcher(new Watcher(){
    		    @Override
    		    public void onCreate(WatchEvent<?> event, Path currentPath) {
    		        Object obj = event.context();
    		        Console.log("创建:{}-> {}", currentPath, obj);
    		    }
    
    		    @Override
    		    public void onModify(WatchEvent<?> event, Path currentPath) {
    		        Object obj = event.context();
    		        Console.log("修改:{}-> {}", currentPath, obj);
    		    }
    
    		    @Override
    		    public void onDelete(WatchEvent<?> event, Path currentPath) {
    		        Object obj = event.context();
    		        Console.log("删除:{}-> {}", currentPath, obj);
    		    }
    
    		    @Override
    		    public void onOverflow(WatchEvent<?> event, Path currentPath) {
    		        Object obj = event.context();
    		        Console.log("Overflow:{}-> {}", currentPath, obj);
    		    }
    		});
    
    		//设置监听目录的最大深入,目录层级大于制定层级的变更将不被监听,默认只监听当前层级目录
    		watchMonitor.setMaxDepth(3);
    		//启动监听
    		watchMonitor.start();
    

    监听全部事件

    		WatchMonitor.createAll(file, new SimpleWatcher(){
    		    @Override
    		    public void onModify(WatchEvent<?> event, Path currentPath) {
    		        Console.log("EVENT modify");
    		    }
    		}).start();
    

    文件的读取

    		//默认UTF-8编码,可以在构造中传入第二个参数做为编码
    		FileReader fileReader = new FileReader("d:/桌面/HuTool测试.txt");
    		String result = fileReader.readString();
    		System.out.println(result);
    

    文件的写入

    		FileWriter writer = new FileWriter("d:/桌面/HuTool测	试.txt");
    		writer.write("添加文本",true);
    

    文件追加

    主要用于类似日志这种(此类只有在写入文件的时候打开文件,写入结束之后,此类不需要关闭

    		File file = new File("d:/桌面/HuTool测试.txt");
    		FileAppender appender = new FileAppender(file, 16, true);
    		appender.append("lolly1023");
    		appender.append("追加");
    		appender.append("成功");
    
    		appender.flush();
    		appender.toString();
    

    文件跟随

    有时候需要启动线程来“监控文件的变化,类似于Linux下的tail -f命令

    	Tailer tailer = new Tailer(FileUtil.file("d:/桌面/test.log"), Tailer.CONSOLE_HANDLER, 2);
    	tailer.start();
    

    实时打印文件变化的类

    /**
     * 命令行打印的行处理器
     * 
     * @author looly
     * @since 4.5.2
     */
    public static class ConsoleLineHandler implements LineHandler {
        @Override
        public void handle(String line) {
            Console.log(line);
        }
    }
    

    该方法会阻塞线程

    文件名与扩展名

    获取文件名

    		File file = FileUtil.file("d:/桌面/HuTool学习.md");
    
    		// HuTool学习.md
    		String name = FileNameUtil.getName(file);
    		System.out.println(name);
    

    单独获取主文件名扩展名

    		File file1 = FileUtil.file("d:/桌面/HuTool学习.md");
    
    		// "HuTool学习"
    		String name1 = FileNameUtil.mainName(file1);
    		System.out.println(name1);
    		// "md"
    		String name2 = FileNameUtil.extName(file1);
    		System.out.println(name2);
    

    工具类

    字符串工具

    判断是否为空

    给定指定字符串,如果是空,则返回true,使用到hasBlankhasEmpty方法。hasEmpty只判断是否为null或者是空字符串,hasBlank会把不可见的字符也算为空。

    		String nullStr = null;
    		// true
    		System.out.println(StrUtil.hasBlank(nullStr));
    		// true
    		System.out.println(StrUtil.hasEmpty(nullStr));
    

    删除前后缀

    removePrefix为删除字符串前缀,removeSuffix为删除字符串后缀,经常用于去文件扩展名。

    		String fileName = StrUtil.removeSuffix("HuTool学习.md", ".md"); 
    		// HuTool学习
    		System.out.println(fileName);
    		String fileName1 = StrUtil.removePrefix("HuTool学习.md", "HuTool学习."); 
    		// md
    		System.out.println(fileName1);
    

    截取字符串

    String中就有截取字符串的方法,但是时常会越界,在这个工具类中,该方法会自动判断,支持负数,(与python相同),第二个位置与第一个位置搞反了的话,也会自动识别更改。

    		String str = "lolly1023";
    		
    		String strSub1 = StrUtil.sub(str, 0, 5); 
    		// lolly
    		System.out.println(strSub1);
    		String strSub2 = StrUtil.sub(str, 0, -4);
    		// lolly
    		System.out.println(strSub2);
    		String strSub3 = StrUtil.sub(str, 5, 0);
    		// lolly
    		System.out.println(strSub3);
    

    格式化字符串

    使用{}进行占位即可,然后使用format方法进行格式化

    		// 使用{}占位
    		String template = "{}+{}=2";
    		// 1+1=2
    		String str1 = StrUtil.format(template, "1", "1"); 
    		System.out.println(str1);
    

    16进制工具

    16进制的转换

    		String str = "测试16进制转换";
    
    		String hex = HexUtil.encodeHexStr(str, CharsetUtil.CHARSET_UTF_8);
    		// e6b58be8af953136e8bf9be588b6e8bdace68da2
    		System.out.println(hex);
    
    		String decodedStr = HexUtil.decodeHexStr(hex);
    		// 测试16进制转换,解码后与str相同
    		System.out.println(decodedStr);
    

    URL工具

    标准化URL链接

    对于不带http://头的地址做简单补全。

    		String url = "http://www.hutool.cn//aaa/bbb";
    		// 结果为:http://www.hutool.cn/aaa/bbb
    		String normalize = URLUtil.normalize(url);
    		System.out.println(normalize);
    		url = "http://www.hutool.cn//aaa/\\bbb?a=1&b=2";
    		// 结果为:http://www.hutool.cn/aaa/bbb?a=1&b=2
    		normalize = URLUtil.normalize(url);
    		System.out.println(normalize);
    

    XML工具

    读取XML

    读取XML分为两个方法:

    • XmlUtil.readXML 读取XML文件
    • XmlUtil.parseXml 解析XML字符串为Document对象

    写XML

    • XmlUtil.toStr 将XML文档转换为String
    • XmlUtil.toFile 将XML文档写入到文件

    创建XML

    • XmlUtil.createXml 创建XML文档, 创建的XML默认是utf8编码,修改编码的过程是在toStr和toFile方法里,既XML在转为文本的时候才定义编码。

    XML操作

    通过以下工具方法,可以完成基本的节点读取操作。

    • XmlUtil.cleanInvalid 除XML文本中的无效字符
    • XmlUtil.getElements 根据节点名获得子节点列表
    • XmlUtil.getElement 根据节点名获得第一个子节点
    • XmlUtil.elementText 根据节点名获得第一个子节点
    • XmlUtil.transElements 将NodeList转换为Element列表

    XML与对象转换

    • writeObjectAsXml 将可序列化的对象转换为XML写入文件,已经存在的文件将被覆盖。
    • readObjectFromXml 从XML中读取对象。

    注意 这两个方法严重依赖JDK的XMLEncoderXMLDecoder,生成和解析必须成对存在(遵循固定格式),普通的XML转Bean会报错。

    Xpath操作

    更多Xpath操作:点击此处
    举例xml文件

    <?xml version="1.0" encoding="utf-8"?>
    
    <returnsms> 
      <returnstatus>Success(成功)</returnstatus>  
      <message>ok</message>  
      <remainpoint>1490</remainpoint>  
      <taskID>885</taskID>  
      <successCounts>1</successCounts> 
    </returnsms>
    

    java代码

    		File xmlFile = new File("/Study/HuToolTest/src/main/java/com/rj/bd/HuToolTest/UTilTest/URLUtil/Test.xml");
    		Document docResult=XmlUtil.readXML(xmlFile);
    		Object value = XmlUtil.getByXPath("//returnsms/message", docResult, XPathConstants.STRING);
    		// ok
    		System.out.println(value.toString());
    

    对象工具

    两个对象是否相等

    需要满足:

    1. obj1 == null && obj2 == null
    2. obj1.equals(obj2)

    才会返回true

    		String string1 = "1";
    		Integer integer1 = 1;
    		// false
    		System.out.println(ObjectUtil.equal(string1, integer1));
    

    计算对象长度

    其实本质就是调用不同对象的计算长度方法,支持的类型有:

    • CharSequence
    • Collection
    • Map
    • Iterator
    • Enumeration
    • Array
    		List<Integer> list = new ArrayList<Integer>();
    		// 0
    		System.out.println(ObjectUtil.length(list));
    

    判断是否包含元素

    即为判断对象中是否包含元素

    		List<Integer> list1 = new ArrayList<Integer>();
    		list1.add(0);
    		// true
    		System.out.println(ObjectUtil.contains(list1, 0));
    

    判断是否为空

    		List<Integer> list2 = new ArrayList<Integer>();
    		// false
    		System.out.println(ObjectUtil.isNull(list2));
    		// true
    		System.out.println(ObjectUtil.isNotNull(list2));
    

    克隆

    • ObjectUtil.clone克隆对象,如果对象实现Cloneable接口,调用其clone方法,如果实现Serializable接口,执行深度克隆,否则返回null

    • ObjectUtil.cloneIfPossible 返回克隆后的对象,如果克隆失败,返回原对象

    • ObjectUtil.cloneByStream 序列化后拷贝流的方式克隆,对象必须实现Serializable接口

    序列化与反序列化

    • serialize 序列化,调用JDK序列化
    • unserialize 反序列化,调用JDK

    判断基本类型

    如果该对象是基本类型,则返回true,反之返回false。

    		int i = 0;
    		// true
    		System.out.println(ObjectUtil.isBasicType(i));
    

    反射

    获取某类的全部方法

    		// 获取类中的全部方法
    		Method[] methods = ReflectUtil.getMethods(Test.class);
    

    获取某类的某个方法

    		// 获取类中的某个方法
    		Method method = ReflectUtil.getMethod(Test.class, "getID");
    

    获取某类的构造方法

    		// 获取某类的构造方法
    		ReflectUtil.newInstance(Test.class);
    

    执行方法

    public class TestClass {
    	public String print(String string) {
    		return string;
    	}
    }	
    

    测试类

    		TestClass testClass = new TestClass();
    		// lolly1023
    		ReflectUtil.invoke(testClass, "print", "lolly1023");
    

    剪切板工具

    获取剪切板内容及修改剪切板内容

    		// 获取系统剪切板内容
    		Clipboard copy = ClipboardUtil.getClipboard();
    		// 设置剪切板内容,图片的话使用setImage
    		ClipboardUtil.setStr("123");
    		// 获取剪切板内容:123,图片的话使用getImage
    		System.out.println(ClipboardUtil.getStr());
    

    命令行工具

    通过Java代码执行命令行命令,在Wubdows下是cmd,在Linux下是shell命令

    执行命令

    		// cmd下输入ipconfig为网卡信息
    		String str = RuntimeUtil.execForStr("ipconfig");
    		// 输出正常,为网卡信息
    		System.out.println(str);
    

    数字工具

    加减乘除

    • NumberUtil.add 针对double类型做加法
    • NumberUtil.sub 针对double类型做减法
    • NumberUtil.mul 针对double类型做乘法
    • NumberUtil.div 针对double类型做除法,并提供重载方法用于规定除不尽的情况下保留小数位数和舍弃方式。

    以上的方法都会将double转为BigDecimal,解决了精确问题。

    保留小数

    		double te1=123456.123456;
    		double te2=123456.123456;
    		// 第二个参数为保留几位小数
    		// 123456.1
    		Console.log(NumberUtil.round(te1,1));
    		// 123456.123
    		Console.log(NumberUtil.round(te2,3));
    

    四舍五入

    		double te3=123456.123456;
    		double te4=123456.128456;
    		// 第二个参数为保留几位小数
    		//123456.12
    		Console.log(NumberUtil.roundStr(te3,2));
    		//123456.13
    		Console.log(NumberUtil.roundStr(te4,2));
    

    格式化

    		long c=299792458;//光速
    		String format = NumberUtil.decimalFormat(",###", c);//299,792,458
    		System.out.println(format);
    

    常用的格式化方式

    • 0 -> 取一位整数
    • 0.00 -> 取一位整数和两位小数
    • 00.000 -> 取两位整数和三位小数
    • # -> 取所有整数部分
    • #.##% -> 以百分比方式计数,并取两位小数
    • #.#####E0 -> 显示为科学计数法,并取五位小数
    • ,### -> 每三位以逗号进行分隔,例如:299,792,458
    • 光速大小为每秒,###米 -> 将格式嵌入文本

    更多格式化操作,点击处此

    是否为数字

    • NumberUtil.isNumber 是否为数字
    • NumberUtil.isInteger 是否为整数
    • NumberUtil.isDouble 是否为浮点数
    • NumberUtil.isPrimes 是否为质数

    随机数

    第一个参数为最小值,第二个参数为最大值,第三个参数为长度。

    		// 生成随机数,用int类型数组承载
    		int[] array = NumberUtil.generateRandomNumber(0, 10, 8);
    		System.out.println(Convert.toStr(array));
    		// 生成随机数,用Integer类型数组承载
    		Integer[] array2 = NumberUtil.generateBySet(0, 10, 8);
    		System.out.println(Convert.toStr(array2));
    

    有序整数列表

    生成一个有序的int类型数组

    		// 第一个参数为起点,第二个参数为终点
    		int[] array3 = NumberUtil.range(2, 5);
    		// [2, 3, 4, 5]
    		System.out.println(Convert.toStr(array3));
    

    其它

    • NumberUtil.factorial 阶乘
    • NumberUtil.sqrt 平方根
    • NumberUtil.divisor 最大公约数
    • NumberUtil.multiple 最小公倍数
    • NumberUtil.getBinaryStr 获得数字对应的二进制字符串
    • NumberUtil.binaryToInt 二进制转int
    • NumberUtil.binaryToLong 二进制转long
    • NumberUtil.compare 比较两个值的大小
    • NumberUtil.toStr 数字转字符串,自动并去除尾小数点儿后多余的0

    数组工具

    判断是否为空

    		int[] a = {};
    		int[] b = null;
    		// 判断空
    		// true
    		System.out.println(ArrayUtil.isEmpty(a));
    		// true
    		System.out.println(ArrayUtil.isEmpty(b));
    		
    		//判断非空
    		// false
    		System.out.println(ArrayUtil.isNotEmpty(a));
    

    新建泛型数组

    该方法支持泛型返回值

    		String[] newArray = ArrayUtil.newArray(String.class, 3);
    

    调整大小

    		ArrayUtil.resize(newArray, 4);
    

    合并数组

    		int[] c = {1,2,3};
    		int[] d = {4,5,6};
    		int[] e = ArrayUtil.addAll(c,d);
    		// [1, 2, 3, 4, 5, 6]
    		System.out.println(Convert.toStr(e));
    

    克隆

    1. 泛型数组调用原生克隆
    		Integer[] b = {1,2,3};
    		Integer[] cloneB = ArrayUtil.clone(b);
    		Assert.assertArrayEquals(b, cloneB);
    
    1. 非泛型数组(原始类型数组)调用第二种重载方法
    	int[] a = {1,2,3};
    	int[] clone = ArrayUtil.clone(a);
    	Assert.assertArrayEquals(a, clone);
    

    有序列表生成

    		int[] array = ArrayUtil.range(0,10);
    		// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    		System.out.println(Convert.toStr(array));
    

    拆分数组

    		byte[] array2 = {1,1,1,1,2,2,2,2};
    		byte[][] array3 = ArrayUtil.split(array2, 4);
    		// [[1, 1, 1, 1], [2, 2, 2, 2]]
    		System.out.println(Convert.toStr(array3));
    

    过滤

    举例,过滤数组,保留偶数

    		Integer[] a = {1,2,3,4,5,6};
    		Integer[] filter = ArrayUtil.filter(a, new 		Editor<Integer>(){
       		@Override
        	public Integer edit(Integer t) {
           	return (t % 2 == 0) ? t : null;
        	}});
    		Assert.assertArrayEquals(filter, new Integer[]{2,4,6});
    

    两个数组生成map

    此方法在python中为zip()函数。
    第一个数组为key,第二个数组对应为value

    		String[] keys = {"w", "e", "r", "f"};
    		Integer[] values = {1,0,2,3};
    		Map<String, Integer> map = ArrayUtil.zip(keys, values, true);
    		// {w=1, e=0, r=2, f=3}
    		System.out.println(Convert.toStr(map));
    

    是否包含元素

    		int[] f = {1,2,3};
    		// true
    		System.out.println(ArrayUtil.contains(f, 3));
    

    判断对象是否为数组

    		int[] g = {1,2,3};
    		int h = 1;
    		// true
    		System.out.println(ArrayUtil.isArray(g));
    		// false
    		System.out.println(ArrayUtil.isArray(h));
    

    转为字符串

    		int[] i = {1,2,3};
    		// [1, 2, 3]
    		System.out.println(ArrayUtil.toString(i));
    		// 第二个参数为间隔符, 1/2/3
    		System.out.println(ArrayUtil.join(i, "/"));
    

    随机工具

    基本使用

    • RandomUtil.randomInt 获得指定范围内的随机数
    • RandomUtil.randomBytes 随机bytes
    • RandomUtil.randomEle 随机获得列表中的元素
    • RandomUtil.randomEleSet 随机获得列表中的一定量的不重复元素,返回Set
    • RandomUtil.randomString 获得一个随机的字符串(只包含数字和字符)
    • RandomUtil.randomNumbers 获得一个只包含数字的字符串
    • RandomUtil.randomUUID 随机UUID
    • RandomUtil.weightRandom 权重随机生成器,传入带权重的对象,然后根据权重随机获取对象

    唯一ID工具

    UUID

    UUID全称通用唯一识别码(universally unique identifier)

    		//生成的UUID是带-的字符串
    		String uuid = IdUtil.randomUUID();
    		System.out.println(uuid);
    		//生成的是不带-的字符串
    		String simpleUUID = IdUtil.simpleUUID();
    		System.out.println(simpleUUID);
    

    ObjectId

    ObjectId是MongoDB数据库的一种唯一ID生成策略,是UUID version1的变种。

    		//生成id
    		String id = ObjectId.next();
    		System.out.println(id);
    		//方法2:从Hutool-4.1.14开始提供
    		String id2 = IdUtil.objectId();
    		System.out.println(id2);
    

    Snowflake

    分布式系统中,有一些需要使用全局唯一ID的场景,有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。Twitter的Snowflake 算法就是这种生成器。

    		//参数1为终端ID
    		//参数2为数据中心ID
    		Snowflake snowflake = IdUtil.getSnowflake(1, 1);
    		long id3 = snowflake.nextId();
    		System.out.println(id3);
    

    压缩工具

    压缩

    打包到当前目录

    		//将aaa目录下的所有文件目录打包到d:/aaa.zip
    		ZipUtil.zip("d:/aaa");
    

    打包到指定目录

    		//将aaa目录下的所有文件目录打包到d:/bbb/目录下的aaa.zip文件中
    		// 此处第二个参数必须为文件,不能为目录
    		ZipUtil.zip("d:/aaa", "d:/bbb/aaa.zip");
    
    		//将aaa目录下的所有文件目录打包到d:/bbb/目录下的ccc.zip文件中
    		ZipUtil.zip("d:/aaa", "d:/bbb/ccc.zip");
    

    多个文件进行打包

    		ZipUtil.zip(FileUtil.file("d:/bbb/ccc.zip"), false, 
    		FileUtil.file("d:/test1/file1.txt"),
     		FileUtil.file("d:/test1/file2.txt"),
      		FileUtil.file("d:/test2/file1.txt"),
      	    FileUtil.file("d:/test2/file2.txt")
    		);
    

    解压

    		//将test.zip解压到e:\\aaa目录下,返回解压到的目录
    		File unzip = ZipUtil.unzip("E:\\aaa\\test.zip", "e:\\aaa");
    

    身份证工具

    主要方法为:

    • isValidCard 验证身份证是否合法
    • convert15To18 身份证15位转18位
    • getBirthByIdCard 获取生日
    • getAgeByIdCard 获取年龄
    • getYearByIdCard 获取生日年
    • getMonthByIdCard 获取生日月
    • getDayByIdCard 获取生日天
    • getGenderByIdCard 获取性别
    • getProvinceByIdCard 获取省份

    简单使用

    		String ID_18 = "321083197812162119";
    		String ID_15 = "150102880730303";
    
    		//是否有效
    		boolean valid = IdcardUtil.isValidCard(ID_18);
    		boolean valid15 = IdcardUtil.isValidCard(ID_15);
    
    		//转换
    		String convert15To18 = IdcardUtil.convert15To18(ID_15);
    		Assert.assertEquals(convert15To18, "150102198807303035");
    
    		//年龄
    		DateTime date = DateUtil.parse("2017-04-10");
            
    		int age = IdcardUtil.getAgeByIdCard(ID_18, date);
    		Assert.assertEquals(age, 38);
    
    		int age2 = IdcardUtil.getAgeByIdCard(ID_15, date);
    		Assert.assertEquals(age2, 28);
    
    		//生日
    		String birth = IdcardUtil.getBirthByIdCard(ID_18);
    		Assert.assertEquals(birth, "19781216");
    
    		String birth2 = IdcardUtil.getBirthByIdCard(ID_15);
    		Assert.assertEquals(birth2, "19880730");
    
    		//省份
    		String province = IdcardUtil.getProvinceByIdCard(ID_18);
    		Assert.assertEquals(province, "江苏");
    
    		String province2 = IdcardUtil.getProvinceByIdCard(ID_15);
    		Assert.assertEquals(province2, "内蒙古");
    

    声明本次数据摘自HuTool官网,为随即编造,如有雷同,纯属巧合。

    集合类

    集合工具

    转为字符串

    第二个参数为连接符

    		String[] col= new String[]{"l","o","l","l","y"};
    		List<String> colList = CollUtil.newArrayList(col);
    
    		String str = CollUtil.join(colList, "#"); 
    		// l#o#l#l#y
    		System.out.println(str);
    

    分页

    		//Integer比较器
    		Comparator<Integer> comparator = new Comparator<Integer>(){
    		    @Override
    		    public int compare(Integer o1, Integer o2) {
    		        return o1.compareTo(o2);
    		    }
    		};
    
    		//新建三个列表,CollUtil.newArrayList方法表示新建ArrayList并填充元素
    		List<Integer> list1 = CollUtil.newArrayList(1, 2, 3);
    		List<Integer> list2 = CollUtil.newArrayList(4, 5, 6);
    		List<Integer> list3 = CollUtil.newArrayList(7, 8, 9);
    
    		//参数表示把list1,list2,list3合并并按照从小到大排序后,取0~2个(包括第0个,不包括第2个),结果是[1,2]
    		@SuppressWarnings("unchecked")
    		List<Integer> result = CollUtil.sortPageAll(0, 2, comparator, list1, list2, list3);
    		System.out.println(result);     //输出 [1,2]
    

    可能接触时间有点少,没读太懂,直接略过了。

    创建容器

    	HashMap<String, String> map = CollUtil.newHashMap();
    	HashSet<String> set = CollUtil.newHashSet();
    	ArrayList<String> list = CollUtil.newArrayList();
    

    添加元素

    		CollUtil.setOrAppend(list, 0, "1");
    		System.out.println(list);
    

    调整数据大小

    		List<String> list5 = CollUtil.reverse(list);
    

    没有搞懂改变List大小有啥用。。。,希望有会的指点一下

    合并数组

    		List<String> list4 = new ArrayList<>();
    		List<String> list6 = new ArrayList<>();
    		list4.add("lolly");
    		list6.add("lolly1023");
     		CollUtil.addAll(list4, list6);
     		// [lolly, lolly1023]
    		System.out.println(list4);
    

    截取数组

    		// [lolly]
    		System.out.println(CollUtil.sub(list4, 0, 1));
    

    判断是否为空

    		// false
    		System.out.println(CollUtil.isEmpty(list4));
    		// true
    		System.out.println(CollUtil.isNotEmpty(list4));
    

    集合生成Map

    源自python语法糖

    		Collection<String> keys = CollUtil.newArrayList("a", "b", "c", "d");
    		Collection<Integer> values = CollUtil.newArrayList(1, 2, 3, 4);
    
    		// {a=1,b=2,c=3,d=4}
    		Map<String, Integer> map = CollUtil.zip(keys, values);
    

    过滤方法

    此方法可以过滤掉map中不需要的key
    举例:

    		@Test
    		public void CollUtil_Filter() {
        		Map<String, Object> m = new HashMap<String, Object>() {{
            		put("k1", "v1");
            		put("k2", "v2");
            		put("k3", "v3");
        		}};
        		String[] inc = {"k1", "k3"};//需要的key
        		List<String> incList = Arrays.asList(inc);
        		m = CollectionUtil.filter(m, new Editor<Map.Entry<String, Object>>() {
            		@Override
            		public Map.Entry<String, Object> edit(Map.Entry<String, Object> stringObjectEntry) {
                		if (incList.contains(stringObjectEntry.getKey())) {
                    		return stringObjectEntry;
                		}
                		return null;
            		}
        		});
        		log.info("{}", m);
    		}
    

    控制台输出

    {k3=v3, k1=v1}
    

    列表工具

    过滤列表

    对每一个元素进行过滤

    		List<String> a = ListUtil.toLinkedList("1", "2", "3");
    		// 结果: [edit1, edit2, edit3]
    		List<String> filter = ListUtil.filter(a, str -> "edit" + str);
    

    获取满足规则元素下标

    		List<String> a = ListUtil.toLinkedList("1", "2", "3", "4", "3", "2", "1");
    		// [1, 5]
    		int[] indexArray = ListUtil.indexOfAll(a, "2"::equals);
    

    Iterator工具

    基本方法

    • isEmpty 是否为null或者无元素
    • isNotEmpty 是否为非null或者至少一个元素
    • hasNull 是否有null元素
    • isAllNull 是否全部为null元素
    • countMap 根据集合返回一个元素计数的Map,所谓元素计数就是假如这个集合中某个元素出现了n次,那将这个元素做为key,n做为value
    • join 使用分隔符将集合转换为字符串
    • toMap toMap Entry列表转Map,或者key和value单独列表转Map
    • asIterator EnumerationIterator
    • asIterable IteratorIterable
    • getFirst 获取列表的第一个元素
    • getElementType 获取元素类型

    Map

    Map工具

    行转列

    如若map中的数据为:

    [
      {a: 1, b: 1, c: 1},
      {a: 2, b: 2},
      {a: 3, b: 3},
      {a: 4}
    ]
    

    则使用toListMap之后变为:

    {
       a: [1,2,3,4],
       b: [1,2,3,],
       c: [1]
    }
    

    列转行

    如若map中的数据为:

    {
       a: [1,2,3,4],
       b: [1,2,3,],
       c: [1]
    }
    

    则使用toMapList之后变为:

    [
      {a: 1, b: 1, c: 1},
      {a: 2, b: 2},
      {a: 3, b: 3},
      {a: 4}
    ]
    

    转为字符串

    joinjoinIgnoreNullsortJoin将Map按照给定的分隔符转换为字符串,此方法一般用于签名。

    Map<String, String> build = MapUtil.builder(new HashMap<String, String>())
        .put("key1", "value1")
        .put("key3", "value3")
        .put("key2", "value2").build();
    
    // key1value1key2value2key3value3
    String join1 = MapUtil.sortJoin(build, StrUtil.EMPTY, StrUtil.EMPTY, false);
    // key1value1key2value2key3value3123
    String join2 = MapUtil.sortJoin(build, StrUtil.EMPTY, StrUtil.EMPTY, false, "123");
    

    过滤方法

    举例:

    Map<String, String> map = MapUtil.newHashMap();
    map.put("a", "1");
    map.put("b", "2");
    map.put("c", "3");
    map.put("d", "4");
    
    Map<String, String> map2 = MapUtil.filter(map, (Filter<Entry<String, String>>) t -> Convert.toIn(t.getValue()) % 2 == 0);
    

    结果为:

    {
       b: "2",
       d: "4"
    }
    

    key和value互换

    举例:

    Map<String, String> map = MapUtil.newHashMap();
            map.put("a", "1");
            map.put("b", "2");
            map.put("c", "3");
            map.put("d", "4");
    
    Map<String, String> map2 = MapUtil.reverse(map);
    

    结果为:

    {
       "1": "a",
       "2": "b",
       "3": "c",
       "4": "d",
    }
    

    BiMap

    BiMap,它实现了一种双向查找的功能,即根据key查找value和根据value查找key,Hutool也同样提供此对象。

    基本使用

    BiMap<String, Integer> biMap = new BiMap<>(new HashMap<>());
    biMap.put("aaa", 111);
    biMap.put("bbb", 222);
    
    // 111
    biMap.get("aaa");
    // 222
    biMap.get("bbb");
    
    // aaa
    biMap.getKey(111);
    // bbb
    biMap.getKey(222);
    

    TableMap

    TableMap这类数据结构,通过键值单独建立List方式,使键值对一一对应,实现正向和反向两种查找。

    基本使用

    TableMap<String, Integer> tableMap = new TableMap<>(new HashMap<>());
    tableMap.put("aaa", 111);
    tableMap.put("bbb", 222);
    
    // 111
    tableMap.get("aaa");
    // 222
    tableMap.get("bbb");
    
    // aaa
    tableMap.getKey(111);
    // bbb
    tableMap.getKey(222);
    
    // [111]
    tableMap.getValues("aaa");
    
    //[aaa]
    tableMap.getKeys(111);
    

    Codec编码

    Base62编码解码

    		String a = "Base62";
    
    		// KixpUr22
    		String encode = Base62.encode(a);
    		System.out.println(encode);
    		// 还原为Base62
    		String decodeStr = Base62.decodeStr(encode);
    		System.out.println(decodeStr);
    

    Base64编码解码

    		String a = "Base64";
    
    		// QmFzZTY0
    		String encode = Base64.encode(a);
    		System.out.println(encode);
    		// 还原为Base64
    		String decodeStr = Base64.decodeStr(encode);
    		System.out.println(decodeStr);
    

    Base32编码解码

    		String a = "Base32";
    
    		// IJQXGZJTGI
    		String encode = Base32.encode(a);
    		System.out.println(encode);
    		// 还原为Base32
    		String decodeStr = Base32.decodeStr(encode);
    		System.out.println(decodeStr);
    

    文本操作

    StrBuilder

    在JDK提供的StringBuilder中,拼接字符串变得更加高效和灵活,但是生成新的字符串需要重新构建StringBuilder对象,造成性能损耗和内存浪费,因此Hutool提供了可复用的StrBuilder。

    摘自HuTool官网

    基本使用

    		StrBuilder builder = StrBuilder.create();
    		builder.append("lolly").append("1023").append('!');
    		// lolly1023!
    		System.out.println(builder);
    

    对比StringBuilder来说,性能几乎提升一倍之高。

    Unicode编码转换工具

    字符串转Unicode符

    		//第二个参数true表示跳过ASCII字符(只跳过可见字符)
    		String s = UnicodeUtil.toUnicode("lolly1023中文", true);
    		// lolly1023\u4e2d\u6587
    		System.out.println(s);
    

    Unicode转字符串

    		String str = "lolly1023\u4e2d\u6587";
    		String res = UnicodeUtil.toString(str);
    		// lolly1023中文
    		System.out.println(res);
    

    比较器

    版本比较器

    		// 1.2.1 < 1.12.1,返回-1
    		System.out.println(VersionComparator.INSTANCE.compare("1.2.1", "1.12.1"));
    
    		// 1.12.1 < 1.12.1c,返回-1
    		System.out.println(VersionComparator.INSTANCE.compare("1.12.1", "1.12.1c"));
    
    		// V0.0.20170102 > V0.0.20170101,返回1
    		System.out.println(VersionComparator.INSTANCE.compare("V0.0.20170102", "V0.0.20170101"));
    

    其它比较器

    • ReverseComparator 反转比较器,排序时提供反序
    • VersionComparator 版本比较器,支持如:1.3.20.8,6.82.20160101,8.5a/8.5c等版本形式
    • PropertyComparator Bean属性比较器,通过Bean的某个属性来对Bean对象进行排序
    • IndexedComparator 按照数组的顺序正序排列,数组的元素位置决定了对象的排序先后
    • ComparatorChain 比较器链。此链包装了多个比较器,最终比较结果按照比较器顺序综合多个比较器结果。
    • PinyinComparator 按照GBK拼音顺序对给定的汉字字符串排序。

    异常

    基本方法

    • getMessage 获得完整消息,包括异常名
    • wrap 包装一个异常为指定类型异常
    • wrapRuntime 使用运行时异常包装编译异常
    • getCausedBy 获取由指定异常类引起的异常
    • isCausedBy 判断是否由指定异常类引起
    • stacktraceToString 堆栈转为完整字符串

    其他方法请参考API文档:API文档

    其它异常封装

    • DependencyException 依赖异常
    • StatefulException 带有状态码的异常
    • UtilException 工具类异常
    • NotInitedException 未初始化异常
    • ValidateException 验证异常

    图片

    图片工具

    缩放图片

    		ImgUtil.scale(
    				FileUtil.file("d:/桌面/石原里美.jpg"), 
    				FileUtil.file("d:/桌面/石原里美缩小版.jpg"),
    				0.5f// 缩放比例
    		);
    

    剪裁图片

    		ImgUtil.cut(
    			    FileUtil.file("d:/桌面/石原里美.jpg"), 
    			    FileUtil.file("d:/桌面/石原里美剪裁版.jpg"), 
    			    new Rectangle(200, 200, 200, 200)//裁剪的矩形区域
    		);
    

    分成行列剪裁

    		ImgUtil.slice(
    				FileUtil.file("d:/桌面/石原里美.jpg"), 
    				FileUtil.file("d:/桌面/石原里美"),
    				2, 
    				2
    		);
    

    图片类型转换

    		ImgUtil.convert(
    				FileUtil.file("d:/桌面/石原里美.jpg"), 
    				FileUtil.file("d:/桌面/石原里美.png")
    		);
    

    图片转为黑白

    		ImgUtil.gray(
    				FileUtil.file("d:/桌面/石原里美.jpg"), 
    				FileUtil.file("d:/桌面/石原里美黑白版.jpg")
    		);
    

    添加文字水印

    		ImgUtil.pressText(//
    			    FileUtil.file("d:/桌面/石原里美.jpg"), //
    			    FileUtil.file("d:/桌面/石原里美水印版.jpg"), //
    			    "lolly1023", Color.WHITE, //文字
    			    new Font("黑体", Font.BOLD, 100), //字体
    			    0, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
    			    0, //y坐标修正值。 默认在中间,偏移量相对于中间偏移
    			    0.8f//透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
    		);
    

    添加图片水印

    		ImgUtil.pressImage(
    			    FileUtil.file("d:/桌面/石原里美.jpg"), 
    			    FileUtil.file("d:/桌面/石原里美图片水印版.jpg"), 
    			    ImgUtil.read(FileUtil.file("d:/桌面/石原里美.jpg")), //水印图片
    			    0, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
    			    0, //y坐标修正值。 默认在中间,偏移量相对于中间偏移
    			    0.1f
    		);
    

    旋转图片

    		// 旋转180度
    		BufferedImage image = (BufferedImage) ImgUtil.rotate(ImageIO.read(FileUtil.file("d:/桌面/石原里美.jpg")), 180);
    		ImgUtil.write(image, FileUtil.file("d:/桌面/石原里美旋转版.jpg"));
    

    水平翻转图片

    	ImgUtil.flip(
    				FileUtil.file("d:/桌面/石原里美.jpg"), 
    				FileUtil.file("d:/桌面/石原里美翻转版.jpg")
    		);
    

    图片编辑器

    图像切割

    		Img.from(
    				FileUtil.file("d:/桌面/石原里美.jpg"))
    	    		.cut(0, 0, 200)//
    	    		.write(FileUtil.file("d:/桌面/石原里美切割版.jpg")
    	    );
    

    图片压缩

    图片压缩只支持jpg文件

    		Img.from(
    				FileUtil.file("d:/桌面/石原里美.jpg"))
    	    		.setQuality(0.5)//压缩比率
    	    		.write(FileUtil.file("d:/桌面/石原里美压缩版.jpg")
    	    );
    

    HuTool暂未学完,持续更新

    本文的所有代码均已上传GitHub,HuTool学习

    学习交流q群:470464545,大家一起学习进步,CSDN博客:lolly1023

    展开全文
  • 前言 Java 平台自出现到目前为止,已经 20 多个年头了,这 20 多年间 Java 也一直作为最流行的程序设计语言之一,不断面临...但是也因为这种特性,让 Java 开发似乎变得缺少灵活性,开发某些功能的应用时,代码量可...

    点赞再看,动力无限。Hello world : ) 微信搜「 程序猿阿朗 」。

    本文 Github.com/niumoo/JavaNotes未读代码博客 已经收录,有很多知识点和系列文章。

    前言

    Java 平台自出现到目前为止,已经 20 多个年头了,这 20 多年间 Java 也一直作为最流行的程序设计语言之一,不断面临着其他新兴编程语言的挑战与冲击。Java 语言是一种静态强类型语言,这样的语言特性可以让 Java 编译器在编译阶段发现错误,这对于构建出一个稳定安全且健壮的应用来说,尤为重要。但是也因为这种特性,让 Java 开发似乎变得缺少灵活性,开发某些功能的应用时,代码量可能是其他语言的几倍。Java 开发的不足之处也体现越来越复杂的 JDK 上,越来越复杂的 JDK 让开发者完全理解的难度变的非常大。以至于开发者有时会重复实现一个 JDK 中已经提供了的功能。

    为了跟上互联网应用编程发展的脚步, Java 从 9 版本开始调整了 JDK 发布的节奏,JDK 的每次更新都注重提高生产效率,提高 JVM 性能,推行模块化等,让开发者可以更多的专注于业务本身,而不是浪费过多的时间在语言特性上。 Java 语言的更新要在语言的严谨性和灵活性上找到一个平衡点,毕竟灵活性可以减少编码的复杂度,而严谨性是构建复杂且健壮应用的基石。

    Java 7 语言特性

    Java 重要的更新版本是在 Java 5 版本,这个版本中增加了如泛型、增强 for、自动装箱拆箱、枚举类型,可变参数、注解等一系列重要功能,但是随后的 Java 6 中并没有增加新的重要的语言特性。Java 5 的发布是在 2004 年,已经很久远了,网上关于 Java 的教程也大多是基于 Java 6 的,也因此我准备从 Java 7 开始介绍每个 Java 版本的新特性。

    下面所有代码的运行演示都是基于 Java 7 ,所以你如果尝试下面的代码,需要安装并配置 Jdk 1.7 或者已上版本。

    1. switch String

    在 Java 7 之前,switch 语法中只支持整数类型以及这些整数类型的封装类进行判断,在 Java 7 中,支持了 string 字符串类型的判断,使用起来非常的简单,但是实用性是很高的。

    1.1. switch String 基本用法

    编写一个简单的 switch 判断字符串的测试类。

    public class SwitchWithString {
    
        public static void main(String[] args) {
            String gender = "男";
            System.out.println(gender.hashCode());
            switch (gender) {
                case "男":
                    System.out.println("先生你好");
                    break;
                case "女":
                    System.out.println("女士你好");
                    break;
                default:
                    System.out.println("你好");
            }
        }
    }
    

    switch 判断字符串使用起来很简单,结果也显而易见会先输出 gender 变量的 hashCode,然后输出匹配结果“先生你好”。

    30007
    先生你好
    

    在使用 switch string 时候,如果结合 Java 5 的枚举类,那么效果会更好,Java 7 之前使用枚举类要为每个值编数字代号,Java 7 之后可以直接定义字符串名称。

    1.2. switch String 实现原理

    但是这个支持只是编译器层面的支持, JVM 依旧是不支持的。在对字符串进行 switch 时,编译器会把字符串转换成整数类型再进行判断。为了验证上面说的只是编译器层面的支持,我们反编译(可以使用 Jad 反编译工具,也可以在 Idea 中双击编译生成的 class )生成的 class 文件,看到编译器把 switch string 转换成了字符串 hashCode 判断,为了防止 hashCode 冲突,又使用了 equals 再次判断。

    public class SwitchWithString {
        public SwitchWithString() {
        }
        
        public static void main(String[] args) {
            String gender = "男";
            System.out.println(gender.hashCode());
            byte var3 = -1;
            switch(gender.hashCode()) {
            case 22899:
                if (gender.equals("女")) {
                    var3 = 1;
                }
                break;
            case 30007:
                if (gender.equals("男")) {
                    var3 = 0;
                }
            }
    
            switch(var3) {
            case 0:
                System.out.println("先生你好");
                break;
            case 1:
                System.out.println("女士你好");
                break;
            default:
                System.out.println("你好");
            }
    
        }
    }
    

    2. try-with-resource

    Java 不同于 C++,需要开发者自己管理每一块内存,大多时候 Java 虚拟机都可以很好的帮我们进行资源管理,但是也有时候需要手动释放一些资源,比如数据库连接、磁盘文件连接、网络连接等。换句话说,只要是资源数量有限的,都需要我们手动的进行释放。

    2.1. try-catch-finally

    在操作有限资源的时候,可能会出现各种异常,不管是读取阶段还是在最后关闭资源的过程中,都有可能出现问题,我们通常会使用下面的方式 try-catch-finally 保证资源的释放。

    像下面这样。

    /**
     * 释放资源
     *
     * @author www.codingme.net
     */
    public class TryCatachFinally {
    
        /**
         * 异常处理
         *
         * @param args
         */
        public static void main(String[] args) throws Exception {
            FileInputStream inputStream = null;
            try {
                inputStream = new FileInputStream("jdk-feature-7.iml");
            } catch (FileNotFoundException e) {
                throw e;
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        throw e;
                    }
                }
            }
        }
    }
    

    看看这恶心的代码结构,为了捕获异常,我们写了一个 catch,为了能保证释放资源,我们又写了 finally 进行资源释放,在资源释放时为了捕捉 close 时抛出的异常,我们又写了一个 try-catch。最后看着这复杂的代码,如果有人告诉你这段代码有 bug,那你一定不会相信。但是确实是这样,看起来严密的代码逻辑,当 try 中的代码逻辑和 close 方法同时产生异常的时候,try 中的异常信息会丢失。

    可以看这里例子。

    package net.codingme.feature.jdk7;
    
    import java.io.IOException;
    
    /**
     * 释放资源
     *
     * @author www.codingme.net
     */
    public class TryCatachFinallyThrow {
    
        /**
         * 异常处理
         *
         * @param args
         */
        public static void main(String[] args) throws Exception {
            read();
        }
    
        public static void read() throws Exception {
            FileRead fileRead = null;
            try {
                fileRead = new FileRead();
                fileRead.read();
            } catch (Exception e) {
                throw e;
            } finally {
                if (fileRead != null) {
                    try {
                        fileRead.close();
                    } catch (Exception e) {
                        throw e;
                    }
                }
            }
    
        }
    }
    
    class FileRead {
    
        public void read() throws Exception {
            throw new IOException("读取异常");
        }
    
        public void close() throws Exception {
            System.out.println("资源关闭");
            throw new IOException("关闭异常");
        }
    }
    

    很明显代码里 readclose 方法都会产生异常,但是运行程序发现只能收到 close 的异常信息。

    资源关闭
    Exception in thread "main" java.io.IOException: 关闭异常
    	at net.codingme.feature.jdk7.FileRead.close(TryCatachFinallyThrow.java:51)
    	at net.codingme.feature.jdk7.TryCatachFinallyThrow.read(TryCatachFinallyThrow.java:33)
    	at net.codingme.feature.jdk7.TryCatachFinallyThrow.main(TryCatachFinallyThrow.java:20)
    

    异常信息丢失了,可怕的是你以为只是 close 时发生了异常而已。

    2.2. try-autocloseable

    上面的问题在 Java 7 中其实已经提供了新的解决方式,Java 7 中对 try 进行了增强,可以保证资源总能被正确释放 。使用增强 try 的前提是 try 中的类实现了 AutoCloseable 接口,在 Java 7 中大量的需要释放资源的操作其实都已经实现了此接口了。

    AutoCloseable 实现类

    实现了 AutoCloseable 的类,在增强 try中使用时,不用担心资源的关闭,在使用完毕会自动的调用 close方法,并且异常不会丢失

    让我们编写的模拟资源操作的类实现 AutoCloseable 接口,然后时候增强 try 看看效果。

    package net.codingme.feature.jdk7;
    
    /**
     * 自动关闭
     *
     * @author www.codingme.net
     */
    public class AutoCloseResource {
        public static void main(String[] args) throws Exception {
            try (Mysql mysql = new Mysql();
                 OracleDatabase oracleDatabase = new OracleDatabase()) {
                mysql.conn();
                oracleDatabase.conn();
            }
        }
    }
    
    class Mysql implements AutoCloseable {
    
        @Override
        public void close() throws Exception {
            System.out.println("mysql 已关闭");
        }
    
        public void conn() {
            System.out.println("mysql 已连接");
        }
    }
    
    class OracleDatabase implements AutoCloseable {
    
        @Override
        public void close() throws Exception {
            System.out.println("OracleDatabase 已关闭");
        }
    
        public void conn() {
            System.out.println("OracleDatabase 已连接");
        }
    }
    

    测试类 Mysql 和 OracleDatabase 都是实现了 AutoCloseable,运行查看结果。

    mysql 已连接
    OracleDatabase 已连接
    OracleDatabase 已关闭
    mysql 已关闭
    

    确认在发生异常时候异常信息不会丢失,写一个有异常的模拟测试类进行测试。

    package net.codingme.feature.jdk7;
    
    import java.io.IOException;
    
    /**
     * 释放资源
     *
     * @author www.codingme.net
     */
    public class AutoCloseThrow {
    
        public static void main(String[] args) throws Exception {
            try (FileReadAutoClose fileRead = new FileReadAutoClose()) {
                fileRead.read();
            }
        }
    }
    
    class FileReadAutoClose implements AutoCloseable {
    
        public void read() throws Exception {
            System.out.println("资源读取");
            throw new IOException("读取异常");
        }
    
        @Override
        public void close() throws Exception {
            System.out.println("资源关闭");
            throw new IOException("关闭异常");
        }
    }
    

    运行查看异常信息。

    资源读取
    资源关闭
    Exception in thread "main" java.io.IOException: 读取异常
    	at net.codingme.feature.jdk7.FileReadAutoClose.read(AutoCloseThrow.java:23)
    	at net.codingme.feature.jdk7.AutoCloseThrow.main(AutoCloseThrow.java:14)
    	Suppressed: java.io.IOException: 关闭异常
    		at net.codingme.feature.jdk7.FileReadAutoClose.close(AutoCloseThrow.java:29)
    		at net.codingme.feature.jdk7.AutoCloseThrow.main(AutoCloseThrow.java:15)
    

    自动关闭,异常清晰,关闭异常存在于 Suppressed ,称为抑制异常,后续文章会详细介绍。

    3. try-catch

    在 Java 7 之前,一个 catch 只能捕获一个异常信息,当异常种类非常多的时候就很麻烦,但是在 Java 7 中,一个 catch 可以捕获多个异常信息,每个异常捕获之间使用 | 分割,

    package net.codingme.feature.jdk7;
    
    import java.io.IOException;
    
    /**
     * 多异常捕获
     */
    public class TryCatchMany {
    
        public static void main(String[] args) {
            try (TxtRead txtRead = new TxtRead()) {
                txtRead.reader();
            } catch (IOException | NoSuchFieldException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    class TxtRead implements AutoCloseable {
    
        @Override
        public void close() throws Exception {
            System.out.println("资源释放");
        }
    
        public void reader() throws IOException, NoSuchFieldException {
            System.out.println("数据读取");
        }
    }
    

    需要注意的是,一个 catch 捕获多个异常时,不能出现重复的异常类型,也不能出现一个异常类型是另一个类的子类的情况。

    4. 二进制

    Java 7 开始,可以直接指定不同的进制数字。

    1. 二进制指定数字值,只需要使用 0b 或者 OB 开头。
    2. 八进制指定数字值,使用 0 开头。
    3. 十六进制指定数字值,使用 0x 开头。
    /**
     * 二进制
     *
     * @author www.codingme.net
     */
    public class Binary {
        public static void main(String[] args) {
            // 二进制
            System.out.println("------2进制-----");
            int a = 0b001;
            int b = 0b010;
            System.out.println(a);
            System.out.println(b);
            // 八进制
            System.out.println("------8进制-----");
            int a1 = 010;
            int b1 = 020;
            System.out.println(a1);
            System.out.println(b1);
            // 十六进制
            System.out.println("------16进制-----");
            int a2 = 0x10;
            int b2 = 0x20;
            System.out.println(a2);
            System.out.println(b2);
        }
    }
    

    输出结果。

    ------2进制-----
    1
    2
    ------8进制-----
    8
    16
    ------16进制-----
    16
    32
    

    5. 数字下划线

    Java 7 开始支持在数字定义时候使用下划线分割,增加了数字的可读性。

    /**
     * 数字下环线
     *
     * @author www.codingme.net
     */
    public class NumberLine {
        public static void main(String[] args) {
            int a = 1_000;
            int b = 1_0__0_0_0_____00;
            System.out.println(a);
            System.out.println(b);
        }
    }
    

    得到结果。

    1000
    1000000
    

    6. 结束语

    虽然 Java 7 早在 2011 年就已经发布了,但是据我发现,使用到 Java 7 开始的新特性新语法的并不多,所以我的 JDK 新特性系列文章计划从 Java 7 开始,一直介绍到目前已经发布的 Java 13,以后 Java 新版本更新的同时,这个新特性系列文章也会持续更新。

    此去山高水远,愿能一路坚持,愿你我一路同行

    <完>

    Hello world : ) 我是阿朗,一线技术工具人,认认真真写文章。

    点赞的个个都是人才,不仅长得帅气好看,说话还好听。


    文章持续更新,可以关注公众号「 程序猿阿朗 」或访问「未读代码博客 」。

    回复【资料】有我准备的各系列知识点和必看书籍。

    本文 Github.com/niumoo/JavaNotes 已经收录,有很多知识点和系列文章,欢迎Star。

    等你好久

    展开全文
  • 连反射都不懂,框架你怎么能学懂啊

    前言

    只有光头才能变强。

    文本已收录至我的GitHub精选文章,欢迎Starhttps://github.com/ZhongFuCheng3y/3y

    今天来简单写一下Java的反射。本来没打算写反射这个知识点的,只是不少的读者都问过我:“你的知识点好像缺了反射阿。能不能补一下?”

    这周末也有点空了,所以来写写我对反射的简单理解。这篇是入门文章,没有高深的知识点,希望能对新人有帮助。如果文章有错的地方,麻烦在评论区友善评论指出~

    Java常用和重要的知识点我都写过(现在已有200+篇技术原创),如果想看的同学,不妨关注我的GitHub,即可获取我的所有原创文章。

    一、序言

    在学习Java基础的时候,一般都会学过反射。我在初学反射的时候,并不能理解反射是用来干嘛的。学了一些API发现:“明明我自己能直接new一个对象,为什么它要绕一个圈子,先拿到Class对象,再调用Class对象的方法来创建对象呢,这不是多余吗?

    相信很多人在初学反射的时候也都会有这个想法(我就不相信就只有我一个人这么蠢!!)

    而且在搜索相关资料的时候,一般也仅仅是讲解反射的一系列API,始终是不了解反射究竟是有什么用,这篇文章来告诉你吧。觉得不错,给我点个赞呗

    二、引出Class对象

    首先我们来看一段代码:

    public class Demo {
        // 自建了一个Student类
        class Student{
        }
        public static void main(String[] args) {
            // 将Object 强转成Student类
            Object o = new Object();
            Student s = (Student) o;
        }
    }
    

    我们在IDE编写这一段代码的时候,不会出现任何的错误。但是等我们执行的时候,我们会知道这肯定强转失败了

    那么“Java”(实质上JVM)是怎么知道我们写的强转有没有问题的呢?可以依赖Class对象来协助判断。

    如果看过我写JVM的那篇文章的同学应该都知道一个对象的加载过程,如果没看过的同学可以再去看看,顺便在这里给大家复习一下:

    • 一个.java的文件经过javac命令编译成功后,得到一个.class的文件

    • 当我们执行了初始化操作(有可能是new、有可能是子类初始化 父类也一同被初始化、也有可能是反射…等),会将.class文件通过类加载器装载到jvm

    • .class文件加载器加载到jvm中,又分了好几个步骤,其中包括 加载、连接和初始化

    • 其中在加载的时候,会在Java堆中创建一个java.lang.Class类的对象,这个Class对象代表着类相关的信息

    既然说,Class对象代表着类相关的信息,那说明只要类有什么东西,在Class对象我都能找得到。我们打开IDE看看里边的方法:

    于是我们可以通过Class对象来判断对象的真正类型

    三、反射介绍

    其实反射就是围绕着Class对象和java.lang.reflect类库来学习,就是各种的API

    比如上面截图的Method/Field/Constructor这些都是在java.lang.reflect类库下,正是因为这些类库的学习并不难,所以我才一直没写反射的文章。

    我并不是说这些API我都能记住,只是这些API教程在网上有非常非常多,也足够通俗易懂了。在入门的时候,其实掌握以下几种也差不多了:

    • 知道获取Class对象的几种途径
    • 通过Class对象创建出对象,获取出构造器,成员变量,方法
    • 通过反射的API修改成员变量的值,调用方法
    /*
    	下面是我初学反射时做的笔记,应该可以帮到大家,代码我就不贴了。(Java3y你值得关注)
    */
    想要使用反射,我先要得到class文件对象,其实也就是得到Class类的对象
    Class类主要API:
            成员变量  - Field
            成员方法  - Constructor
            构造方法  - Method
    获取class文件对象的方式:
            1:Object类的getClass()方法
            2:数据类型的静态属性class
            3:Class类中的静态方法:public static Class ForName(String className)
    --------------------------------  
    获取成员变量并使用
            1: 获取Class对象
            2:通过Class对象获取Constructor对象
            3:Object obj = Constructor.newInstance()创建对象
            4:Field field = Class.getField("指定变量名")获取单个成员变量对象
            5:field.set(obj,"") 为obj对象的field字段赋值
    如果需要访问私有或者默认修饰的成员变量
            1:Class.getDeclaredField()获取该成员变量对象
            2:setAccessible() 暴力访问  
    ---------------------------------          
    通过反射调用成员方法
            1:获取Class对象
            2:通过Class对象获取Constructor对象
            3:Constructor.newInstance()创建对象
            4:通过Class对象获取Method对象  ------getMethod("方法名");
            5: Method对象调用invoke方法实现功能
    如果调用的是私有方法那么需要暴力访问
            1: getDeclaredMethod()
            2: setAccessiable();          
    

    相信我,去搜索引擎看一会,你就学会了。反射的API并不难学,一般人学不懂反射因为不知道反射究竟能干什么,下面我来讲讲我的讲解。

    四、为什么需要反射

    在初学Java的时候其实我个人认为还是比较难理解为什么需要反射的,因为没有一定的代码量下,很难理解为什么我要绕一个圈子去搞反射这一套。

    我现在认为用反射主要有两个原因:

    • 提高程序的灵活性
    • 屏蔽掉实现的细节,让使用者更加方便好用

    我一直在文章中都在强调,学某一项技术之前,一定要理解为什么要学这项技术,所以我的文章一般会花比较长的幅度上讲为什么。

    下面我来举几个例子来帮助大家理解

    4.1 案例一(JDBC)

    相信大家都写过jdbc的代码,我贴一小段,大家回顾一下:

    Class.forName("com.mysql.jdbc.Driver");
    
    //获取与数据库连接的对象-Connetcion
    connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/java3y", "root", "root");
    
    //获取执行sql语句的statement对象
    statement = connection.createStatement();
    
    //执行sql语句,拿到结果集
    resultSet = statement.executeQuery("SELECT * FROM users");
    

    后来为什么要变成下面这种形式呢?

    //获取配置文件的读入流
    InputStream inputStream = UtilsDemo.class.getClassLoader().getResourceAsStream("db.properties");
    
    Properties properties = new Properties();
    properties.load(inputStream);
    
    //获取配置文件的信息
    driver = properties.getProperty("driver");
    url = properties.getProperty("url");
    username = properties.getProperty("username");
    password = properties.getProperty("password");
    
    //加载驱动类
    Class.forName(driver);
    

    理由很简单,人们不想修改代码。只要存在有变动的地方,我写在配置里边,不香吗?但凡有一天,我的username,password,url甚至是数据库都改了,我都能够通过修改配置的方式去实现。

    不需要动我丝毫的代码,改下配置就完事了,这就能提供程序的灵活性。

    有人可能会问:“那还是要改啊,我改代码也很快啊,你改配置不也是要改吗”。

    其实不一样的,我举个例子:

    • 三歪写了一个JDBC组件,把各种配置都写死在代码上,比如上面的driver/username/数据库连接数等等。现在三歪不干了,要跑路了。
    • 敖丙来接手三歪的代码,敖丙刚开始接手项目,公司说要换数据库。敖丙给领导说:这玩意,我改改配置就好了,几分钟完事。
    • 敖丙找了半天都没找到配置的地方,由于三歪写的代码又臭又烂,找了半天才找到入口和对应的位置。

    改代码的风险要比改配置大,即便不知道代码的实现都能通过改配置来完成要做的事。

    这种就能通过可配的,其内部很可能就是通过反射来做的。

    这里只是说可能,但不全是。有的可配的参数可能就仅仅只是配置,跟反射无关。但上面jdbc的例子,就是通过反射来加载驱动的。

    4.2 案例二(SpringMVC)

    相信大家学SpringMVC之前都学过Servlet的吧,如果没学过,建议看我的文章再复复习。

    我当时学MVC框架的时候给我带来印象最深的是什么,本来需要各种getParameter(),现在只要通过约定好JavaBean的字段名,就能把值填充进去了。

    还是上代码吧,这是我们当时学Servlet的现状:

    //通过html的name属性,获取到值
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    String gender = request.getParameter("gender");
    
    //复选框和下拉框有多个值,获取到多个值
    String[] hobbies = request.getParameterValues("hobbies");
    String[] address = request.getParameterValues("address");
    
    //获取到文本域的值
    String description = request.getParameter("textarea");
    
    //得到隐藏域的值
    String hiddenValue = request.getParameter("aaa");
    

    我们学到SpringMVC的时候是怎么样的:

    @RequestMapping(value = "/save")
    @ResponseBody
    public String taskSave(PushConfig pushConfig) {
         // 直接使用  
    	   String name= pushConfig.getName();
    }
    

    为什么SpringMVC能做到?其实就是通过反射来做的。

    相信你也有过的经历:

    • 如果你的JavaBean的属性名跟传递过来的参数名不一致,那就“自动组装”失败了。因为反射只能根据参数名去找字段名,如果不一致,那肯定set不进去了。所以就组装失败了呀~

    如果在使用框架的时候,为什么我们往往写上JavaBean,保持字段名与参数名相同,就能“自动”得到对应的值呢。这就是反射的好处。

    屏蔽掉实现的细节,让使用者更加方便好用

    五、我们写反射的代码多吗?

    大部分程序员都是写业务代码的,大部分程序员都是维护老系统的,其实要我们自己写反射的代码的时候,真的不多。

    从上面也看出,什么时候会写反射?写我们自己组件/框架的时候。如果想找个地练手一下反射,我觉得自定义注解是一个不错的选择。

    因为现在用注解的地方很多,主要是够清晰简单(再也不用对着一堆的XML文件了,哈哈哈哈~)。

    我初学的时候写过一段,可以简单参考一下,思路都差不多的哈。下面是使用的效果(使用自定义注解给不同的接口增加权限)

    @permission("添加分类")
    /*添加分类*/ void addCategory(Category category);
    
    /*查找分类*/
    void findCategory(String id);
    
    @permission("查找分类")
    /*查看分类*/ List<Category> getAllCategory();
    

    返回一个代理的Service对象来处理自定义注解:

    public class ServiceDaoFactory {
    
        private static final ServiceDaoFactory factory = new ServiceDaoFactory();
    
        private ServiceDaoFactory() {
        }
    
        public static ServiceDaoFactory getInstance() {
            return factory;
        }
    
    
        //需要判断该用户是否有权限
        public <T> T createDao(String className, Class<T> clazz, final User user) {
    
            System.out.println("添加分类进来了!");
    
            try {
                //得到该类的类型
                final T t = (T) Class.forName(className).newInstance();
                //返回一个动态代理对象出去
                return (T) Proxy.newProxyInstance(ServiceDaoFactory.class.getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
    
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, PrivilegeException {
                        //判断用户调用的是什么方法
                        String methodName = method.getName();
                        System.out.println(methodName);
    
                        //得到用户调用的真实方法,注意参数!!!
                        Method method1 = t.getClass().getMethod(methodName,method.getParameterTypes());
    
                        //查看方法上有没有注解
                        permission permis = method1.getAnnotation(permission.class);
    
                        //如果注解为空,那么表示该方法并不需要权限,直接调用方法即可
                        if (permis == null) {
                            return method.invoke(t, args);
                        }
    
                        //如果注解不为空,得到注解上的权限
                        String privilege = permis.value();
    
                        //设置权限【后面通过它来判断用户的权限有没有自己】
                        Privilege p = new Privilege();
                        p.setName(privilege);
    
                        //到这里的时候,已经是需要权限了,那么判断用户是否登陆了
                        if (user == null) {
    
                            //这里抛出的异常是代理对象抛出的,sun公司会自动转换成运行期异常抛出,于是在Servlet上我们根据getCause()来判断是不是该异常,从而做出相对应的提示。
                            throw new PrivilegeException("对不起请先登陆");
                        }
    
                        //执行到这里用户已经登陆了,判断用户有没有权限
                        Method m = t.getClass().getMethod("findUserPrivilege", String.class);
                        List<Privilege> list = (List<Privilege>) m.invoke(t, user.getId());
    
                        //看下权限集合中有没有包含方法需要的权限。使用contains方法,在Privilege对象中需要重写hashCode和equals()
                        if (!list.contains(p)) {
                            //这里抛出的异常是代理对象抛出的,sun公司会自动转换成运行期异常抛出,于是在Servlet上我们根据getCause()来判断是不是该异常,从而做出相对应的提示。
                            throw new PrivilegeException("您没有权限,请联系管理员!");
                        }
    
                        //执行到这里的时候,已经有权限了,所以可以放行了
                        return method.invoke(t, args);
                    }
                });
    
            } catch (Exception e) {
                new RuntimeException(e);
            }
            return null;
        }
    }
    

    最后

    这篇反射跟网上的文章不太一样,网上的反射一般都是介绍反射的API如何使用。如果你觉得还不错,给我点赞吧👍。想要看其他知识点的同学,可以给我留言,我可以酌情考虑写一下(哈哈哈哈,突然变大牌了)

    这篇文章涉及到的其他知识点:JVM类的加载过程、注解、动态代理、SpringMVC、JDBC我都已经写过文章了,想要阅读的同学可以关注我的GitHub搜索相关关键字即可。

    涵盖Java后端所有知识点的开源项目(已有5.8K star):https://github.com/ZhongFuCheng3y/3y

    如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号「Java3y」。(微信搜Java3y即可关注)

    • 🔥Java精美脑图
    • 🔥Java学习路线
    • 🔥Java常用的开发工具
    • 🔥原创PDF电子书

    PDF文档的内容均为手打,有任何的不懂都可以直接来问我(公众号有我的联系方式)。

    在公众号下回复「888」即可获取!!

    展开全文
  • 白话阿里巴巴Java开发手册高级篇

    万次阅读 多人点赞 2019-11-08 16:25:22
    不久前,阿里巴巴发布了《阿里巴巴Java开发手册》,总结了阿里巴巴内部实际项目开发过程中开发人员应该遵守的研发流程规范,这些流程规范在一定程度上能够保证最终的项目交付质量,通过在时间中总结模式,并推广给...
  • 高级JAVA开发 MQ部分

    千次阅读 2019-05-15 02:18:43
    高级JAVA开发 MQ部分MQMQ的作用、为什么要用MQ常见的MQ的优缺点使用MQ带来的问题以及处理办法MQ带来的问题列举消息重复消费(幂等)问题消息丢失问题消息顺序性问题消息过期丢失、大量积压等问题如何保证MQ高可用性...
  • 总结一下就是,调用者需要知道类到底是怎么实现,怎么命名,和业务逻辑,只管调用就行。 好吧,这个例子是我想破脑袋才想出来的,网上解释很多,但是我现在的水品还怎么理解。希望有能力的大哥大姐指正,教育。...
  • Java 开发必备:"神器

    千次阅读 2018-09-04 21:40:21
    导读:Java开发人员经常要和各种各样的工具打交道,除了常用的IDE工具以外,其实还有很多工具是我们在日常开发及学习过程中要经常使用到的。本文作者Hollis偏爱使用在线工具,因为这样比较方便。本文就总结了一下...
  • 想必是很多人都有的心理历程或者是“说辞”,但其实真正的原因并不是你们所说的“我能懂,但是让我写却写不出来”,真正的原因和问题是在于你当时学习的时候就没有学会,也不懂如何正确的学习Java编程。...
  • 从初级java开发到中级java开发,我用了三年

    千次阅读 多人点赞 2020-04-28 14:06:44
    我从事java开发是在我毕业之后通过培训机构的学习,还有自己的努力,才走上了这条道路。 我在的城市是广州,相对北上深的其他一线城市来说,工资是没有那么高的,所幸的是,消费相对来说也比较便宜,所以我挺喜欢...
  • [Java]Spring Ioc讲解,不怕你不懂

    千次阅读 多人点赞 2015-10-13 21:00:45
    但是IoC这个重要的概念却比较晦涩隐讳,容易让人望文生义,这说是一大遗憾。不过IoC确实包括很多内涵,它涉及代码解耦、设计模式、代码优化等问题的考量,我们打算通过一个小例子来说明这个概念。通过实例...
  • 10分钟看懂Java NIO 底层原理

    千次阅读 2020-10-27 00:26:32
    很多的小伙伴,也被nio这个名词搞晕了,一会儿java 的nio 叫 非阻塞io,一会儿java nio 又是非阻塞io,到底是啥呢? ​很多的小伙伴,被异步和非阻塞搞晕了。都非阻塞了,难道不是异步的吗? ​这这,好难呀。 此...
  • Java开发中的命名规范

    千次阅读 2010-09-15 11:19:00
    开发过大型项目的的软件工程师都可能遇过这种情况,在项目的命名不规范,导致代码的可读性下降,看不懂其他工程师写的代码,这是个很严重的问题。对于项目后续维护来说,也是不可想像的。除此之外,注释也一样不可...
  • JAVA后端开发浅谈

    千次阅读 多人点赞 2020-02-28 16:00:40
    两个阵营的开发基本上都是各自围绕着各自的开发语言(php/Java),选取最为兼容合适的框架结构和数据库,然后进行服务器端的开发。以下附上PHP和Java语言的区别介绍和原文链接: 《php和java的区别有哪些》 php中文...
  • 小白也能看懂Java内存模型

    千次阅读 热门讨论 2021-03-09 14:28:14
    也是中高级岗位面试必问的问题,本系列就是为了带读者们系统的一步一步击破Java并发编程各个难点,打破屏障,在面试中所向披靡,拿到心仪的offer,Java并发编程系列文章依然采用图文并茂的风格,让小白也能秒。...
  • 全新Java开发思维导图

    千次阅读 2018-08-06 20:58:47
    蓦然回首自己做开发已经十年了,这十年中我获得了很多,技术能力、培训、出国、大公司的...路其实一直都在那里,只是我们看不到而已!   以前我一直被公司和技术牵着走,并是自己在选择技术,而是自觉地被...
  • JAVA开发全集

    万次阅读 2013-08-14 18:37:22
    http://java.zttc.edu.cn/webservice"/ >  //�如果使用以下方式进行设置,会见转换为<和>  //body.addBodyElement(qname).setValue("<a>1</a><b>2</b>");  SOAPBodyElement ele = body....
  • 后来,又有读者私信问我,“挺纠结的,知道该选前端还是 Java?” 真不好选,因为“男怕入错行,女怕嫁错郎”,初学者纠结这个问题也是情有可原。 首先来说说 PHP,Web 蛮荒的年代,PHP 真的是王者姿态,连 Java ...
  • java 开发新技术

    千次阅读 2017-02-14 10:01:33
    最近在网上查资料碰到好多没接触过的技术,先汇总在这里备用,以后慢慢吸收 ...基于JDBC3.0转为Desktop应用设计的嵌入式数据库,纯Java,本地访问,支持网络 但目前好像太活跃,最新版本是0.2,并且20
  • java web 开发入门心得

    万次阅读 多人点赞 2011-12-15 00:05:45
    从事Java Web开发这一段时间来,对Java 面向对象的思想和MVC开发模式可以说已经熟悉了。我当前参与的项目使用的框架是Spring、SpringMVC、Hibernate。作为刚刚参加工作的入门者,我下面谈自己的几点心得,还恳请前辈...
  • 公司最近准备招JAVA后台,虽然目前我任职IOS开发工作  但JAVA技术之前有做过几个项目,对于面试这种事情自然不在话下。  关于招聘要求: 首先当然要技术过关才行,适当的有自己的技术博客或者开源框架开源优先...
  • 本文来自作者 我是最强青铜杨小强 在 GitChat 上分享 「知名互联网公司校招 Java 开发岗面试知识点解析」,「阅读原文」查看交流实录。「文末高能」编辑 | 哈比天之道,损有余而补不足,是故虚胜实,不足胜有余...
  • long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) 在Java中,线程池的概念是Executor这个接口,具体实现为...
  • Java开发:开源框架面试总结

    千次阅读 2017-11-04 15:03:29
    此篇文章是应届生临时总结的Java开发面试开源框架部分:主要总结了主要的几个点,便于回答,用于有一定Java基础的同学面试所用,由于是面试问题,所以内容多有详尽之处。  学习一个技术要明白几个点:这个技术是...
  • 大四 Java开发实习近一年 记录

    万次阅读 多人点赞 2018-05-02 10:41:02
    但是去了客户现场后我还是一头雾水,很多关于项目上线的具体细节都了解(之前关注具体的业务开发),导致那段时间压力巨大。微博截图为证: 但是咬咬牙坚持两个月,项目终于还是成功上线了。并且我认为这段经历也...
  • java开发经验分享

    千次阅读 2013-10-13 17:02:23
    开发经验分享 一、 编码 1. 约束自己,规范编码习惯 充足的代码注释、标准缩进的格式、注意命名规范。参考《开发管理规范》 "上去"专业能促进代码质量。越是难看的代码,在它的演化过程中会越来越差。因为当...
  • 2017java开发新技术

    千次阅读 2017-12-11 11:19:06
    1. JNA ...基于JDBC3.0转为Desktop应用设计的嵌入式数据库,纯Java,本地访问,支持网络 但目前好像太活跃,最新版本是0.2,并且2008年后没有更新   3. Fisheye 类似Hudson的配置库管
  • Java Web开发技术概述

    千次阅读 2008-01-24 00:16:00
    第1章 Java Web开发技术概述J2EE(Java 2 Platform,Enterprise Edition)平台建立在J2SE(Java 2 Platform,Standard Edition)的基础上,为企业级应用提供了完整,稳定,安全和快速的Java平台.J2EE平台提供的Web开发技术...
  • 简介:最新发布的《Java开发手册(嵩山版)》增加了前后端规约,其中有一条:禁止服务端在超大整数下使用Long类型作为返回。这是为何?在实际开发中可能出现什么问题?本文从IEEE754浮点数标准讲起,详细解析背后的...
  • Java开发实习(入职经历)

    万次阅读 多人点赞 2018-11-24 15:50:42
    今天周末,在家整理电脑,看着自己辛辛苦苦总结出来的学习记录越来越多,忍不住想要整理出来分享...大致讲了规章制度,什么该做,什么能做,待遇等。。。比公司宣讲的时候多了一点要求,其他,比如福利相比宣讲时...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 62,782
精华内容 25,112
关键字:

java开发看不懂业务

java 订阅