ApacheCommons常用工具类使用

Apache Commons 项目包含了很多工具,并且非常好用,能提高我们的开发效率,在很多开源框架中使用广泛,所以….如果项目中引入了这些依赖,能用就用吧,起码 Apache 的应该是比自己写的强多了。。
另外,Google 的 Guava 也是非常好用的,也做了笔记,地址在这里
常用工具一览表:

组件功能介绍
BeanUtils提供了对于JavaBean进行各种操作,克隆对象,属性等等.
BetwixtXML与Java对象之间相互转换.
Codec处理常用的编码方法的工具类包 例如 DES、SHA1、MD5、Base64 等.
Collectionsjava集合框架操作.
Compressjava提供文件打包压缩类库.
Configuration一个java应用程序的配置管理类库.
DBCP提供数据库连接池服务.
DbUtils提供对jdbc 的操作封装来简化数据查询和记录读取操作.
Emailjava 发送邮件对 javamail 的封装.
FileUpload提供文件上传功能.
HttpClien提供 HTTP 客户端与服务器的各种通讯操作. 现在已改成 HttpComponents
IOio 工具的封装.
LangJava 基本对象方法的工具类包 如:StringUtils,ArrayUtils 等等.
Logging提供的是一个 Java 的日志接口.
Validator提供了客户端和服务器端的数据验证框架.

BeanUtils

提供了对于 JavaBean 进行各种操作,比如对象,属性复制等等。

克隆对象: Person person2 = (Person)BeanUtils.cloneBean(person);

需要注意的是,cloneBean 方法拷贝对象只是浅拷贝,如果想深拷贝,可参考下面的代码

经测试,这种克隆效率很低,并且不是很稳定,推荐优先使用 Spring 的 BeanUtils 通过属性 copy 的方式来“克隆对象”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class JavaBeanCopier {
/**
* Returns a deeply cloned java bean.
*
* @param fromBean java bean to be cloned.
* @return a new java bean cloned from fromBean.
*/
public static Object copy(Object fromBean) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
XMLEncoder out = new XMLEncoder(bos);
out.writeObject(fromBean);
out.close();
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
XMLDecoder in = new XMLDecoder(bis);
Object toBean = in.readObject();
in.close();
return toBean;
}
}

将一个 Map 对象转化为一个 Bean:
首先这个 Map 对象的 key 必须与 Bean 的属性相对应:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Map map = new HashMap();
map.put("name","tom");
map.put("email”,”[email protected]");
map.put("age”,”21");

//将map转化为一个Person对象
Person person = new Person();
BeanUtils.populate(person,map);

// web 中示例
Enumeration params = request.getParameterNames();
while (params.hasMoreElements()){
String name = (String) params.nextElement();
map.put(name, request.getParameter(name));
}

// bean 转 map
Map map = BeanUtils.describe(person);

使用场景嘛…..如果不使用 web 层框架,还记得被 request.getParameter 支配的恐惧….


bean 的属性拷贝:

在拼装 VO 或者 DTO 的时候非常有用吧:BeanUtils.copyProperties(source, target);

需要注意的是,除了属性名要一致,属性拷贝同时也会将值为 null 的属性拷贝,所以,这行代码放的位置很重要!


其他常用:

1
2
3
4
5
6
7
8
9
10
11
12
Person p = new Person(new Book());
// 使用beanUtils给对象的属性赋值
BeanUtils.setProperty(p, "username", "张三");

// 使用beanUtils获取对象的属性值
System.out.println(BeanUtils.getProperty(p, "username"));

// beanUtils 支持属性链赋值与获得值,不过赋值前 book 要先实例化
BeanUtils.setProperty(p, "book.name", "历史小说");

System.out.println(BeanUtils.getProperty(p, "book.name"));
System.out.println(p.getBook().getName());

