【API知识】类型转换工具ConvertUtils引发的思考
前言
在读取Excel文件数据,有时候不可避免地需要把获取到的字符串转型为基本类型的对象。以前都是自己写转换,难度也不大。后来听说,有可以直接用的轮子——Apache 的commons-beanutils这个包,有提供ConvertUtils。以下我的相关记录。
我要的异常呢?
听说有可以用的轮子,第一反应,肯定是拿来先跑几个测试案例。这东西使用起来也很简单,参数就是源字符串和目的类型。我就先测了一下,一个乱码String转Boolean,看看会不会抛出异常。结果出乎意外的是,它居然没有抛出异常,还返回了false。认真看了一下,才发现它直接把异常打印出来了,还返回了默认值。
代码如下:
public class ConvertTest {
public static void main(String[] args) {
Object result;
result = ConvertUtils.convert("@7##jF*&%#$", Boolean.class);
System.out.println(result);
}
}
输出结果:

真是够呛,你不抛出异常,我留你何用。我就是要你抛出异常,然后我再在上层决定怎么和用户交互,你倒好,直接打印出来了,还给我个默认值,那怎么知道原来的值到底是错误的还是bool false。
于是我想,这种工具都有一个尿性——可配置。我就想肯定有什么方法,比如xxxwithException(),或者throwException()这样的设定。结果翻了一下,还真没有。哇,上头。
内核——ConvertUtilsBean
刚好有时间,于是就看它到底怎么实现的。看了才知道,原来它是把工作委托给ConvertUtilsBean来做的。
public static Object convert(final String value, final Class<?> clazz) {
//这里获取一个ConvertUtilsBean的实例来执行convert方法
return ConvertUtilsBean.getInstance().convert(value, clazz);
}
于是顺藤摸瓜,我就随便翻了翻ConvertUtilsBean。我的眼睛就盯着,看看有没有exception这个关键字,果然让我找到了!!!
public void register(final boolean throwException, final boolean defaultNull, final int defaultArraySize) {
registerPrimitives(throwException);
registerStandard(throwException, defaultNull);
registerOther(throwException);
registerArrays(throwException, defaultArraySize);
}
这里可以配置是否要抛出异常。于是我就用这个bean,测了一下,果然可以。
public class ConvertBeanTest {
public static void main(String[] args) {
ConvertUtilsBean convertUtilsBean = new ConvertUtilsBean();
convertUtilsBean.register(true, false, 0);
Object obj;
obj = convertUtilsBean.convert("@7##jF*&%#$", Boolean.class);
System.out.println(obj);
}
}
输出:

