0

Lets say I have n methods and I get a number i, now I want to call method f_i.

The trivial way to do this is to use conditionals like so:

if (j == 1) f_1();
else if (j == 2) f_2();
...
else if (j == n) f_n();

Since there are n comparisons in the worst case, the worst-case runtime is O(n).

Extra: How would you solve this if function f_i takes arguments p[i][1] to p[i][#parameters of f_i] where p is 2 dimensional array?

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
Niki
  • 738
  • 8
  • 17
  • Problem is if the functions take different number of parameters, you can't use a `Map>`, but you could just create your own function wrapper class. – tobias_k Oct 22 '19 at 19:08
  • A `switch/case` statement works in `O(1)` - that's probably what your teacher wants you to say. – Dawood ibn Kareem Oct 22 '19 at 19:10
  • IMHO the first question, however, is: How bad is O(n) in this case? How big is n, how often will this be called, and how does selecting the function compare to executing the function (or the rest of the code). – tobias_k Oct 22 '19 at 19:10
  • @DawoodibnKareem Is it? That was new to me. Do you have a reference for that? – tobias_k Oct 22 '19 at 19:11
  • switch case can be O(1) but that depends on how the compiler translates the code... If at all possible, I want to avoid function interfaces – Niki Oct 22 '19 at 19:12
  • 1
    Just an array will do, no need for a map. – Gonen I Oct 22 '19 at 19:13
  • 1
    @tobias_k Have a look at https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-3.html#jvms-3.10 which describes a tableswitch, which is what the compiler would use in this case. There's a good explanation at https://stackoverflow.com/a/12938176 – Dawood ibn Kareem Oct 22 '19 at 19:17

1 Answers1

3

Just use an array, like so:

private static final class Functions {
    private static void f0() {
        System.out.println(0);
    }
    private static void f1() {
        System.out.println(1);
    }
    private static void f2() {
        System.out.println(2);
    }
    private static void f3() {
        System.out.println(3);
    }
}

public static void main(String[] args) throws Exception {
    int j = 2;

    Runnable[] functions = {
            Functions::f0,
            Functions::f1,
            Functions::f2,
            Functions::f3,
    };

    functions[j].run();
}

If your functions return something and/or take arguments, you need a different type for the array, like Consumer, Supplier, or Function.

Alex R
  • 3,139
  • 1
  • 18
  • 28
  • Thank you, that would work. Any idea how to solve this before Java 8 / without a functional interface? – Niki Oct 22 '19 at 19:24
  • 1
    Yes, you have to create a wrapper around the function calls. So instead of using `Functions::f1` you have to do something 'ugly' like ` new Runnable() { @Override public void run() { Functions.f1(); } }` – Alex R Oct 22 '19 at 19:26
  • `Runnable` existed before Java 8. Method references are just one of 4 ways to create instances of interfaces like `Runnable`. You still have anonymous classes and regular classes that implement prior to Java 8. – Zabuzard Oct 22 '19 at 19:26
  • Theoretically you could also use Reflection to get a `Method` handle on the methods, even by their name. And then use the handle to dynamically invoke it. – Zabuzard Oct 22 '19 at 19:30
  • 1
    @Zabuza I thought about that too but this iterates over all the methods to check if the names match. Take a look at the implementation. – Alex R Oct 22 '19 at 19:32
  • Good point. Was about to write an answer, but then its not O(1) anymore, thanks. – Zabuzard Oct 22 '19 at 19:35
  • 1
    @Zabuza Well, at least I think that is does (`getDeclaredMethod` does it). The code looks rather complicated and even has some native calls. – Alex R Oct 22 '19 at 19:46