整理了开发中常用的 JavaBean 处理工具类,包括 Beanutils、PropertyUtils、CollectionUtils、ConvertUtils。近期使用中发现 BeanUtils.populate 方法存在 bug,实体类属性与 Map 中 key 值一模一样,但是会有一些属性拷贝完未null,而且 debug 源码未果,在这里推荐大家一个集成程度更高的 Util 工具类 hutool
- BeanUtils:主要提供了对于 JavaBean 进行各种操作,比如对象,属性复制等等,自动转换数据类型。
- PropertyUtils:用处大致与 BeanUtils 相同,但是如果类型不能自动转换会抛异常。
- CollectionUtils :集合处理类,集合类型转化,取交集、并集等方法。
- ConvertUtils:数据类型转换类,BeanUtils 的自动类型转换就要到了它。
BeanUtils
导入依赖包:org.apache.commons-beanutils.jar、org.apache.commons-collections.jar、org.apache.commons-logging.jar。
新建 Maven 工程,在 pom.xml 中加入:
<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
常用方法:
方法 | 说明 |
---|---|
cloneBean(Object bean) | 对象的克隆 |
copyProperties(Object dest, Object orig) | 对象的拷贝 |
copyProperty(Object bean, String name, Object value) | 拷贝指定的属性值到指定的bean |
setProperty(Object bean, String name, Object value) | 设置指定属性的值 |
populate(Object bean, Map<String,? extends Object> properties) | 将map数据拷贝到javabean中(map的key要与javabean的属性名称一致) |
处理参数是 map 类型的情况,例如在 jdbc 中获取的结果集使用 hashmap 存储后如何转为其他对象(Servlet 简单应用),使用 populate 方法。
举个例子:
public class App
{
public static void main( String[] args )
{
Dog dog = new Dog();
Map<String, Object> map = new HashMap<>();
map.put("age",2);
map.put("name","huahua");
try {
BeanUtils.populate(dog,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} finally {
}
System.out.println("dog:"+dog);//dog:Dog{name='huahua', age=2}
}
}
//Dog 类:
public class Dog {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
下面用一下其他几个方法举几个例子。
// Animal 类
public class Animal {
private String name;
private String type;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", type='" + type + '\'' +
", age=" + age +
'}';
}
}
//测试类
public class App
{
public static void main( String[] args ) throws IllegalAccessException,InvocationTargetException
{
// copyProperties 方法
Animal animal = new Animal();
animal.setName("mimi");
animal.setType("dog");
animal.setAge(2);
Dog dog = new Dog();
BeanUtils.copyProperties(dog,animal);
System.out.println("将 animal 值赋给 dog:");
System.out.println(dog);
//如果被copy对象缺少目标对象中的某些属性,那么目标对象中的对应值为 null
Animal animal1 = new Animal();
BeanUtils.copyProperties(animal1,dog);
System.out.println("将 dog 值赋给 animal1 对象:");
System.out.println(animal1);
// copyProperty 方法
animal.setName("huahua");
BeanUtils.copyProperty(dog,"name",animal.getName());
System.out.println("改变 animal name属性,并赋给 dog:");
System.out.println(dog);
// setProperty 方法
BeanUtils.setProperty(dog,"age",3);
System.out.println("给 dog 的 age 属性赋值:");
System.out.println(dog);
// cloneBean 方法
try {
Animal animal2 = (Animal)BeanUtils.cloneBean(animal1);
System.out.println("通过 animal1 克隆 animal2 对象:");
System.out.println(animal2);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
输出结果:
将 animal 值赋给 dog:
Dog{name='mimi', age=2}
将 dog 值赋给 animal1 对象:
Animal{name='mimi', type='null', age=2}
改变 animal name属性,并赋给 dog:
Dog{name='huahua', age=2}
给 dog 的 age 属性赋值:
Dog{name='huahua', age=3}
通过 animal1 克隆 animal2 对象:
Animal{name='mimi', type='null', age=2}
顺带提一下 PropertyUtils
BeanUtils与PropertyUtils这两个类几乎有一摸一样的功能,唯一的区别是:BeanUtils在对Bean赋值是会进行类型转化。
举例来说也就是在copyProperty时只要属性名相同,就算类型不同,BeanUtils也可以进行copy;而PropertyBean则可能会报错!!当然2个Bean之间的同名属性的类型必须是可以转化的,否则用BeanUtils一样会报错。
若实现了org.apache.commons.beanutils.Converter接口则可以自定义类型之间的转化。由于不做类型转化,用PropertyUtils在速度上会有很大提高!
CollectionUtils
集合处理工具类。
举几个例子:
String[] arrA = new String[]{"1", "2", "3"};
String[] arrB = new String[]{"1", "a", "b"};
List<String> listA = Arrays.asList(arrA);
List<String> listB = Arrays.asList(arrB);
// 判断集合是否为 空
System.out.println(CollectionUtils.isEmpty(listA));// false
System.out.println(CollectionUtils.isEmpty(listB));// false
// 判断集合是否为 不为空
System.out.println(CollectionUtils.isNotEmpty(listA));// true
System.out.println(CollectionUtils.isNotEmpty(listB));// true
// 两个集合的比较
System.out.println(CollectionUtils.isEqualCollection(listA, listB));// false
// 集合的操作
// 取并集
System.out.println(CollectionUtils.union(listA, listB));// [1, a, 2, b, 3]
// 取交集
System.out.println(CollectionUtils.intersection(listA, listB));// [1]
// 取交集的补集
System.out.println(CollectionUtils.disjunction(listA, listB));// [a, 2, b, 3]
// 取集合相减
System.out.println(CollectionUtils.subtract(listA, listB));// [2, 3]
System.out.println(CollectionUtils.subtract(listB, listA));// [a, b]
List<String> listC = new ArrayList<>();
listC.add("1");
listC.add("2");
listC.add("3");
String[] arrC = {"4", "5", "6"};
// 向集合中添加值
CollectionUtils.addAll(listC, arrC);
System.out.println(listC);// [1, 2, 3, 4, 5, 6]
ConvertUtils
类型转换工具类,有了这个就不用为记各种数据类型互转的方法而烦恼了。
使用的主要方法:
convert(Object value, Class<?> targetType)//将给定的value转换成指定的Class类型
举个例子:
public static void main( String[] args ) throws IllegalAccessException,InvocationTargetException
{
String str = "10";
Object obj = ConvertUtils.convert(str, BigDecimal.class);
System.out.println(obj.getClass());//class java.math.BigDecimal
Object obj2 = ConvertUtils.convert("100",Integer.class);
System.out.println(obj2.getClass());//class java.lang.Integer
}
通过查看 BeanUtils 的源码,发现 BeanUtils 里的自动类型转换其实就是使用了 ConvertUtils,根本上都用到了 ConvertUtilsBean 对象。
查看 ConvertUtils.convert(String str,Class class) 的源码:
/**
* <p>Convert the specified value to an object of the specified class (if
* possible). Otherwise, return a String representation of the value.</p>
*
* <p>For more details see <code>ConvertUtilsBean</code>.</p>
*
* @param value Value to be converted (may be null)
* @param clazz Java class to be converted to (must not be null)
* @return The converted value
*
* @see ConvertUtilsBean#convert(String, Class)
*/
public static Object convert(final String value, final Class<?> clazz) {
return ConvertUtilsBean.getInstance().convert(value, clazz);
}
查看 BeanUtils.copyProperty() 方法的源码:
BeanUtilsBean.java 中的 copyProperty 方法,判断完非空并且获取完目标属性类型后对类型进行转化并存储:
// Convert the specified value to the required type and store it
if (index >= 0) { // Destination must be indexed
value = convertForCopy(value, type.getComponentType());
try {
getPropertyUtils().setIndexedProperty(target, propName,
index, value);
} catch (final NoSuchMethodException e) {
throw new InvocationTargetException
(e, "Cannot set " + propName);
}
进入 convertForCopy 发现调用了类成员方法 convert ,再看 convert 通过 getConvertUtils 获取了 Converter 对象:
//顶部声明成员为 ConvertUtilsBean
private final ConvertUtilsBean convertUtilsBean;
//实际 convert 方法
protected Object convert(final Object value, final Class<?> type) {
final Converter converter = getConvertUtils().lookup(type);
if (converter != null) {
log.trace(" USING CONVERTER " + converter);
return converter.convert(type, value);
} else {
return value;
}
}
//获取 ConvertUtilsBean 对象
public ConvertUtilsBean getConvertUtils() {
return convertUtilsBean;
}
这些工具类已经可以满足一般应用开发需要,当然还可以再封装定制。(大佬造好的轮子真的好用)