使用Java 8执行计时方法

Phi*_*ipp 1 java closures java-8 method-reference

我已经阅读了如何计算方法在Java中的执行时间?并了解定时执行方法的常用可能性(启动/停止计时器执行,使用方面等).

我想知道Java 8的新方法引用和lambdas是否为实现以下目标带来了任何帮助.

普通代码:

String r;
r = methodCall("foo","bar");
Run Code Online (Sandbox Code Playgroud)

在性能调优期间,将代码修改为类似的内容,以测量执行方法所花费的时间

String r;
time(() -> {
  r = methodCall("foo", "bar"); // doesn't work as r needs to be effectively final
});
Run Code Online (Sandbox Code Playgroud)

我明白我能做到

String r;
r = time1(() -> 
    methodCall("foo", "bar)
);
Run Code Online (Sandbox Code Playgroud)

(注意结尾处缺少的分号),使用类似的time1方法

public static <R> R time1(Supplier<R> s){
    long start = System.currentTimeMillis();
    R result  = s.get();
    System.out.println("Execution took " + (System.currentTimeMillis() - start));
    return result;
}
Run Code Online (Sandbox Code Playgroud)

或者我能做到

r = time2(this::methodCall, "foo", "bar");
Run Code Online (Sandbox Code Playgroud)

用time2方法就好

public static <A,B,R> R time2(BiFunction<A, B, R> f, A first, B second){
    long start = System.currentTimeMillis();
    R result = f.apply(first, second);
    System.out.println("Execution took " + (System.currentTimeMillis() - start));
    return result;
}
Run Code Online (Sandbox Code Playgroud)

没有回报价值,我可以做得更好

time3(() -> {
    System.out.println("hello");
});
Run Code Online (Sandbox Code Playgroud)

(注意,分号存在)和time3一样

public static void time3(Runnable r){
    long start = System.currentTimeMillis();
    r.run();
    System.out.println("Execution took " + (System.currentTimeMillis() - start));
}
Run Code Online (Sandbox Code Playgroud)

当我有一个返回值时,有更好的解决方案吗?

我需要闭合才能做到这一点吗?

Rog*_*gue 6

你仍然可以包装方法调用,只返回null,什么都不产生:

public <R> R timing(Supplier<R> operation) {
    long start = System.nanoTime();
    R result  = operation.get();
    System.out.printf("Execution took %dms\n", TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start));
    return result;
}

public void timing(Runnable operation) {
    this.timing(() -> { operation.run(); return null; });
}
Run Code Online (Sandbox Code Playgroud)

然后调用本质上是相同的:

String r = timing(() -> methodCall("foo", "bar"));
timing(() -> System.out.println("Hello"));
Run Code Online (Sandbox Code Playgroud)

实际上,如果您想要使用方法参数/引用,您需要了解Java的Function api和方法签名之间的关系.

从本质上讲,你不能动态地重新映射所有的方法参数,并对方法进行直接的"命名"引用(并对参数进行varargs),你可以做的最好/最接近的就是覆盖n你所看到的参数BiFunction(或者继续做自定义FunctionalInterfaces.也许有一天我们会有一个类似于C#的"varargs"泛型操作,但在那之前我们不能做类似的想法#time2