前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >apache-commons家族的八兄弟(上)

apache-commons家族的八兄弟(上)

作者头像
lyb-geek
发布2022-03-10 13:52:05
4620
发布2022-03-10 13:52:05
举报
文章被收录于专栏:Linyb极客之路

Apache Commons包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动。篇幅很长所以拆分为两篇。

组件

功能介绍

beanUtils

提供了对于JavaBean进行各种操作,克隆对象,属性等等.

codec

处理常用的编码方法的工具类包 例如DES、SHA1、MD5、Base64等.

collections

java集合框架操作.

configuration

一个java应用程序的配置管理类库.

io

io工具的封装.

lang

Java基本对象方法的工具类包 如:StringUtils,ArrayUtils等等.

logging

提供的是一个Java 的日志接口.

net

提供了客户端和服务器端的数据验证框架.

老大:commons-beanUtils

Commons BeanUtils一共包括如下5个包:

org.apache.commons.beanutils – 核心包,定义一组 Utils 类和需要用到的接口规范

org.apache.commons.beanutils.converters – 转换 String 到需要类型的类,实现 Converter 接口

org.apache.commons.beanutils.locale –beanutils 的 locale 敏感版本

org.apache.commons.beanutils.locale.converters– converters 的 locale 敏感版本

org.apache.commons.collections – beanutils 使用到的 Collection 类

其中需要我们特别关注的是这个org.apache.commons.beanutils包,其他包都是起辅助作用的。接下来我们就仔细看一看这个包都有些什么东东:

4个接口

1.Converter

该接口定义了如下方法:

代码语言:javascript
复制
public java.lang.Object convert(java.lang.Class type, java.lang.Object value);

只要实现了这个Converter接口并注册到ConvertUtils类即可被我们的BeanUtils包所使用,它的主要目的是提供将给定的Object实例转换为目标类型的算法。我们可以在beanutils.converters包中找到相当多的已经实现的转换器。

2.DynaBean

该接口定义的是一个动态的JavaBean,它的属性类型、名称和值都是可以动态改变的。

3.DynaClass

该接口定义的是针对实现了DynaBean接口的类的java.lang.Class对象,提供如getName()、newInstance()等方法。

4.MutableDynaClass

该接口是对DynaClass的扩展,使得动态bean的属性可以动态增加或删除。

24个类

BasicDynaBean

DynaBean接口的最精简实现

BasicDynaClass

DynaClass接口的最精简实现

BeanUtils

提供通过反射机制填写JavaBeans属性的工具/静态方法

BeanUtilsBean

BeanUtils类的实例化实现,区别于BeanUtils的静态方法方式,使得自定义的配置得以保持

ConstructorUtils

同MethodUtils类似,不过专注于构造方法

ContextClassLoaderLocal

针对每个classloader的唯一标识

ConvertingWrapDynaBean

包含了标准JavaBean实例的DynaBean实现,使得我们可以使用DynaBean的API来访问起属性,同时提供设定属性时的类型转换,继承自并区别于WrapDynaBean

ConvertUtils

提供工具/静态方法,用于将String对象及其数组转换为指定的类型的对象及其数组

ConvertUtilsBean

ConvertUtils类的实例化实现,区别于ConvertUtils的静态方法方式,使得自定义的配置得以保持

DynaProperty

用于描述DynaBean的属性

JDBCDynaClass

为DynaClass的JDBC实现提供公用的逻辑

LazyDynaBean

懒载入DynaBean,自动往DynaClass添加属性并提供懒载入List和懒载入Map的功能

LazyDynaClass

实现MutableDynaClass接口的类

LazyDynaMap

为Map实例提供一个轻量级的DynaBean包装

MappedPropertyDescriptor

用于描述映射的属性

MethodUtils

包含了针对一般意义上的方法而非特定属性的反射工具/静态方法

MethodUtils.MethodDescriptor

描述通过反射查找某个方法所使用的键值

PropertyUtils

提供利用Java反射API调用具体对象的getter和setter的工具/静态方法

PropertyUtilsBean

PropertyUtils类的实例化实现,区别于PropertyUtils的静态方法方式,使得自定义的配置得以保持

ResultSetDynaClass

包装java.sql.ResultSet中的java.sql.Row实例的DynaBean所对应的DynaClass实现

