前言

  在读取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引发的思考的更多相关文章

  1. API文档管理工具-数据库表结构思考.

    API文档管理工具-数据库表结构思考. PS: 管理工具只是为了方便自己记录API的一些基本信息,方便不同的开发人员 (App Developer, Restful API Developer)之间的 ...

  2. 由C# dynamic是否装箱引发的思考

    前言 前几天在技术群里看到有同学在讨论关于dynamic是否会存在装箱拆箱的问题,我当时第一想法是"会".至于为啥会有很多人有这种疑问,主要是因为觉得dynamic可能是因为有点特 ...

  3. Spring之LoadTimeWeaver——一个需求引发的思考---转

    原文地址:http://www.myexception.cn/software-architecture-design/602651.html Spring之LoadTimeWeaver——一个需求引 ...

  4. 解决一道leetcode算法题的曲折过程及引发的思考

    写在前面 本题实际解题过程是 从 40秒 --> 24秒 -->1.5秒 --> 715ms --> 320ms --> 48ms --> 36ms --> ...

  5. 【思考】由安装zabbix至排障php一系列引发的思考

    [思考]由安装zabbix至排障php一系列引发的思考 linux的知识点林立众多,很有可能你在排查一个故障的时候就得用到另一门技术的知识: 由于linux本身的应用依赖的库和其它环境环环相扣,但又没 ...

  6. 一个ScheduledExecutorService启动的Java线程无故挂掉引发的思考

    2018年12月12日18:44:53 一个ScheduledExecutorService启动的Java线程无故挂掉引发的思考 案件现场 不久前,在开发改造公司一个端到端监控日志系统的时候,出现了一 ...

  7. Vue.js 2.x API 知识梳理(一) 全局配置

    Vue.js 2.x API 知识梳理(一) 全局配置 Vue.config是一个对象,包含Vue的全局配置.可以在启动应用之前修改指定属性. 这里不是指的@vue/cli的vue.config.js ...

  8. 由SecureCRT引发的思考和学习

    由SecureCRT引发的思考和学习 http://mp.weixin.qq.com/s?__biz=MzAxOTAzMDEwMA==&mid=2652500597&idx=1& ...

  9. 由<a href = "#" > 引发的思考

    原文:由<a href = "#" > 引发的思考 前阵子在一个移动项目中,通过 <a href = "#" >  的方式 绑定clic ...

随机推荐

  1. Hibernate Generic DAO的介绍安装和使用

    java 的包挺多,比c#多 . jar包一个名,解压缩出来又出来又叫另一个名 .搜索起来,内容都分散的很 http://mvnrepository.com  maven库搜索 com.googlec ...

  2. CSS 样式中的两个方法

    在很多时候,我们需要LI开头空一点距离.结尾不能再有下划线了.这个效果在以前是很难实现的.但是有了下面两个选择器,非常容易做出这种东西. .slideTxtBox .bd ul > :first ...

  3. Git 在团队中的使用--如何正确使用Git Flow

    Git的优点 Git的优点很多,但是这里只列出我认为非常突出的几点. 由于是分布式,所有本地库包含了远程库的所有内容. 优秀的分支模型,打分支以及合并分支,机器方便. 快速,在这个时间就是金钱的时代, ...

  4. 找不到phpize

    yum install php-devel 报错如下: 解决办法: yum install php71w-devel

  5. python requests 模块

    requests 是第三方 python 库,用于处理 url 资源 requests 项目官网:http://www.python-requests.org/en/master/ 安装方式:pip ...

  6. boost asio 学习(三)post与dispatch

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg=4 本章节为io_ ...

  7. python爬虫笔记

    1.抓取网页并保存到txt中.解决控制台乱码问题 #_*_coding:utf-8_*_ import urllib2 response = urllib2.urlopen('http://hws.m ...

  8. Delphi过程和函数中变量的作用域

    变量的作用域是指变量能被某一子程序识别的范围. 全局变量和局部变量.全局变量是指在程序的type区定义的变量,而局部变量是在过程或函数的定义部分声明的变量.全局变量在整个程序中都有意义,局部变量只在它 ...

  9. java多线程系列12 ConcurrentHashMap CopyOnWriteArrayList 简介

    我们知道 ,hashmap 和 arraylist 是线程不安全的 在多线程环境下有数据安全问题, 当然 我们可以通过Collections的一些方法把他们变成线程安全的, Collections.s ...

  10. Oracle使用JDBC进行增删改查 表是否存在

    Oracle使用JDBC进行增删改查 数据库和表 table USERS (   USERNAME VARCHAR2(20) not null,   PASSWORD VARCHAR2(20) ) a ...