方法引用不满足功能接口契约,但它编译。怎么可能?

时间:2017-05-01 10:24:55

标签: java-8 java-stream method-reference

在下面的类中,我将方法引用WordCounterEx::accumulate作为第二个参数传递给reduce方法。 reduce方法的签名是:

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

因此reduce方法的第二个参数必须满足BiFunction配方。 但是传递的累积方法不是BiFunction(它只有一个参数)。为什么还要编译?

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*/);
    }
}

2 个答案:

答案 0 :(得分:3)

accumulate()是一个实例方法,您可以通过类名和方法名称(而不是实例和方法名称)来引用它。所以如果我想打电话给你的方法,我通常会myEx.accumulate(myCh)。因此,我提供了两个东西,WordCounterEx实例和角色。因此,使用这种方法时,方法计为BiFunction<WordCounterEx, ? super Character, WordCounterEx>

如果你给我举例this::accumulate,那么调用方法的对象就会被赋予(this),它不能再用作BiFunction (在我的Eclipse中我得到“Stream中的方法reduce(U,BiFunction,BinaryOperator)不适用于参数(WordCounterEx,this :: accumulate,WordCounterEx :: combine)”)。

答案 1 :(得分:1)

WordCounterEx#countWords方法可以按如下方式重写:

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;
    }
}

在这种情况下,accumulate方法必须在其签名

中有WordCounterEx wc