How to specify function types for void (not Void) methods in Java8?

Solution 1:

You are trying to use the wrong interface type. The type Function is not appropriate in this case because it receives a parameter and has a return value. Instead you should use Consumer (formerly known as Block)

The Function type is declared as

interface Function<T,R> {
  R apply(T t);
}

However, the Consumer type is compatible with that you are looking for:

interface Consumer<T> {
   void accept(T t);
}

As such, Consumer is compatible with methods that receive a T and return nothing (void). And this is what you want.

For instance, if I wanted to display all element in a list I could simply create a consumer for that with a lambda expression:

List<String> allJedi = asList("Luke","Obiwan","Quigon");
allJedi.forEach( jedi -> System.out.println(jedi) );

You can see above that in this case, the lambda expression receives a parameter and has no return value.

Now, if I wanted to use a method reference instead of a lambda expression to create a consume of this type, then I need a method that receives a String and returns void, right?.

I could use different types of method references, but in this case let's take advantage of an object method reference by using the println method in the System.out object, like this:

Consumer<String> block = System.out::println

Or I could simply do

allJedi.forEach(System.out::println);

The println method is appropriate because it receives a value and has a return type void, just like the accept method in Consumer.

So, in your code, you need to change your method signature to somewhat like:

public static void myForEach(List<Integer> list, Consumer<Integer> myBlock) {
   list.forEach(myBlock);
}

And then you should be able to create a consumer, using a static method reference, in your case by doing:

myForEach(theList, Test::displayInt);

Ultimately, you could even get rid of your myForEach method altogether and simply do:

theList.forEach(Test::displayInt);

About Functions as First Class Citizens

All been said, the truth is that Java 8 will not have functions as first-class citizens since a structural function type will not be added to the language. Java will simply offer an alternative way to create implementations of functional interfaces out of lambda expressions and method references. Ultimately lambda expressions and method references will be bound to object references, therefore all we have is objects as first-class citizens. The important thing is the functionality is there since we can pass objects as parameters, bound them to variable references and return them as values from other methods, then they pretty much serve a similar purpose.

Solution 2:

When you need to accept a function as argument which takes no arguments and returns no result (void), in my opinion it is still best to have something like

  public interface Thunk { void apply(); }

somewhere in your code. In my functional programming courses the word 'thunk' was used to describe such functions. Why it isn't in java.util.function is beyond my comprehension.

In other cases I find that even when java.util.function does have something that matches the signature I want - it still doesn't always feel right when the naming of the interface doesn't match the use of the function in my code. I guess it's a similar point that is made elsewhere here regarding 'Runnable' - which is a term associated with the Thread class - so while it may have he signature I need, it is still likely to confuse the reader.

Solution 3:

Set return type to Void instead of void and return null

// Modify existing method
public static Void displayInt(Integer i) {
    System.out.println(i);
    return null;
}

OR

// Or use Lambda
myForEach(theList, i -> {System.out.println(i);return null;});