In java 8+ are only single argument method reference permitted in a stream

Viewed 883

Is it true to say that in a Stream in Java 8, you can only use method references that take a single argument (if you disallow wrapping the method reference with a method call)?

I assume so because in a stream at any time you are processing a single item.

Therefore:

  • Something::new (must refer to a single arg constructor)
  • this::doSomething (must take a single arg)
  • Something::doSomething (must take a single arg)

...when used in a Stream. Is this rule always true?

3 Answers

No, it's not. Some of the Stream methods take functional interfaces having a method with multiple arguments.

For example, Stream's sorted(Stream<T> Comparator<? super T> comparator) method, takes a Comparator, whose method has two arguments.

Here's an example of using a method reference - String::compareTo - of a method having two arguments:

System.out.println(Stream.of("a","d","c").sorted(String::compareTo).collect(Collectors.toList()));

Stream's Optional<T> max(Comparator<? super T> comparator) method is another similar example.

There are four types of methods references:

  • A method reference to a static method i.e.

    Class::staticMethod --> (args) -> Class.staticMethod(args)

  • A method reference to an instance method of an object of a particular type. i.e.

    ObjectType::instanceMethod --> (obj, args) -> obj.instanceMethod(args)

  • A method reference to an instance method of an existing object i.e.

    obj::instanceMethod --> (args) -> obj.instanceMethod(args)

  • A method reference to a constructor i.e.

    ClassName::new --> (args) -> new ClassName(args)

As you can see with the second example, a given method can take two arguments and still be translated to a method reference, this is true for the case of calling sorted , min , max etc.. of a stream.

credit to Java 8 Method Reference: How to Use it for the examples above.

Just to add to the answer from Eran, you can possibly find a real life example better to understand.

Let's assume we have a method that adds an Integer i and an intValue of a Long l to return back as a String s representation. This would look like :

String convertToStringAfterAddingValues(Long l, Integer i) {
    return String.valueOf(l.intValue() + i);
}

In the world of FunctionalInterface, this could be represented as a BiFunction as an anonymous class:

BiFunction<Long, Integer, String> biFunctionAnonymous = new BiFunction<Long, Integer, String>() {
    @Override
    public String apply(Long l, Integer i) {
        return String.valueOf(l.intValue() + i);
    }
};

which in the lambda world could then be represented as:

BiFunction<Long, Integer, String> biFunctLambda = (l, i) -> String.valueOf(l.intValue() + i);

the same can be represented using method reference with the object of the class the method resides in as :

BiFunction<Long, Integer, String> biFunctMethodReference = <YourClassInstance>::convertToStringAfterAddingValues;
Related