The method reference does not conform to the functional interface contract, but is compiled. How is this possible?

In the class below, I pass the WordCounterEx::accumulate method WordCounterEx::accumulate as the second parameter to the reduction method. Signature reduction method:

 <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner); 

Thus, the second parameter of the reduction method should correspond to the BiFunction recipe. But the accumulation method passed is not BiFunction (it has only one parameter). Why is it still compiling?

 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*/); } } 
+5
source share
2 answers

accumulate() is an instance method, and you reference it by name and class name (and not by instance name and method). Therefore, if I wanted to call the method that you give me, I would usually do myEx.accumulate(myCh) . Thus, I provide two things: an instance of WordCounterEx and a character. Therefore, using this method, the method is calculated as BiFunction<WordCounterEx, ? super Character, WordCounterEx> BiFunction<WordCounterEx, ? super Character, WordCounterEx> .

If instead you gave me, for example, this::accumulate , an object to call the on method would be specified ( this ), and it can no longer be used as a BiFunction (in my Eclipse I get a "Reduce (U, BiFunction, BinaryOperator) method) in type Stream is not applicable for arguments (WordCounterEx, this :: accumulate, WordCounterEx :: comb) ".)

+3
source

The WordCounterEx#countWords 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 accumulation method must have WordCounterEx wc in its signature

+1
source

Source: https://habr.com/ru/post/1267350/


All Articles