很好,终于抛出异常了。那么,我用这个ConvertUtilsBean就可以了。
ConvertUtilsBean为何能够想转什么就转什么?
实际上,它也不是想转什么就转什么。初始条件下,它内部只注册了基本类型的转换器。
public ConvertUtilsBean() {
converters.setFast(false);
//这个方法是关键,它清除当前所有转换器,并重新初始化
deregister();
converters.setFast(true);
}
public void deregister() {
converters.clear();
//false参数表示,是否抛出异常。即默认不抛出异常。
//这里注册了基本类型的转换器
registerPrimitives(false);
registerStandard(false, false);
registerOther(true);
registerArrays(false, 0);
register(BigDecimal.class, new BigDecimalConverter());
register(BigInteger.class, new BigIntegerConverter());
}
注册是什么概念?
“注册”这个词,看上去挺玄乎的,其实一般就是写到一个注册表里面,然后需要的时候从表中检索。在这个实现中,注册表,不过就是一张HashMap。而注册操作,就是把Converter对象放到这个哈希表中。
/**
* The set of {@link Converter}s that can be used to convert Strings
* into objects of a specified Class, keyed by the destination Class.
*/
private final WeakFastHashMap<Class<?>, Converter> converters =
new WeakFastHashMap<Class<?>, Converter>();
我们可以看到,这个表的Key是类型。也就是说,我们在使用convert方法的时候,已经指定了key,自然就找到了对应的Converter。那我们还能想到什么呢,那就是“覆盖”。因为HashMap中,Key是唯一的,所以同种类型的Converter只能存在一个,即新注册的Converter会覆盖同类型的Converter。
对了,忘记提了,这个包有一个Converter接口,如果要自定义的话,也可以自己实现相关的类,注册到这个Bean上,然后统一使用这个Bean。
service provider framework
之所以想到这个,是因为前几天刚刚开始看《Effective Java》这本书中,而里面说的service provider framwork的结构,和这个非常类似。
三个要素:
service接口 => Converter接口
register API => register方法
access API => ConverterUtils工具类
体现的思想就是:客户端和实现类解耦,参照上面的,客户端只要知道ConvertUtils或者ConvertUtilsBean这个类就好了,不需要去记该用哪个Converter。
【API知识】类型转换工具ConvertUtils引发的思考的更多相关文章
- API文档管理工具-数据库表结构思考.
API文档管理工具-数据库表结构思考. PS: 管理工具只是为了方便自己记录API的一些基本信息,方便不同的开发人员 (App Developer, Restful API Developer)之间的 ...
- 由C# dynamic是否装箱引发的思考
前言 前几天在技术群里看到有同学在讨论关于dynamic是否会存在装箱拆箱的问题,我当时第一想法是"会".至于为啥会有很多人有这种疑问,主要是因为觉得dynamic可能是因为有点特 ...
- Spring之LoadTimeWeaver——一个需求引发的思考---转
原文地址:http://www.myexception.cn/software-architecture-design/602651.html Spring之LoadTimeWeaver——一个需求引 ...
- 解决一道leetcode算法题的曲折过程及引发的思考
写在前面 本题实际解题过程是 从 40秒 --> 24秒 -->1.5秒 --> 715ms --> 320ms --> 48ms --> 36ms --> ...
- 【思考】由安装zabbix至排障php一系列引发的思考
[思考]由安装zabbix至排障php一系列引发的思考 linux的知识点林立众多,很有可能你在排查一个故障的时候就得用到另一门技术的知识: 由于linux本身的应用依赖的库和其它环境环环相扣,但又没 ...
- 一个ScheduledExecutorService启动的Java线程无故挂掉引发的思考
2018年12月12日18:44:53 一个ScheduledExecutorService启动的Java线程无故挂掉引发的思考 案件现场 不久前,在开发改造公司一个端到端监控日志系统的时候,出现了一 ...
- Vue.js 2.x API 知识梳理(一) 全局配置
Vue.js 2.x API 知识梳理(一) 全局配置 Vue.config是一个对象,包含Vue的全局配置.可以在启动应用之前修改指定属性. 这里不是指的@vue/cli的vue.config.js ...
- 由SecureCRT引发的思考和学习
由SecureCRT引发的思考和学习 http://mp.weixin.qq.com/s?__biz=MzAxOTAzMDEwMA==&mid=2652500597&idx=1& ...
- 由<a href = "#" > 引发的思考
原文:由<a href = "#" > 引发的思考 前阵子在一个移动项目中,通过 <a href = "#" > 的方式 绑定clic ...
随机推荐
- PHP开发——超全局数组变量
概述 l JS中的变量分两类:局部变量.全局变量. l PHP中的变量分三类:局部变量.全局变量.超全局变量. l 局部变量:在函数内部声明的变量,就是局部变量.函数执行完毕,局部变量就消失了. ...
- Python开发——基础
注释 单行注释 # 被注释的内容 多行注释 """ 被注释的内容 """ 解释器路径 #!/usr/bin/env python # 用于L ...
- 线程属性 pthread_attr_t
参考资料: https://blog.csdn.net/hudashi/article/details/7709413 Posix线程中的线程属性pthread_attr_t主要包括scope属性.d ...
- JVM 字节码(一)字节码规范
JVM 字节码(一)字节码规范 JVM 学习资源 Java ClassFile 字节码规范(Oracle) Java 虚拟机规范(Java SE 7 中文版) (周志明等译) Java 反编译工具 - ...
- epoll_wait会被系统中断唤醒
今天,当一个程序在epoll_wait阻塞时,用strace跟踪了一下,结果epoll_wait就被EINTR唤醒了,并且返回-1: 所以,当epoll_wait返回-1时,需要判断errno是不是E ...
- PHP-预定义函数访问数据库
(1)复习:自定义函数 (2)调用PHP预定义的函数——访问MySQL数据库 1.函数的基础概念 定义一个简单的函数: function 函数名( ){ #函数主体 } 调用/运行一次函数: ...
- 11. English vocabulary 英语词汇量
11. English vocabulary 英语词汇量 (1) The exact number of English words is not known.The large dictionari ...
- shell脚本学习- 传递参数
跟着RUNOOB网站的教程学习的笔记 我们可以在执行shell脚本时,向脚本传递参数,脚本内获取参数的格式为:$n.n代表一个数字,1为执行脚本的第一参数,2为执行脚本的第二个参数,以此类推... 实 ...
- Android系统的镜像文件的打包过程
在前面一篇文章中,我们分析了Android模块的编译过程.当Android系统的所有模块都编译好之后,我们就可以对编译出来的模块文件进行打包了.打包结果是获得一系列的镜像文件,例如system.img ...
- ECharts初体验
ECharts,一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等) ...