ResultSetIterator

针对ResultSetDynaClass的java.util.Iterator实现

RowSetDynaClass

DynaClass的一种实现,用于在内存中创建一组表示SQL查询结果的DynaBeans,区别于ResultSetDynaClass,它不需要保持ResultSet打开

WrapDynaBean

DynaBean的一种实现,包含一个标准的JavaBean实例,以便我们可以使用DynaBean的API去访问它的属性,区别于ConvertingWrapDynaBean,它不做专门的类型转换

WrapDynaClass

DynaClass的一种实现,针对那些包装标准JavaBean实例的DynaBeans

只要把握好BeanUtils本身要完成的事,就不难理解这些类存在的道理。我们不妨把BeanUtils的基础应用分解成:访问JavaBean的属性、设定JavaBean的属性、以及创建和使用DynaBeans。

代码示例

假定我们有如下两个标准的JavaBean:

代码语言:javascript
复制
//地址类
public class Address {
    private String zipCode;
    private String addr;
    private String city;
    private String country;
    public Address() {}
    public Address(String zipCode, String addr,String city, String country) {
        this .zipCode = zipCode;
        this .addr = addr;
        this .city = city;
        this .country = country;
    }
   //get-set method
}

//顾客类
public class Customer {
    private long id;
    private String name;
    private Address[] addresses;
    public Customer() {
    }
    public Customer( long id, String name, Address[]addresses) {
        this .id = id;
        this .name = name;
        this .addresses = addresses;
    }
   //get-set method
}

我们来看看通常我们是怎样利用Commons BeanUtils来完成一些基本的JavaBean和DynaBean操作:

代码语言:javascript
复制
public class BeanUtilsUsage {
    public static void main(String[] args) throws Exception {
        demoNormalJavaBeans();
        demoDynaBeans();
    }
    public static void demoNormalJavaBeans() throws Exception {
        System.out.println(StringUtils.center( " demoNormalJavaBeans " , 40, "=" ));
        // data setup
        Address addr1 = new Address( "CA1234" , "xxx" , "Los Angeles" , "USA" );
        Address addr2 = new Address( "100000" , "xxx" , "Beijing" , "China" );
        Address[] addrs = new Address[2];
        addrs[0] = addr1;
        addrs[1] = addr2;
        Customer cust = new Customer(123, "John Smith" , addrs);
        // accessing the city of first address
        String cityPattern = "addresses[0].city" ;
        String name =        (String)PropertyUtils.getSimpleProperty(cust, "name" );
        String city = (String)PropertyUtils.getProperty(cust, cityPattern);
        Object[] rawOutput1 = new Object[] { "The city of customer " ,name,
                "'sfirst address is " , city, "." };
        System.out.println(StringUtils.join(rawOutput1));
        // setting the zipcode of customer'ssecond address
        String zipPattern = "addresses[1].zipCode" ;
        if (PropertyUtils.isWriteable(cust, zipPattern)){
            System.out.println( "Setting zipcode ..." );
            PropertyUtils.setProperty(cust,zipPattern, "200000" );
        }
        String zip = (String)PropertyUtils.getProperty(cust, zipPattern);
        Object[] rawOutput2 = new Object[] { "The zipcode of customer " ,name,
                "'ssecond address is now " , zip, "." };
        System.out.println(StringUtils.join(rawOutput2));
        System.out.println();
    }
    public static void demoDynaBeans() throws Exception {
        System.out.println(StringUtils.center( " demoDynaBeans " , 40, "=" ));
        // creating a DynaBean
        DynaProperty[] dynaBeanProperties = new DynaProperty[] {
                new DynaProperty( "name" , String.class),
                new DynaProperty( "inPrice" , Double.class), 
                new DynaProperty( "outPrice" , Double.class),
        };
        BasicDynaClass cargoClass = new BasicDynaClass( "Cargo" ,BasicDynaBean.class, dynaBeanProperties);
        DynaBean cargo =cargoClass.newInstance();
        // accessing a DynaBean
        cargo.set( "name" , "Instant Noodles" );
        cargo.set( "inPrice" ,new Double(21.3));
        cargo.set( "outPrice" ,new Double(23.8));
        System.out.println( "name: " + cargo.get( "name" ));
        System.out.println( "inPrice: " + cargo.get( "inPrice" ));
        System.out.println( "outPrice: " + cargo.get( "outPrice" ));
        System.out.println();
    }
}

