将裸引用的 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 ) 更能表达意图,后者读起来仍然很像命令式陈述。

对于那些关心临时对象的人来说,代码不会创建任何对象。