java 中利用 function 函数式接口转换对象属性,核心做法是创建一个接收源对象并返回目标对象的 lambda 表达式或方法引用,通过 apply() 方法执行映射。具体实现时,通常将源对象作为输入参数,在 lambda 体内实例化目标对象并逐个赋值,最后返回该实例。若源对象与目标对象属性名和类型完全一致,可直接使用 beanutils.copyproperties() 简化代码;若需转换逻辑(如格式调整),则在 lambda 中显式处理。此方式灵活且符合函数式编程风格,适用于 dto 转换、数据封装等场景。

如何定义一个通用的对象属性映射函数
要定义一个通用的对象属性映射函数,可以使用 Java 8 引入的 Function 接口。该接口接受一个泛型参数作为输入,返回另一个泛型参数作为输出。在实际开发中,我们通常通过 Lambda 表达式来实例化这个函数,从而指定具体的属性转换逻辑。例如,将一个包含用户信息的 UserDTO 对象转换为领域模型 UserEntity,只需编写一个 Lambda 表达式,接收 UserDTO 实例,创建 UserEntity 实例,并将对应字段赋值后返回。这种方式使得转换逻辑与业务代码解耦,便于复用和测试。

import java.util.function.Function;
public class ObjectMapperExample {
// 定义源对象和目标对象
static class UserDTO {
String username;
String email;
int age;
public UserDTO(String username, String email, int age) {
this.username = username;
this.email = email;
this.age = age;
}
}
static class UserEntity {
String name;
String contactEmail;
int yearsOld;
public UserEntity(String name, String contactEmail, int yearsOld) {
this.name = name;
this.contactEmail = contactEmail;
this.yearsOld = yearsOld;
}
@Override
public String toString() {
return "UserEntity{name='" + name + "', contactEmail='" + contactEmail + "', yearsOld=" + yearsOld + "}";
}
}
public static void main(String[] args) {
// 创建 Function 实例,定义转换逻辑
Function<userdto userentity> mapper = dto -> {
if (dto == null) return null;
return new UserEntity(
dto.getUsername(),
dto.getEmail(),
dto.getAge()
);
};
// 执行转换
UserDTO source = new UserDTO("john_doe", "john@example.com", 30);
UserEntity target = mapper.apply(source);
System.out.println(target);
}
}</userdto>
如何处理属性名不一致或需要转换的情况
当源对象与目标对象的属性名不一致,或者需要进行数据类型转换时,可以在 Function 的 Lambda 体中进行手动映射。例如,将字符串类型的日期转换为 Date 对象,或者将枚举值转换为对应的 ID。这种情况下,Lambda 表达式充当了适配器角色,负责处理复杂的转换规则。开发者需要在 Lambda 内部编写具体的转换逻辑,如调用 LocalDate.parse() 或使用工具类进行数值计算。这种方式的优点是逻辑清晰、可控性强,缺点是代码量稍多,适合转换规则较为复杂或非标准化的场景。

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.function.Function;
public class ComplexMapperExample {
static class OrderDTO {
String orderId;
String orderDateStr; // 格式: yyyy-MM-dd
double totalAmount;
public OrderDTO(String orderId, String orderDateStr, double totalAmount) {
this.orderId = orderId;
this.orderDateStr = orderDateStr;
this.totalAmount = totalAmount;
}
}
static class OrderEntity {
String id;
LocalDate orderDate;
long amountInCents;
public OrderEntity(String id, LocalDate orderDate, long amountInCents) {
this.id = id;
this.orderDate = orderDate;
this.amountInCents = amountInCents;
}
@Override
public String toString() {
return "OrderEntity{id='" + id + "', orderDate=" + orderDate + ", amountInCents=" + amountInCents + "}";
}
}
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
// 定义包含复杂转换逻辑的 Function
Function<orderdto orderentity> complexMapper = dto -> {
if (dto == null) return null;
LocalDate date = LocalDate.parse(dto.getOrderDateStr(), formatter);
long cents = Math.round(dto.getTotalAmount() * 100);
return new OrderEntity(dto.getOrderId(), date, cents);
};
OrderDTO source = new OrderDTO("ORD-123", "2023-10-01", 99.99);
OrderEntity target = complexMapper.apply(source);
System.out.println(target);
}
}</orderdto>
当输入对象为 null 时 Function 会返回什么
当输入对象为 null 时,Function 的行为取决于 Lambda 表达式内部的实现。如果 Lambda 体中没有对 null 进行检查而直接访问属性,将抛出 NullPointerException。因此,最佳实践是在 Lambda 开头添加空值检查,若输入为 null 则直接返回 null 或默认值。例如,在上面的示例中,if (dto == null) return null; 确保了安全性。这种处理方式避免了运行时异常,使转换函数更加健壮。开发者应始终考虑边界条件,确保函数在各种输入下都能稳定运行。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