运行结果:

代码语言:javascript
复制
=========demoNormalJavaBeans ==========
The city of customerJohn Smith's first address is Los Angeles.
Setting zipcode ...
The zipcode ofcustomer John Smith's second address is now 200000.
============demoDynaBeans =============
name: InstantNoodles
inPrice: 21.3
outPrice: 23.8

老2:commons-codec

commons-codec是Apache开源组织提供的用于摘要运算、编码的包。在该包中主要分为四类加密:BinaryEncoders、DigestEncoders、LanguageEncoders、NetworkEncoders。

为大家介绍一下如何用commons-codec包完成常见的编码、摘要运算。

base64

代码语言:javascript
复制
@Test
public void testBase64(){
    System.out.println("==============Base64================");
    byte[] data = "imooc".getBytes();
    Base64 base64 = new Base64();
    String encode = base64.encodeAsString(data);
    System.out.println(encode);
    System.out.println(new String(base64.decode(encode)));
}

运行结果:

代码语言:javascript
复制
==============Base64================
amlhbmdndWppbg==
imooc

MD5

代码语言:javascript
复制
@Test
public void testMD5(){
    System.out.println("==============MD5================");
    String result = DigestUtils.md5Hex("imooc");
    System.out.println(result);
}

运行结果:

代码语言:javascript
复制
acab4efdfd3b8efcdec37fe160d7be0e

SHA等摘要运算和MD5类似。

URLCode

代码语言:javascript
复制
@Test
public void testURLCodec() throws Exception{
    System.out.println("==============URLCodec================");
    URLCodec codec = new URLCodec();
    String data = "imooc";
    String encode = codec.encode(data, "UTF-8");
    System.out.println(encode);
    System.out.println(codec.decode(encode, "UTF-8"));
}

运行结果:

代码语言:javascript
复制
==============URLCodec================
%E8%92%8B%E5%9B%BA%E9%87%91
imooc

老三:commons-collections

Commons Collections,又是一个重量级的东西,为Java标准的Collections API提供了相当好的补充。Collections当然有它存在的道理,能够把常用的数据结构归纳起来,以通用的方式去维护和访问,这应该说是一种进步,但是用起来似乎不够友好。这个时候我就会想,如果Java比现在做得更好用些,或者有一套第三方的API把我的这些需求抽象出来,实现了,该多好。Commons Collections就是这样一套API。

org.apache.commons.collections

此包包含在此组件的所有子包中共享的接口和实用程序。

org.apache.commons.collections.bag

该包包含 Bag和 SortedBag接口的实现。

org.apache.commons.collections.bidimap

这个软件包包含的实现 BidiMap, OrderedBidiMap和 SortedBidiMap接口。

org.apache.commons.collections.buffer

该包包含Buffer接口的实现 。

org.apache.commons.collections.collection

该包包含Collection接口的实现 。

org.apache.commons.collections.comparators

该包包含Comparator接口的实现 。

org.apache.commons.collections.functors

这个软件包包含的实现 Closure, Predicate, Transformer和 Factory接口。

org.apache.commons.collections.iterators

该包包含Iterator接口的实现 。

org.apache.commons.collections.keyvalue

此包包含集合和映射相关键/值类的实现。

org.apache.commons.collections.list

该包包含List接口的实现 。

org.apache.commons.collections.map

这个软件包包含的实现 Map, IterableMap, OrderedMap和 SortedMap接口。

org.apache.commons.collections.set

该包包含 Set和 SortedSet接口的实现。

用过Java Collections API的朋友大概或多或少会同意我如下的划分:在Java的Collections API中,不狭义的区分语法上的接口和类,把它们都看作是类的话,大致我们可以发现三种主要的类别:

1.容器类:如Collection、List、Map等,用于存放对象和进行简单操作的;

2.操作类:如Collections、Arrays等,用于对容器类的实例进行相对复杂操作如排序等;

