将裸引用的 get/test/set 替换为 Optional.ofNullable(...).ifPresent(...)?
Replace get/test/set of bare references with Optional.ofNullable(...).ifPresent(...)?
我有一个增变器方法,它只设置参数中提供的非空字段。参数 returns 仅引用,而不是 Optional
包装器,并且无法更改。
在 Java8 之前,一种方法是:
Double h = arg.getH();
if ( null != h ) setH( h );
Double v = arg.getV();
if ( null != h ) setV( v );
String s = arg.getS();
if ( null != s ) setS( s );
// Etc. ...
从Java8开始,可以用throwawayOptional
来表达得更简洁。
Optional.ofNullable( arg.getH()).ifPresent( this::setH );
Optional.ofNullable( arg.getV()).ifPresent( this::setV );
Optional.ofNullable( arg.getS()).ifPresent( this::setS );
// Etc. ...
这个成语不太熟悉。但是,它也消除了潜在的错误源——例如上面 "before Java 8" 代码中的错误。
问题:经常使用这种新模式有什么负面影响吗?(例如,与编译大小或性能的早期模式?)
性能总是很难以通用的方式回答。事实是:JVM 进行了如此多的优化,以至于很难说它对 您的 应用程序的表现如何。即便如此,随着时间的推移,性能可能与 "cold boot" 后立即测量的性能不同。例如,如果您的参数在 99% 的情况下都不为空,则分支预测可能会使两个变体的性能变得无关紧要。
最后,如果您真的很在意性能,请在您自己的应用程序上进行测量。
总而言之,我会说最好选择你更容易阅读和维护的版本。在我的例子中,pre-Java 8 会赢,但那只是我:)
显然,您的任务是调整您的类型的实例以反映您无法控制的类型的属性。 (我有点担心 // etc
评论。)在那种情况下,我们可以将“transfer this 属性, if not null
”封装为一个操作:
// in MyType
static <T> BiConsumer<TypeOfArg,MyType> transfer(
Function<TypeOfArg,T> from, BiConsumer<MyType,T> to) {
return (arg,myself) -> {
T value = from.apply(arg);
if(value!=null) to.accept(myself, value);
};
}
static final BiConsumer<TypeOfArg,MyType> TRANSFER_ALL_PROPERTIES =
transfer(TypeOfArg::getH, MyType::setH).andThen(
transfer(TypeOfArg::getV, MyType::setV).andThen(
transfer(TypeOfArg::getS, MyType::setS)));
void mutatorMethod(TypeOfArg arg) {
TRANSFER_ALL_PROPERTIES.accept(arg, this);
}
我很确定,这也可能会引起争论,即这是否比第一个变体中的 get
-if
-set
调用的普通序列更好,不过我觉得,这跟熟悉程度也有很大关系。
对我来说,transfer(TypeOfArg::getV, MyType::setV)
比 Optional.ofNullable( arg.getV()).ifPresent( this::setV )
更能表达意图,后者读起来仍然很像命令式陈述。
对于那些关心临时对象的人来说,代码不会创建任何对象。
我有一个增变器方法,它只设置参数中提供的非空字段。参数 returns 仅引用,而不是 Optional
包装器,并且无法更改。
在 Java8 之前,一种方法是:
Double h = arg.getH();
if ( null != h ) setH( h );
Double v = arg.getV();
if ( null != h ) setV( v );
String s = arg.getS();
if ( null != s ) setS( s );
// Etc. ...
从Java8开始,可以用throwawayOptional
来表达得更简洁。
Optional.ofNullable( arg.getH()).ifPresent( this::setH );
Optional.ofNullable( arg.getV()).ifPresent( this::setV );
Optional.ofNullable( arg.getS()).ifPresent( this::setS );
// Etc. ...
这个成语不太熟悉。但是,它也消除了潜在的错误源——例如上面 "before Java 8" 代码中的错误。
问题:经常使用这种新模式有什么负面影响吗?(例如,与编译大小或性能的早期模式?)
性能总是很难以通用的方式回答。事实是:JVM 进行了如此多的优化,以至于很难说它对 您的 应用程序的表现如何。即便如此,随着时间的推移,性能可能与 "cold boot" 后立即测量的性能不同。例如,如果您的参数在 99% 的情况下都不为空,则分支预测可能会使两个变体的性能变得无关紧要。
最后,如果您真的很在意性能,请在您自己的应用程序上进行测量。
总而言之,我会说最好选择你更容易阅读和维护的版本。在我的例子中,pre-Java 8 会赢,但那只是我:)
显然,您的任务是调整您的类型的实例以反映您无法控制的类型的属性。 (我有点担心 // etc
评论。)在那种情况下,我们可以将“transfer this 属性, if not null
”封装为一个操作:
// in MyType
static <T> BiConsumer<TypeOfArg,MyType> transfer(
Function<TypeOfArg,T> from, BiConsumer<MyType,T> to) {
return (arg,myself) -> {
T value = from.apply(arg);
if(value!=null) to.accept(myself, value);
};
}
static final BiConsumer<TypeOfArg,MyType> TRANSFER_ALL_PROPERTIES =
transfer(TypeOfArg::getH, MyType::setH).andThen(
transfer(TypeOfArg::getV, MyType::setV).andThen(
transfer(TypeOfArg::getS, MyType::setS)));
void mutatorMethod(TypeOfArg arg) {
TRANSFER_ALL_PROPERTIES.accept(arg, this);
}
我很确定,这也可能会引起争论,即这是否比第一个变体中的 get
-if
-set
调用的普通序列更好,不过我觉得,这跟熟悉程度也有很大关系。
对我来说,transfer(TypeOfArg::getV, MyType::setV)
比 Optional.ofNullable( arg.getV()).ifPresent( this::setV )
更能表达意图,后者读起来仍然很像命令式陈述。
对于那些关心临时对象的人来说,代码不会创建任何对象。