通过getter和setter更新pojos的通用方法

use*_*r_x 8 java generics lambda java-8 method-reference

假设我有不同类型的吸气剂和固定剂POJO.我想写一些通用算法,只需通过lambdas定义getter和setter,就可以将数据从一个更新到另一个.我试图以这种方式创建它

private static final Map<Function<Entity, Object>, BiConsumer<Entity, Object>> ACCESSORS = new HashMap
        <Function<Entity, Object>, BiConsumer<Entity, Object>>() {{
    put(Entity::getAreaCode, Entity::setAreaCode);
}});
Run Code Online (Sandbox Code Playgroud)

然后我遍历所有应用目标实体的条目,如果getter的结果不为null,那么我想为其他实体应用相应的setter.

但它不起作用,因为Object不能转换为String.而且我想将它用于不同的类型,不仅是字符串,还有整数等...

是否可以通过一些简单的方法解决而无需创建特殊转换器并将其与每个条目相关联?

Hol*_*ger 13

使用类似的东西

private static final List<BiConsumer<Entity,Entity>> ACCESSORS =
    Collections.unmodifiableList(Array.asList(
        (src,dst) -> dst.setAreaCode(src.getAreaCode()),
        (src,dst) -> dst.setOtherProperty(src.getOtherProperty())
        /* etc */
));
Run Code Online (Sandbox Code Playgroud)

然后,您可以遍历列表并将每个操作应用于两个实体,例如

static final void copyAll(Entity src, Entity dst) {
    ACCESSORS.forEach(op -> op.accept(src, dst));
}
Run Code Online (Sandbox Code Playgroud)

关键点是实际的属性值类型在每个属性中处理,BiConsumer但不再是通用签名的一部分,因此不需要声明ACCESSORS.它更有效率,因为它可以处理原始数据类型而无需装箱费用.

Map不承担这一任务的合适的数据结构,无论如何,对于这些功能,任何有意义的查询可以进行,所以这是一个数据结构只打算遍历.

您可以将"仅在非空时复制"逻辑与通用帮助程序方法集成:

private static final List<BiConsumer<Entity,Entity>> ACCESSORS =
    Collections.unmodifiableList(Arrays.asList(
        copyWhenNonNull(Entity::getAreaCode, Entity::setAreaCode),
        copyWhenNonNull(Entity::getOtherProperty, Entity::setOtherProperty)
        /* etc */
));
private static <E,V> BiConsumer<E,E> copyWhenNonNull(
    Function<? super E, ? extends V> getter, BiConsumer<? super E, ? super V> setter) {
    return (src,dst) -> {
        V value = getter.apply(src);
        if(value != null) setter.accept(dst, value);
    };
}
Run Code Online (Sandbox Code Playgroud)

copyAll方法不会改变.这甚至允许混合无条件复制属性,这些属性永远不会null与条件复制相关.