3.辅助类:如Iterator、Comparator等,用于辅助操作类以及外部调用代码实现对容器类的操作,所谓辅助,概括而通俗的来讲,就是这些类提供一种算法,你给它一个对象或者一组对象,或者仅仅是按一定的规则调用它,它给你一个运算后的答案,帮助你正确处理容器对象。比如Iterator会告诉你容器中下一个对象有没有、是什么,而Comparator将对象大小/先后次序的算法逻辑独立出来。

list包中的方法Commons Collections在java.util.Map的基础上扩展了很多接口和类,比较有代表性的是BidiMap、MultiMap和LazyMap。跟Bag和Buffer类似,Commons Collections也提供了一个MapUtils。

所谓BidiMap,直译就是双向Map,可以通过key找到value,也可以通过value找到key,这在我们日常的代码-名称匹配的时候很方便:因为我们除了需要通过代码找到名称之外,往往也需要处理用户输入的名称,然后获取其代码。需要注意的是BidiMap当中不光key不能重复,value也不可以。

所谓MultiMap,就是说一个key不在是简单的指向一个对象,而是一组对象,add()和remove()的时候跟普通的Map无异,只是在get()时返回一个Collection,利用MultiMap,我们就可以很方便的往一个key上放数量不定的对象,也就实现了一对多。

所谓LazyMap,意思就是这个Map中的键/值对一开始并不存在,当被调用到时才创建,这样的解释初听上去是不是有点不可思议?这样的LazyMap有用吗?我们这样来理解:我们需要一个Map,但是由于创建成员的方法很“重”(比如数据库访问),或者我们只有在调用get()时才知道如何创建,或者Map中出现的可能性很多很多,我们无法在get()之前添加所有可能出现的键/值对,或者任何其它解释得通的原因,我们觉得没有必要去初始化一个Map而又希望它可以在必要时自动处理数据生成的话,LazyMap就变得很有用了。

Collection包下的方法中首先就是这个TypedCollection,它实际上的作用就是提供一个decorate方法,我们传进去一个Collection和需要的类型甄别信息java.lang.Class,它给我们创建一个全新的强类型的Collection。我们其实在bag、buffer、list、map、set这些子包中都可以找到分别对应Bag、Buffer、List、Map、Set接口的TypedXxxx版本。

Bag是在org.apache.commons.collections包中定义的接口,它extends java.util.Collection,而它的实现类都被放在下面的bag包中。之所以有这样一组类型,是因为我们有时候需要在Collection中存放多个相同对象的拷贝,并且需要很方便的取得该对象拷贝的个数。需要注意的一点是它虽然extends Collection,但是如果真把它完全当作java.util.Collection来用会遇到语义上的问题,详细信息参考Javadoc。

HashBag是Bag接口的一个标准实现。而BagUtils提供一组static的方法让调用者获取经过不同装饰后的Bag实例。

Buffer是定义在org.apache.commons.collections包下面的接口,用于表示按一定顺序除去成员对象的collection如队列等。具体的实现类在org.apache.commons.collections.buffer包下可以找到。

BufferUtils提供很多静态/工具方法装饰现有的Buffer实例,如将其装饰成BlockingBuffer、执行类型检查的TypedBuffer、或者不可改变的UnmodifiableBuffer等等。

最简单直接的Buffer实现类是UnboundedFifoBuffer,提供先进先出的大小可变的队列。而BoundedFifoBuffer则是对其大小进行了限制,是固定大小的先进先出队列。BlockingBuffer要在多线程的环境中才能体现出它的价值,尤其是当我们需要实现某种流水线时这个BlockingBuffer很有用:每个流水线上的组件从上游的BlockingBuffer获取数据,处理后放到下一个BlockingBuffer中依次传递。BlockingBuffer的核心特色通俗点说就是如果你向它要东西,而它暂时还没有的话,你可以一直等待直至拿到为止。PriorityBuffer则提供比一般的先进先出Buffer更强的控制力:我们可以自定义Comparator给它,告诉它怎么判定它的成员的先后顺序,优先级最高的最先走。

Comparator包已经明确定了一个java.util.Comparator接口,只是有很多人并不了解,Commons Collections也只是扩展了这个接口而已。这个java.util.Comparator定义如下核心方法:

代码语言:javascript
复制
public int compare(Object arg0, Object arg1)

