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).
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...)
.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With