In the class below, I pass the method reference WordCounterEx::accumulate
as second parameter to the reduce method. The signature of reduce method is:
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
Thus the second parameter of reduce method, must fulfil the BiFunction recipe. But the passed accumulate method is not BiFunction (it has only one parameter). Why it still compile?
public class WordCounterEx {
private final int counter;
private final boolean lastSpace;
public WordCounterEx(int counter, boolean lastSpace) {
this.counter = counter;
this.lastSpace = lastSpace;
}
public int countWords(Stream<Character> stream) {
WordCounterEx wordCounter = stream.reduce(new WordCounterEx(0, true),
//HOW CAN THIS WORK? here must come BiFunction - R apply(T t, U u);
WordCounterEx::accumulate,
WordCounterEx::combine);
return wordCounter.counter;
}
public WordCounterEx accumulate(Character c) {
if(Character.isWhitespace(c)) {
return lastSpace ?
this :
new WordCounterEx(counter, true);
} else {
return lastSpace ?
new WordCounterEx(counter+1, false) :
this;
}
}
public WordCounterEx combine(WordCounterEx wordCounter) {
return new WordCounterEx(counter + wordCounter.counter
,wordCounter.lastSpace /*does not matter*/);
}
}
accumulate()
is an instance method, and you refer to it by class name and method name (not by instance and method name). So if I wanted to call the method you are giving me, I would usually do myEx.accumulate(myCh)
. Thus I provide two things, the WordCounterEx
instance and the character. Therefore, used this way the method counts as a BiFunction<WordCounterEx, ? super Character, WordCounterEx>
.
If instead you had given me for example this::accumulate
, the object to call the method on would have been given (this
), and it could no longer be used as a BiFunction
(in my Eclipse I get “The method reduce(U, BiFunction, BinaryOperator) in the type Stream is not applicable for the arguments (WordCounterEx, this::accumulate, WordCounterEx::combine)”).
The WordCounterEx#countWords
method can be rewritten as follows:
public int countWordsWithInstance(Stream<Character> stream) {
WordCounterEx wordCounter = stream.reduce(new WordCounterEx(0, true),
this::accumulate,
WordCounterEx::combine);
return wordCounter.counter;
}
public WordCounterEx accumulate(WordCounterEx wc,Character c) {
if(Character.isWhitespace(c)) {
return wc.lastSpace ?
wc :
new WordCounterEx(wc.counter, true);
} else {
return wc.lastSpace ?
new WordCounterEx(wc.counter+1, false) :
wc;
}
}
In this case the accumulate method must have WordCounterEx wc
in its signature
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