Java 8 lambda Void argument

Let's say I have the following functional interface in Java 8:

interface Action<T, U> {
   U execute(T t);
}

And for some cases I need an action without arguments or return type. So I write something like this:

Action<Void, Void> a = () -> { System.out.println("Do nothing!"); };

However, it gives me compile error, I need to write it as

Action<Void, Void> a = (Void v) -> { System.out.println("Do nothing!"); return null;};

Which is ugly. Is there any way to get rid of the Void type parameter?


Solution 1:

Use Supplier if it takes nothing, but returns something.

Use Consumer if it takes something, but returns nothing.

Use Callable if it returns a result and might throw (most akin to Thunk in general CS terms).

Use Runnable if it does neither and cannot throw.

Solution 2:

I think this table is short and usefull:

Supplier       ()    -> x
Consumer       x     -> ()
BiConsumer     x, y  -> ()
Callable       ()    -> x throws ex
Runnable       ()    -> ()
Function       x     -> y
BiFunction     x,y   -> z
Predicate      x     -> boolean
UnaryOperator  x1    -> x2
BinaryOperator x1,x2 -> x3

As said on the other answers, the appropriate option for this problem is a Runnable

Solution 3:

The syntax you're after is possible with a little helper function that converts a Runnable into Action<Void, Void> (you can place it in Action for example):

public static Action<Void, Void> action(Runnable runnable) {
    return (v) -> {
        runnable.run();
        return null;
    };
}

// Somewhere else in your code
 Action<Void, Void> action = action(() -> System.out.println("foo"));

Solution 4:

The lambda:

() -> { System.out.println("Do nothing!"); };

actually represents an implementation for an interface like:

public interface Something {
    void action();
}

which is completely different than the one you've defined. That's why you get an error.

Since you can't extend your @FunctionalInterface, nor introduce a brand new one, then I think you don't have much options. You can use the Optional<T> interfaces to denote that some of the values (return type or method parameter) is missing, though. However, this won't make the lambda body simpler.

Solution 5:

You can create a sub-interface for that special case:

interface Command extends Action<Void, Void> {
  default Void execute(Void v) {
    execute();
    return null;
  }
  void execute();
}

It uses a default method to override the inherited parameterized method Void execute(Void), delegating the call to the simpler method void execute().

The result is that it's much simpler to use:

Command c = () -> System.out.println("Do nothing!");