Java-лямбда-выражение с параметром не конечной функции

#java #lambda #final

#java #лямбда-выражение #Финал

Вопрос:

Я пытаюсь просто определить время функции, используя выполняемый интерфейс, чтобы обернуть вокруг любой функции, которая мне нужна.

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

тогда я мог бы просто сделать следующее:

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

однако, если у меня есть функция, которая принимает параметр, его необходимо изменить на:

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

Проблема, с которой я сталкиваюсь, заключается в том, что ‘someParameter’ должен быть окончательным или фактически окончательным. Есть ли какое-либо решение этой проблемы? Я видел циклы с forEach, но мне нужно, чтобы этот параметр был экспоненциальным от 1, 10, 100 -> до тех пор, пока не будет выполнено условие. Код такой:

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

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

Я требую, чтобы функция B принимала параметр, потому что я хочу проверить его сложность / big-O. Я обеспокоен тем, что я неправильно кодирую / использую лямбда-выражения. Если кто-то может помочь решить эту проблему или найти другое решение, это было бы оценено.

В качестве примечания, я знаю, что мне не нужно делать это настолько сложным с помощью управляемого интерфейса, я могу просто правильно рассчитать время в цикле while. Однако я просто хотел посмотреть, возможно ли это сделать, чтобы я мог просто ввести некоторую функцию для тестирования и в качестве синтаксического сахара.

Ответ №1:

Вы можете просто скопировать значение переменной в отдельную конечную переменную следующим образом:

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

Кроме того, я могу посоветовать вам создать еще несколько функций синхронизации для различного количества параметров для функций, которые вы хотите рассчитать.
Вот как вы можете это сделать:

 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:

Попробуйте это.

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

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

Лямбда-выражение ссылается на свободные переменные, копируя их внутрь.
Таким образом, свободные переменные не должны быть изменены (должны быть final ).
Но когда вы передаете size[0] , лямбда-выражение копирует переменную массива size .
Это так final .

Комментарии:

1. Попробуйте … добавление объяснения?

2. Спасибо за помощь! Я предполагаю, что это связано с тем, что массив является окончательным, но фактическое содержимое является гибким?