Codec

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

  • DigestUtils
    主要包括 MD5、SHA1、SHA256 算法等实现静态方法
  • Base64
    主要包含 Base64 编码和解码静态方法

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
public class CodecTest{
/**
* MD5散列算法实现(长度有16位和32位,常用32位的)
*/
@Test
public void testMD5(){
String data = "hello";
String md5String = DigestUtils.md5Hex(data);
System.out.println(md5String);
}

/**
* SHA1散列算法实现(长度为40位)
*/
@Test
public void testSHA1(){
String data = "hello";
String sha1String = DigestUtils.sha1Hex(data);
System.out.println(sha1String.length());
}

/**
* SHA256散列算法实现(长度为64位)
*/
@Test
public void testSHA256(){
String data = "hello";
String sha256String = DigestUtils.sha256Hex(data);
System.out.println(sha256String.length());
}

/**
* 摘要算法
*/
@Test
public void testDigestAlgorithms(){
// 摘要算法在 MessageDigestAlgorithms 下有列出
// public static final String MD2 = "MD2";
// public static final String MD5 = "MD5";
// public static final String SHA_1 = "SHA-1";
// public static final String SHA_256 = "SHA-256";
// public static final String SHA_384 = "SHA-384";
// public static final String SHA_512 = "SHA-512";

// 备注:都是基于 HASH 算法实现的
}

/**
* 使用Base64类进行编码和解码,注意其可以转换二进制数据到字符串(比如图片转字符串)
*
* 如果是小图片的话,可以使用Base64编码来存储,只是可以并不是推荐使用。
*/
@Test
public void testBase64(){
String encodeString = Base64.encodeBase64String("hello".getBytes());
System.out.println(encodeString);
byte[] bytes = Base64.decodeBase64(encodeString);

System.out.println(new String(bytes));
}

/**
* 使用Base64将图片编码为字符串
*/
@Test
public void image2String() throws Exception{
FileInputStream inputStream = new FileInputStream("e:/test.jpg");

// 借助Commons IO 组件的IOUtils静态方法将输入流转为子节数组
byte[] imageBytes = IOUtils.toByteArray(inputStream);
String imageString = Base64.encodeBase64String(imageBytes);

System.out.println(imageString);
}

/**
* 使用Base64将字符串解码为图片
*/
@Test
public void string2Image() throws Exception{
FileInputStream inputStream = new FileInputStream("e:/test.jpg");
// 借助Commons IO 组件的IOUtils静态方法将输入流转为子节数组
byte[] imageBytes = IOUtils.toByteArray(inputStream);
String imageString = Base64.encodeBase64String(imageBytes);

FileOutputStream outputStream = new FileOutputStream("e:/testCopy.jpg");

byte[] bytes = Base64.decodeBase64(imageString);
// 借助Commons IO 组件的IOUtils静态方法将字节数组转为输出流
IOUtils.write(bytes, outputStream);
}
}

然后再补充一个 URL 的编码和解码:

1
2
3
4
5
6
7
8
9
@Test
public void testURLCodec() throws Exception {
System.out.println("==============URLCodec================");
URLCodec codec = new URLCodec();
String data = "啦啦啦";
String encode = codec.encode(data, "UTF-8");
System.out.println(encode);
System.out.println(codec.decode(encode, "UTF-8"));
}

Collections

对 Java 中的集合类进行了一定的补充,定义了一些全新的集合,当然也是实现了 Collection 接口的,比如Bag,BidiMap
同时拥有新版本的原有集合,比如 FastArrayList。最后,更为重要的是一系列 utils 类,提供了我们常用的集合操作,可以大大方便我们的日常编程。

Bag

Bag 定义了一种集合:收集一个对象出现的次数。
例如 Bag:{a,a,b,c} 调用 bag.getCount(a) 返回 2,意味着里面有 2 个 a。 调用 bag.uniqueSet() 则返回一个 set,值为 {a,b,c}。

1
2
3
4
5
6
7
8
9
10
// 例子
HashBag bag = new HashBag();
bag.add("rabbit",1);
bag.add("fox",1);
bag.add("rabbit",2);

// rabbit count
System.out.print(bag.getCount("rabbit"));
// how many animals
System.out.print(bag.uniqueSet().size());

除了 HashBag,还有 SynchronizedBag、TreeBag,自行了解哈….

BidiMap

BidiMap 定义了一种 map,不仅可以通过 key 得到 value,还可以通过 value 得到 key。
Bidi 意思是 bidirectional,双向使用的 map。
除了传统 Map 的操作,还加入了一些新”技能“:

1
2
3
4
5
6
7
8
BidiMap bidi = new DualHashBidiMap();
bidi.put("k1","v1");
bidi.put("k2","v2");

bidi.get("k2"); // return v2
bidi.getKey("v2"); // return k2

bidi.inverseBidiMap(); // 反转 bidi,原先的 value 作为 key

作为代价,BidiMap 必须要求 k 和 v 是一一对应的,在上述代码之后,无法做到 bidi.put("k2","v1");,因为这样就无法实现响应操作。 现实中如学号和身份证号做对应就是这样一种关系,可以视情况使用。
同样,除了 DualHashBidiMap,还有 TreeBidiMap 等

