6

I found an interesting example of using Stream API:

Stream<String> stream = Stream.of("w", "o", "l", "f");
BiConsumer<StringBuilder, String> append = StringBuilder::append;
StringBuilder collected = stream.collect(StringBuilder::new, append, StringBuilder::append);
System.out.println(collected); //it works correctly

Stream.collect takes three parameters:

Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner

BiConsumer takes two parameters and doesn't return anything. Why this line compiles and works?

BiConsumer<StringBuilder, String> append = StringBuilder::append;

StringBuilder doesn't have void method append(java.lang.StringBuilder, java.lang.String).

3
  • 5
    The first argument becomes the object on which the method is invoked. And StringBuilder.append(String) does exist. Commented May 4, 2016 at 20:05
  • 2
    One thing that helps me to wrap my head around it is that a member function is really no different than a static function with an extra parameter for this. Whenever you see ClassName::memberFunction, the first parameter is always ClassName this Commented May 4, 2016 at 20:52
  • I don't see an answer for this in the mentioned duplicate. Any body care to elaborate? I have the same problem. Since append is not a void method and BiConsumer's non abstract method has a void method how above code compiles? Commented Feb 10, 2017 at 14:24

2 Answers 2

3

JLS 15.13.3 specifies more or less that the receiver -- the object the method is being called on -- can become the first argument for the functional interface:

If the form is ReferenceType :: [TypeArguments] Identifier, the body of the invocation method similarly has the effect of a method invocation expression for a compile-time declaration which is the compile-time declaration of the method reference expression. Run-time evaluation of the method invocation expression is as specified in §15.12.4.3, §15.12.4.4, and §15.12.4.5, where:

The invocation mode is derived from the compile-time declaration as specified in §15.12.3.

If the compile-time declaration is an instance method, then the target reference is the first formal parameter of the invocation method. Otherwise, there is no target reference.

If the compile-time declaration is an instance method, then the arguments to the method invocation expression (if any) are the second and subsequent formal parameters of the invocation method. Otherwise, the arguments to the method invocation expression are the formal parameters of the invocation method.

The compile-time declaration is in fact an instance method, so the StringBuilder becomes the first parameter of the invocation method, and the String becomes the second.

In other words, the method reference SomeClass::instanceMethod is equivalent to the lambda (SomeClass receiver, args...) -> receiver.instanceMethod(args...).

Sign up to request clarification or add additional context in comments.

Comments

2

The first type argument of the BiConsumer is the type the method is applied on, and the second is the method's single parameter. The classic example would be ArrayList::add.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.