我当时的想法是,对任何可能在某个时候返回空值的方法调用链使用如下函数 Package 器:
public static <T, R extends Class> R getOrPassNullable(Function<T, R> call, T param) {
try {
return call.apply(param);
}
catch (NullPointerException e) {
return null;
}
}
我提出了一个简单的基准测试来测试性能影响:创建一个虚拟变量,其中一些字段嵌套在2-3个深度调用中,并使用我的函数 Package 器和普通的手动检查来度量运行时。
对于基准测试本身,我稍微修改了其他帖子中的一个答案,只需按照指定次数执行给定的方法:
public class TimeTracedExecutor<T, R> {
Function<T, R> methodToExecute;
public TimeTracedExecutor(Function<T, R> methodToExecute) {
this.methodToExecute = methodToExecute;
}
public void executeWithInput(String taskDescription, T t, int times) {
Instant start = Instant.now();
for (int i = 0; i < times; i++) {
methodToExecute.apply(t);
}
Instant finish = Instant.now();
String format = "Task took %s milliseconds: " + taskDescription;
String elapsedTime = NumberFormat.getNumberInstance()
.format(Duration.between(start, finish).toMillis());
System.out.println(String.format(format, elapsedTime));
}
}
然后在测试用例中,我使用了一个简单的类定义和嵌套字段,如下所示:
public class NestingDoll {
private NestingDoll nested;
public NestingDoll getNested(){
return this.nested;
}
public void setNested(NestingDoll val){
this.nested = val;
}
}
对于要测试的实现,我使用了以下两种方法:
private NestingDoll getNestedFunctionalBypass(NestingDoll root) {
return getOrPassNullable(() -> root.getNested().getNested().getNested().getNested());
}
private NestingDoll getNestedManualChecks(NestingDoll root) {
if (root != null
&& root.getNested() != null
&& root.getNested().getNested() != null
&& root.getNested().getNested().getNested() != null)
) {
return root.getNested().getNested().getNested().getNested();
}
return null;
}
最后,我建立并运行了如下基准:
public void profileNullChecks() {
NestingDoll root = new NestingDoll();
NestingDoll depth1 = new NestingDoll();
NestingDoll depth2 = new NestingDoll();
NestingDoll depth3 = new NestingDoll();
depth2.setNested(depth3);
depth1.setNested(depth2);
root.setNested(depth1);
TimeTracedExecutor<NestingDoll, NestingDoll> nullChecks =
new TimeTracedExecutor<NestingDoll,NestingDoll>(
this::getNestedManualChecks);
TimeTracedExecutor<NestingDoll, NestingDoll> functionalBypass =
new TimeTracedExecutor<NestingDoll,NestingDoll>(
this::getNestedFunctionalBypass);
nullChecks.executeWithInput("Manual null checks", root, (int) Math.pow(10, 10));
functionalBypass.executeWithInput("Functional bypass", root, (int) Math.pow(10, 10));
}
我本以为可能会对性能产生一些影响,但结果却是巨大的:手动检查的时间是9毫秒,而我的函数 Package 器的时间是7000毫秒。
我不知道为什么这里的差异有多个数量级。我的设置方式或实现 Package 器的方式是否有什么遗漏,或者功能接口是否有什么让它们使用起来如此缓慢?
暂无答案!
目前还没有任何答案,快来回答吧!