有用的工具类

这是 collections 包中最有价值的一个部分,介绍 ListUtilsCollectionUtils

ListUtils 列表工具类

  • ListUtils.intersection(list1, list2)
    取交集;
  • ListUtils.subtract(list1, list2)
    返回 list1 和 list2 的差。这里和 list1.removeAll(list2) 的差别在于:
    前者不改变任何一个集合;
    如果 list1 中有 2 个 a,list2 中有一个a:removeAll 会将 list1 中所有的 a 都抹去,而 subtract 结果 list1 仍然会剩下一个 a。
  • ListUtils.union(list1, list2)
    取并集;
  • ListUtils.removeAll(list1, list2)
    不改变 list 的情况下做 removeAll

CollectionUtils 通用的集合工具类

  • CollectionUtils.union(c1, c2),CollectionUtils.intersection(c1,c2)
    不再解释
  • CollectionUtils.disjunction(c1, c2)
    返回两者的不相交部分的并集,没想到一个现实场景。。
  • CollectionUtils.containsAny(c1, c2)
    只要 c1 包含任何一个 c2 的元素,返回 true
  • CollectionUtils.find(c, predicate)
    重要方法:借助 Predicate 达到神一般的效果,从此减少一半 for 循环。返回第一个找到的元素
  • CollectionUtils.filter(c, predicate)
    重要方法:同上,直接改变容器 c。
  • CollectionUtils.transform(c, transformer)
    重要方法:还是神器,但是在 jdk8 中等同于 foreach 方法效果。如果 jdk<8,可以用这个方法代替
  • CollectionUtils.countMatches(c,predicate)
    根据 predicate 返回有多少元素满足预言,返回值 int。
  • CollectionUtils.select(c,predicate)
    根据 predicate 找出满足的元素,组成新的 collection 并返回
  • CollectionUtils.select(c,predicate,outputCollection)
    根据 predicate 找出满足的元素,加入到 outputCollection 中。
  • CollectionUtils.isEmpty(c)
    简单实用,是否为 null 或者空集合

补充:predicate

既然上面用到了还是说一说,感觉自从 JDK8 来了后,能省一大部分工具类了。。。
预言,这个类主要结合 CollectionUtils.find,CollectionUtils.filter 来使用。
他的作用类似于『断言』,其中只有一个方法:public boolean evaluate(Object object);
这个方法用于判断一个对象是否满足某种标准,感觉和 JDK8 中的 stream + map 差不多呢~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 一个例子
Predicate predicate = new Predicate{
@override
public boolean evaluate(Object object){
return PropertyUtils.getSimpleProperty(object,"age") >50 ;
}
}
Predicate predicate2 = new Predicate{
@override
public boolean evaluate(Object object){
return PropertyUtils.getSimpleProperty(object,"id") == 12306 ;
}
}

//删除不满足条件的结果
CollectionUtils.filter(list,predicate);
//返回第一个满足的元素
Object obj = CollectionUtils.find(list,predicate2);

// new AndPredicate(predicate1,predicate2);

同时,Predicate 可以进行谓词连接,借助于:AndPredicate、OrPredicate、AnyPredicate、NotPredicate 这些类。

Long

提供了很多安全操作和工具类,避免我们编码校验各种的 null;
JDK8+ 后,对空值处理有了加强,但是嘛,国内用的人…..

  • ArrayUtils:
    数组工具类,提供数组拷贝、查找、反转等功能
  • StringUtils:
    提供字符串操作,对 null 是安全的,字符串查找、替换、分割、去空格等操作;
    isEmpty 和 isBlank 的区别在于 isEmpty 不会忽略空格,而isBlank会认为是空,isBlank更常用
  • ObjectUtils:
    对 null 进行安全处理
  • RandomUtils:
    随机数工具类,获得随机整数、小数、字符串等
  • NumberUtils:
    数值工具类,数值类型转换等操作
  • DateUtils:
    日期工具类
  • EnumUtils:
    枚举工具类
  • ClassUtils
    判断是否有内部类、是否可以转型、获取包名、类名等
  • ReflectionToStringBuilder/ToStringBuilder:
    重写 toString 方法
  • EqualsBuilder/HashCodeBuilder:
    提供了方便的方法来覆盖 equals() 和 hashCode() 方法

