Search code examples
javac#actionconsumer

Mimic C# Actions in Java 8


Actions are nice because you can just pass an arbitrary function returning void as a parameter.

Use cases? Any function wrappers like for example Timers.

So bascially in C# I can write a method

private static void Measure(Action block) {
    var watch = new Stopwatch();
    watch.Start();
    block();
    watch.Stop();
    Console.WriteLine(watch.ElapsedMilliseconds);
}

and use it like

public static void Main(string[] args) {
    Measure(() => {Console.WriteLine("Hello");});
}

to measure the time elapsed for that method. Pretty neat. Now if I want to mimic this in Java I need to write a method

private static <T> Consumer<T> measure(Consumer<T> block) {
        return t -> {
            long start = System.nanoTime();
            block.accept(t);
            System.out.printf("Time elapsed: %d Milliseconds\n", (System.nanoTime() - start) / 1000);
        };
    }

and use it like

public static void main(String[] args) {
    measure(Void -> System.out.println("Hello")).accept(null);
}

Problems:

  1. Consumers expect only a single argument while Actions can be anything that returns void.
  2. Since I can not simply call block() in Java, I need to pass it a redundant null parameter.
  3. For the latter reason, I have to make measure() itself returning a Consumer.

Question: - Could I mimic this by using a method instead of an external Consumer, thus making the null parameter obsolete?


Solution

  • For a no-args method, you can use a Runnable instead of a Consumer.

    private static Runnable measure(Runnable block) {
        return () -> {
            long start = System.nanoTime();
            block.run();
            System.out.printf("Time elapsed: %d Milliseconds\n", (System.nanoTime() - start) / 1000);
        };
    }
    

    And then:

    public static void main(String[] args) {
        measure(System.out::println("Hello")).run();
    }
    

    Though, now that I think about it, you don't really need to return the Runnable:

    private static void measure(Runnable block) {
            long start = System.nanoTime();
            block.run();
            System.out.printf("Time elapsed: %d Milliseconds\n", (System.nanoTime() - start) / 1000);
    }