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

I'm playing around with Java 8 to find out how functions as first class citizens. I have the following snippet:

package test;

import java.util.*;
import java.util.function.*;

public class Test {

    public static void myForEach(List<Integer> list, Function<Integer, Void> myFunction) {
      list.forEach(functionToBlock(myFunction));
    }

    public static void displayInt(Integer i) {
      System.out.println(i);
    }


    public static void main(String[] args) {
      List<Integer> theList = new ArrayList<>();
      theList.add(1);
      theList.add(2);
      theList.add(3);
      theList.add(4);
      theList.add(5);
      theList.add(6);
      myForEach(theList, Test::displayInt);
    }
}

What I'm trying to do is pass method displayInt to method myForEach using a method reference. To compiler produces the following error:

src/test/Test.java:9: error: cannot find symbol
      list.forEach(functionToBlock(myFunction));
                   ^
  symbol:   method functionToBlock(Function<Integer,Void>)
  location: class Test
src/test/Test.java:25: error: method myForEach in class Test cannot be applied to given ty
pes;
      myForEach(theList, Test::displayInt);
      ^
  required: List<Integer>,Function<Integer,Void>
  found: List<Integer>,Test::displayInt
  reason: argument mismatch; bad return type in method reference
      void cannot be converted to Void

The compiler complains that void cannot be converted to Void. I don't know how to specify the type of the function interface in the signature of myForEach such that the code compiles. I know I could simply change the return type of displayInt to Void and then return null. However, there may be situations where it's not possible to alter the method I want to pass somewhere else. Is there an easy way to reuse displayInt as it is?

This question is related to java java-8

The answer is


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.


I feel you should be using the Consumer interface instead of Function<T, R>.

A Consumer is basically a functional interface designed to accept a value and return nothing (i.e void)

In your case, you can create a consumer elsewhere in your code like this:

Consumer<Integer> myFunction = x -> {
    System.out.println("processing value: " + x);    
    .... do some more things with "x" which returns nothing...
}

Then you can replace your myForEach code with below snippet:

public static void myForEach(List<Integer> list, Consumer<Integer> myFunction) 
{
  list.forEach(x->myFunction.accept(x));
}

You treat myFunction as a first-class object.


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;});

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.