开发中,操作属性时,经常遇到下面这种情况:
public static void main(String[] args) {
// tony是新转学的学生,mike是老生
Student mike = new Student("Mike",12,"四年二班","Kite","1.4","40","合肥市蜀山区");
Student tony = new Student("Tony",14,null,null,"1.5","50","合肥市包河区");
// 将tony转到了mike所在的班级
tony.setClassName(mike.getClassName());
tony.setTeacherName(mike.getTeacherName());
// 结果:Student(studentName=Tony, studentAge=14, className=四年二班, teacherName=Kite, height=1.5, weight=50, homeAddress=合肥市包河区)
System.out.println(tony.toString());
}
上面简单设置两个属性看上去还好,但是如果几十条甚至上百条属性要变,一个一个set看上去会很糟糕
下面我们对比一下几个第三方工具中对于属性copy的使用,可以借鉴一下:
import com.example.demo.java.other.domain.Student;
import com.example.demo.java.other.domain.Teacher;
import org.apache.commons.beanutils.BeanUtils;
import org.modelmapper.Conditions;
import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
//import org.springframework.beans.BeanUtils;
/**
* <p>
* <code>PropertiesCopyTest</code>
* </p>
* Description:java对象拷贝
* 注意事项:
* 使用spring的BeanUtils不用抛异常,而使用Apache的BeanUtils必须抛异常(反射),否则编译报错
* 使用BeanUtils的copyProperties时,如果实体B想要copy实体A,而实体A中某些和B相同的字段是null时,
* 也会被copy过去,导致实体B本身存在的数据丢失,此时可以考虑使用modelMapper工具
*
* @author Mcchu
* @date 2017/10/13 12:07
*/
public class PropertiesCopyTest {
public static void main(String[] args) {
// Tony是新转来的学生,还没有分配班级和老师,下面我们要将他分到和mike一个班
Student mike = mike();
Student tony = tony();
// 1. 使用spring自带的工具,tony的属性被全部覆盖了,这不是我们想要的
//BeanUtils.copyProperties(mike,tony);
// 结果失败:Student(name=Mike, age=12, className=四年二班, teacherName=Kite, height=1.4, weight=40, homeAddress=合肥市蜀山区)
//System.out.println(tony.toString());
try {
// 2. 使用apache工具,将属性一次性全部地copy到tony上,可以发现tony的属性被全部覆盖了,这也不是我们想要的
//BeanUtils.copyProperties(tony,mike);
// 结果失败:Student(name=Mike, age=12, className=四年二班, teacherName=Kite, height=1.4, weight=40, homeAddress=合肥市蜀山区)
//System.out.println(tony.toString());
// 3. 使用apache工具,退而求其次,我们将属性一个一个地copy到tony的属性上,这样是可以的
//BeanUtils.copyProperty( tony, "className", mike.getClassName() );
//BeanUtils.copyProperty( tony, "teacherName", mike.getTeacherName() );
// 结果正确:Student(name=Tony, age=14, className=四年二班, teacherName=Kite, height=1.5, weight=50, homeAddress=合肥市包河区)
//System.out.println(tony.toString());
}catch (Exception e){
e.printStackTrace();
}
// 4. 我们反过来想,如果将tony的属性先覆盖到mike的属性上,这里的覆盖有个关键性条件,即只覆盖存在数据的字段,如果为null时,不做覆盖操作,此时得到的mike属性不就是tony需要的真实属性吗?
//ModelMapper modelMapper = new ModelMapper();
//modelMapper.getConfiguration().setPropertyCondition(Conditions.isNotNull());
//modelMapper.map(tony,mike);
//tony = mike;
// 结果正确:Student(name=Tony, age=14, className=四年二班, teacherName=Kite, height=1.5, weight=50, homeAddress=合肥市包河区)
//System.out.println(tony.toString());
// 5. 假如我们可以拿得到kite老师的属性,而老师的属性里又存在tony需要的className和teacherName,那么我们直接copyProperties就好了
try {
Teacher kite = kite();
BeanUtils.copyProperties(tony,kite); //此处等同于org.springframework.beans.BeanUtils.copyProperties(kite,tony);
// 结果正确:Student(studentName=Tony, studentAge=14, className=四年二班, teacherName=Kite, height=1.5, weight=50, homeAddress=合肥市包河区)
System.out.println(tony.toString());
}catch (Exception e){
e.printStackTrace();
}
}
private static Student mike(){
return new Student("Mike",12,"四年二班","Kite","1.4","40","合肥市蜀山区");
}
private static Student tony(){
return new Student("Tony",14,null,null,"1.5","50","合肥市包河区");
}
private static Teacher kite(){
return new Teacher("Kite",36,"四年二班");
}
}
上面5种方式中,后3种是可以实现正确结果的
附录:Student实体类和Teacher实体类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* <p>
* <code>Teacher</code>
* </p>
* Description:
*
* @author Mcchu
* @date 2017/10/13 13:34
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
private String teacherName;
private Integer teacherAge;
private String className;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* <p>
* <code>Student</code>
* </p>
* Description:
*
* @author Mcchu
* @date 2017/10/13 12:07
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private String studentName;
private Integer studentAge;
private String className;
private String teacherName;
private String height;
private String weight;
private String homeAddress;
}