【发布时间】:2016-10-09 00:06:37
【问题描述】:
我有一个 mutator 方法,它只设置参数中提供的非空字段。该参数返回裸引用,而不是 Optional 包装器,并且无法更改。
在 Java 8 之前,一种方法是:
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. ...
从 Java 8 开始,可以用一次性的Optional 更简洁地表达这一点。
Optional.ofNullable( arg.getH()).ifPresent( this::setH );
Optional.ofNullable( arg.getV()).ifPresent( this::setV );
Optional.ofNullable( arg.getS()).ifPresent( this::setS );
// Etc. ...
这个成语不太熟悉。但是,它也消除了潜在的错误来源——例如上面“Java 8 之前”代码中的错误。
问题:频繁使用这种新模式是否有任何负面影响?(例如,它与早期模式相比在编译大小或性能方面如何? )
【问题讨论】:
-
第二个变体创建临时对象,而第一个没有。它们与大多数现实生活中的案例无关,但仍然有开发人员对这些事情感到难过。除此之外,这更多是代码风格的问题。我宁愿专注于这个问题,为什么首先会有
Double对象…… -
如果代码执行得足够频繁,它可能会达到阈值并被 HotSpot 编译器优化(即内联)。内存影响也不应该那么大,因为可选只是一个包装器,并且很快就会被youngGenGC清理掉。所以我同意 Nicolas,替补!
-
您问的是性能成本(基本上是两个对象创建)是否值得简洁,但我认为这是错误的问题。就像一个人很容易过分关注性能一样,一个人也可以做到简洁。真正的目标应该是清晰。正如@jpkrohling 所暗示的那样,许多用户会发现
Optional的复杂用法比原始版本的可读性差。 -
@the8472:年轻 GC 的性能取决于 幸存 对象的数量,当您提高 临时 对象的数量时,这不会改变> 对象。考虑到这些临时对象的大小与 TLAB 的大小之比,您只会导致年轻 GC 提前 0.0…% 发生。
-
@AndyThomas Holger 的方法似乎要好得多;它直接解决了意图——获取一个属性,如果它不为空,则将其复制到其他地方。 (它也碰巧产生更少的意外垃圾——未绑定的实例方法引用实际上是常量。)