Dis*_*ame 9 java reflection functional-programming java-8
如何在getter链之后安全地调用setter,例如foo.getX().getY().setZ(...);?例如,假设我有一个嵌套的POJO,我希望能够设置嵌套对象的字段.
Foo foo = ...
foo.getX().getY().setZ(...);
Run Code Online (Sandbox Code Playgroud)
我希望行为是这样的,如果X和Y不存在,那么它们是自动创建的; 否则它会重用现有对象.
换句话说,我希望它的行为相当于
Foo foo = ...
X x = foo.getX();
if (x == null) {
x = new X();
foo.setX(x);
}
Y y = x.getY();
if (y == null) {
y = newY();
x.setY(y);
}
y.setZ(...);
Run Code Online (Sandbox Code Playgroud)
我想知道是否有一个使用反射/功能的技巧接近这一点.
我也有以下约束:
x = foo.getX()修改foo.使用函数式编程.创建一个接受getter,setter和默认值供应商的方法,该方法返回一个封装所需逻辑的getter:
public static <T, U> Function<T, U> getOrSetDefault(
Function<T, U> getter,
BiConsumer<T, U> setter,
Supplier<U> defaultValue) {
return t -> {
U u = getter.apply(t);
if (u == null) {
u = defaultValue.get();
setter.accept(t, u);
}
return u;
};
}
Run Code Online (Sandbox Code Playgroud)
然后创建这些装饰的 getter:
Function<Foo, X> getX = getOrSetDefault(Foo::getX, Foo::setX, X::new);
Function<X, Y> getY = getOrSetDefault(X::getY, X::setY, Y::new);
Run Code Online (Sandbox Code Playgroud)
最后,链接它们并将生成的函数foo作为参数应用于实例中:
Foo foo = ...
getX.andThen(getY).apply(foo).setZ(...);
Run Code Online (Sandbox Code Playgroud)
编辑:这假定两者X并Y具有由所引用的无参数的构造函数X::new和Y::new分别.但是你可以使用任何东西作为Supplier,即已经创建的实例,或方法的返回值等.
TL;DR:不要试图在显然没有地方使用函数式 Java 的地方。
在 Java 8 中,无需修改任何类即可实现此功能的唯一方法是使用Optionals 及其.orElse()方法。它变得非常长非常快,但如果您只想在一行中完成它,那么这是使用函数实际上有意义的唯一方法。
Optional.ofNullable(foo.getX()).orElseGet(() -> { foo.setX(new X()); return foo.getX(); }).setY(...);
Run Code Online (Sandbox Code Playgroud)
如果foo.setX()也返回设定值则可以简化为:
Optional.ofNullable(foo.getX()).orElseGet(() -> foo.setX(new X())).setY(...);
Run Code Online (Sandbox Code Playgroud)
这是我能想到的唯一通用且实用的方法。如上所述,您可以清楚地看到,即使对于两个吸气剂链,这也会变得巨大且丑陋,所以我不建议这样做。如果您必须链接多个调用,我绝对建议您使用经典的多语句方法。
另一种选择,即使认为功能不太强大,也是使用三态运算符,但前提是设置器返回设置的值:
(foo.getX() == null ? foo.setX(new X()) : foo.getX()).setY(...);
Run Code Online (Sandbox Code Playgroud)
如果找到该元素,这可能会产生不必要的副作用,即调用 getter 两次,您可能不喜欢这种副作用,但如果 getter 以某种方式缓存该值,则可能会被忽略。
| 归档时间: |
|
| 查看次数: |
192 次 |
| 最近记录: |