传给它两个对象,它要告诉我们这两个对象哪一个在特定的语义下更“大”,或者两者相等。如果arg0 > arg1,返回大于0的整数;如果arg0 = arg1,返回0;如果arg0 < arg2,返回小于0的整数。

我们看看Commons Collections给我们提供了哪些Comparator的实现类(都在org.apache.commons.collections.comparators包下面):

BooleanComparator – 用于排序一组 Boolean 对象,指明先 true 还是先 false ;

ComparableComparator – 用于排序实现了 java.lang.Comparable 接口的对象(我们常用的 Java 类如 String 、 Integer、 Date 、 Double 、 File 、 Character 等等都实现了 Comparable 接口);

ComparatorChain – 定义一组 Comparator 链,链中的 Comparator 对象会被依次执行;

FixedOrderComparator – 用于定义一个特殊的顺序,对一组对象按照这样的自定义顺序进行排序;

NullComparator – 让 null 值也可参与比较,可以设定为先 null 或者后 null ;

ReverseComparator – 将原有的 Comparator 效果反转;

TransformingComparator – 将一个 Comparator 装饰为具有 Transformer 效果的 Comparator 。

// 有关 Transformer 的内容会在以后的笔记中讲到。

以上除了ComparatorChain之外,似乎都是实现一些很基本的比较方法,但是当我们用ComparatorChain将一组Comparator串起来之后,就可以实现非常灵活的比较操作。

在Predicate包中Predicate是Commons Collections中定义的一个接口,可以在org.apache.commons.collections包中找到。其中定义的方法签名如下:

代码语言:javascript
复制
public boolean evaluate(Object object)

它以一个Object对象为参数,处理后返回一个boolean值,检验某个对象是否满足某个条件。其实这个Predicate以及上一篇笔记提到的Comparator还有我们即将看到的Transformer和Closure等都有些类似C/C++中的函数指针,它们都只是提供简单而明确定义的函数功能而已。

跟其他组类似,Commons Collections也提供了一组定义好的Predicate类供我们使用,这些类都放在org.apache.commons.collections.functors包中。当然,我们也可以自定义Predicate,只要实现这个Predicate接口即可。在Commons Collections中我们也可以很方便使用的一组预定义复合Predicate,我们提供2个或不定数量个Predicate,然后交给它,它可以帮我们处理额外的逻辑,如AndPredicate处理两个Predicate,只有当两者都返回true它才返回true;AnyPredicate处理多个Predicate,当其中一个满足就返回true,等等。

而我们有时候需要将某个对象转换成另一个对象供另一组方法调用,而这两类对象的类型有可能并不是出于同一个继承体系的,或者说出了很基本的Object之外没有共同的父类,或者我们根本不关心他们是不是有其他继承关系,甚至就是同一个类的实例只是对我们而言无所谓,我们为了它能够被后续的调用者有意义的识别和处理,在这样的情形,我们就可以利用Transformer。除了基本的转型Transformer之外,Commons Collections还提供了Transformer链和带条件的Transformer,使得我们很方便的组装出有意义的转型逻辑。

Closure这一组接口和类提供一个操作对象的execute方法,为我们在处理一系列对象时可以将处理逻辑分离出来。理论上讲,使用Transformer也可以达到类似的效果,只要输出对象和输入对象是同一个对象就好,但是Closure接口定义的execute方法返回void,并且从效果和功能区分上,Closure可以更好的诠释对象处理或执行的意思。而事实上,ClosureUtils中也提供了一个asClosure方法包装一个现成的Transformer。

最后提到的java.util.Iterator接口定义了标准的Collection遍历方法,但是如果不做改变的使用它,我们得到的是从头到尾一次性的遍历。假如我们需要循环遍历,假如我们需要遍历某一段,假如我们需要遍历满足某些条件的元素,等等等等,我们就不能完全依赖于这个Iterator的标准实现了。除非我们宁可在此基础上在调用的代码中多加一些判断,不过这样的话代码就会显得混乱,时间长了就容易变得难以维护。Commons Collections的这一组Iterator为我们带来了便利。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-02-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linyb极客之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 老大:commons-beanUtils
    • 4个接口
      • 24个类
      • 代码示例
      • 老2:commons-codec
      • 老三:commons-collections
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档