Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why StringBuilder::append is BiConsumer<StringBuilder, String>? [duplicate]

Tags:

java

java-8

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).

like image 447
A. Segen Avatar asked May 04 '16 20:05

A. Segen


2 Answers

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...).

like image 104
Louis Wasserman Avatar answered Sep 30 '22 04:09

Louis Wasserman


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.

like image 41
Mureinik Avatar answered Sep 30 '22 06:09

Mureinik