Java Lambda Expression with Non-final Function Paramter

泄露秘密 提交于 2019-11-28 11:13:41

问题


I am trying to simply time a function by using the Runnable interface to wrap around whichever function I need.

private static double time(Runnable runnable) { // returns how long runnable took
    long startTime = System.nanoTime();
    runnable.run();
    return (System.nanoTime() - startTime) / 1000000000.0;
}

then I could simply do the following:

double durationOfFunctionA = time(Driver::functionA); // functionA belongs in class Driver

however, if I have a function that takes a parameter, it must be modified to:

double durationOfFunctionB = time(() -> functionB(someParameter));

The problem I am having is that 'someParameter' must be final or effectively final. Is there any workaround this problem? I have seen loops with forEach, but I need this parameter to be exponential from 1, 10, 100 -> until a condition is met. The code is this:

public static void main(String[] args) {
    double timer = 0;
    int size = 1;

    while(timer <= 10) {
        timer = time(() -> functionB(size));
        size *= 10;
    }
}

I require functionB to take in a parameter because I want to test the complexity/big-O of it. I am worried that I am not coding/using lambda expressions the correct way. If someone can help solve this problem or find another solution, that would be appreciated.

As a side note, I do know that I don't have to make this so complex with a Runnable interface, I can just do the timing right in the while loop. However, I just wanted to see if it were possible to do such a thing both so I could just input some function to test, and as syntactic sugar.


回答1:


You can simply copy the variable value to separate final variable like this:

double timer = 0;
int size = 0;
while(true) {
  final finalSize = size;
  timer = time(() -> functionB(finalSize));
  size *= 10;
}

Also, I can advice you to make some more timing functions for various amount of parameters for functions you want to time. Here how you can do it:

public class Test {

    public static void main(final String[] args) {
        int ttt = 0;
        time(ttt, Test::func);
        time(ttt, ttt, Test::func);
    }

    public static void func(int i) {

    }

    public static void func(int i, int j) {

    }

    public static <T> double time(T arg, Consumer<T> func) {
        long startTime = System.nanoTime();
        func.accept(arg);
        return (System.nanoTime() - startTime) / 1000000000.0;
    }

    public static <T1, T2> double time(T1 arg1, T2 arg2, BiConsumer<T1, T2> func) {
        long startTime = System.nanoTime();
        func.accept(arg1, arg2);
        return (System.nanoTime() - startTime) / 1000000000.0;
    }

}



回答2:


Try this.

public static void main(String[] args) {
    double timer = 0;
    final int[] size = {1};

    while(timer <= 10) {
        timer = time(() -> functionB(size[0]));
        size[0] *= 10;
    }
}

Lambda expression refers to the free variables by copying them inside. So the free varibles must not be changed (must be final). But when you pass size[0], lambda expression copies array variable size. It is final.



来源:https://stackoverflow.com/questions/39940323/java-lambda-expression-with-non-final-function-paramter

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!