然后给一些示例代码吧,比如 Builder 系列,虽然一般我们都是工具自动生成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//ToStringBuilder  
@Override
public String toString() {
return new ToStringBuilder(this).append(this.getId())
.append(this.getUsername()).toString();
}

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
// 以上输出格式为 [email protected][<null>,<null>]

// HashCodeBuilder
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}

@Override
public int hashCode() {
return new HashCodeBuilder(this).append(this.getId())
.append(this.getUsername()).hashCode();
}

// EqulasBuilder
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj.getClass() == Test.class) {
Test test = (Test) obj;
return new EqualsBuilder().append(this.getId(), test.getId())
.append(this.getUsername(), test.getUsername()).isEquals();
}
return false;
}

@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}

// CompareToBuilder
@Override
public int compareTo(Test o) {
return CompareToBuilder.reflectionCompare(this, o);
}

@Override
public int compareTo(Test o) {
return new CompareToBuilder().append(this.getId(), o.getId())
.append(this.getUsername(), o.getUsername()).toComparison();
}

除了上面列举的,还有很多工具类,大部分也不说了,看一下方法基本就会用了,非常简单,看例子可去参考的第二个链接。
然后是日期,稍微提一下,也不常用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class TestMain {
public static void main(String[] args) throws IllegalAccessException {
Date day1 = new Date();
/*
* 由于 Aache 的 DateUtils 和 DateFormatUtils 并没有 Joda 强大,
* 所以在这里只作简单的示例
*/

// 增加一天
DateUtils.addDays(day1, 1);
// 减少一年
DateUtils.addYears(day1, -1);

// 格式化时间,第三参数为国际化,表示按美国时间显示
DateFormatUtils.format(day1, "yyyy-MM-dd", Locale.UK);
}
}

IO

看名字也知道,这是用来操作文件的工具类,工具类包括 FileUtils、IOUtils、FilenameUtils 和 FileSystemUtils,前三者的方法并没有多大的区别,只是操作的对象不同;
故名思议:FileUtils 主要操作 File 类,IOUtils 主要操作 IO 流,FilenameUtils 则是操作文件名,FileSystemUtils 包含了一些 JDK 没有提供的用于访问文件系统的实用方法。当前,只有一个用于读取硬盘空余空间的方法可用。
果然还是例子最能说明问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
public class FileUtilsTest {
private String basePath = null;

@Before
public void setUp() {
basePath = System.getProperty("user.dir") + "\\file\\";
}

/**
* 拷贝文件
*/
@Test
public void testCopy() throws IOException {
File srcFile = new File(basePath + "a.txt");
File destFile = new File(basePath + "b.txt");
FileUtils.copyFile(srcFile, destFile);
}

/**
* 删除文件
*/
@Test
public void testDelete() throws IOException {
File delFile = new File(basePath + "b.txt");
FileUtils.forceDelete(delFile);
//FileUtils.forceMkdir(delFile);
}

/**
* 比较文件内容
*/
@Test
public void testCompareFile() throws IOException {
File srcFile = new File(basePath + "a.txt");
File destFile = new File(basePath + "b.txt");
boolean result = FileUtils.contentEquals(srcFile, destFile);
System.out.println(result);
}

/**
* 移动文件
*/
@Test
public void testMoveFile() throws IOException {
File srcFile = new File(basePath + "b.txt");
File destDir = new File(basePath + "move");
FileUtils.moveToDirectory(srcFile, destDir, true);
}

/**
* 读取文件内容
*/
@Test
public void testRead() throws IOException {
File srcFile = new File(basePath + "a.txt");
String content = FileUtils.readFileToString(srcFile);
List<String> contents = FileUtils.readLines(srcFile);
System.out.println(content);
System.out.println("******************");
for (String string : contents) {
System.out.println(string);
}
}

/**
* 写入文件内容
*/
@Test
public void testWrite() throws IOException {
File srcFile = new File(basePath + "a.txt");
FileUtils.writeStringToFile(srcFile, "\nyes文件", true);
}
}

public class FileSystemUtilsTest {
/**
* 获取磁盘空余空间
*/
@SuppressWarnings("deprecation")
@Test
public void testFreeSpace() throws IOException {
// 以字节为单位
System.out.println(FileSystemUtils.freeSpace("c:\\") / 1024 / 1024 / 1024);
System.out.println(FileSystemUtils.freeSpace("d:\\") / 1024 / 1024 / 1024);
// 以k为单位
System.out.println(FileSystemUtils.freeSpaceKb("e:\\") / 1024 / 1024);
System.out.println(FileSystemUtils.freeSpaceKb("f:\\") / 1024 / 1024);

}
}

// 行迭代器
public class LineIteratorTest {
private String basePath = null;

@Before
public void setUp() throws Exception {
basePath = System.getProperty("user.dir") + "\\file\\";
}

/**
* 测试行迭代器
*/
@Test
public void testIterator() throws IOException {
File file = new File(basePath + "a.txt");
LineIterator li = FileUtils.lineIterator(file);
while (li.hasNext()) {
System.out.println(li.nextLine());
}
LineIterator.closeQuietly(li);
}
}

// 文件过滤器
public class FileFilterTest {
private String basePath = null;

@Before
public void setUp() throws Exception {
basePath = System.getProperty("user.dir") + "\\file\\";
}

/**
* 空内容文件过滤器
*/
@Test
public void testEmptyFileFilter() throws IOException {
File dir = new File(basePath);
String[] files = dir.list(EmptyFileFilter.NOT_EMPTY);
for (String file : files) {
System.out.println(file);
}
}

/**
* 文件名称后缀过滤器
*/
@Test
public void testSuffixFileFilter() throws IOException {
File dir = new File(basePath);
String[] files = dir.list(new SuffixFileFilter("a.txt"));
for (String file : files) {
System.out.println(file);
}
}
}

// 文件比较器
public class ComparatorTest {
private String basePath = null;

@Before
public void setUp() throws Exception {
basePath = System.getProperty("user.dir") + "\\file\\";
}

/**
* 文件名称比较器
*/
@Test
public void testNameFileComparator() throws IOException {
File f1 = new File(basePath + "a.txt");
File f2 = new File(basePath + "c.txt");
int result = NameFileComparator.NAME_COMPARATOR.compare(f1, f2);
System.out.println(result);
}

/**
* 文件路径比较器
*/
@Test
public void testPathFileComparator() throws IOException {
File f1 = new File(basePath + "a.txt");
File f2 = new File(basePath + "c.txt");
int result = PathFileComparator.PATH_COMPARATOR.compare(f1, f2);
System.out.println(result);
}

/**
* 组合比较器
*/
@SuppressWarnings("unchecked")
@Test
public void testCompositeFileComparator() throws IOException {
File dir = new File(basePath);
File[] files = dir.listFiles();
for (File file : files) {
System.out.println(file.getName());
}
CompositeFileComparator cfc = new CompositeFileComparator(
DirectoryFileComparator.DIRECTORY_COMPARATOR,
NameFileComparator.NAME_COMPARATOR);
cfc.sort(files);
System.out.println("*****after sort*****");
for (File file : files) {
System.out.println(file.getName());
}
}
}

最常用的还是刚上来工具类的那些,精简一下,最多的就是复制文件/文件夹:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 复制文件夹(文件夹里面的文件内容也会复制),file1和file2平级。
// 参数1:文件夹; 参数2:文件夹
void copyDirectory( file1 , file2 );

// 复制文件夹到另一个文件夹。 file1是file2的子文件夹.
// 参数1:文件夹; 参数2:文件夹
void copyDirectoryToDirectory( file1 , file2 );

// 复制文件夹,带有文件过滤功能
void copyDirectory(File srcDir, File destDir, FileFilter filter);

// ***********复制文件**************
// 复制文件到另外一个文件
void copyFile(final File srcFile, final File destFile);
// 复制文件到输出流
void long copyFile(final File input, final OutputStream output);
// 复制文件到一个指定的目录
void copyFileToDirectory( file1 , file2);

// 把输入流里面的内容复制到指定文件
void copyInputStreamToFile( InputStream source, File destination);

// 把URL 里面内容复制到文件。可以下载文件。
// 参数1:URL资源 ; 参数2:目标文件
void copyURLToFile(final URL source, final File destination);

// 把URL 里面内容复制到文件。可以下载文件。
// 参数1:URL资源 ; 参数2:目标文件;参数3:http连接超时时间 ; 参数4:读取超时时间
void copyURLToFile(final URL source, final File destination,
final int connectionTimeout, final int readTimeout);

先暂时贴这么多吧,更多参考:https://blog.csdn.net/zhaoyanjun6/article/details/54972773

参考

https://www.jianshu.com/p/c3c3ab2bad8d
http://www.voidcn.com/article/p-ahnjkqaf-wo.html
https://blog.csdn.net/u011179993/article/details/46743521

评论框加载失败,无法访问 Disqus

你可能需要魔法上网~~