方法引用不满足功能接口契约,但它编译。怎么可能?
Method reference does not fulfil the functional interface contract but it compile. How it is possible?
在下面的 class 中,我将方法引用 WordCounterEx::accumulate
作为第二个参数传递给 reduce 方法。 reduce方法的签名是:
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
因此reduce方法的第二个参数,必须满足BiFunction配方。
但是传递的 accumulate 方法不是 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*/);
}
}
accumulate()
是实例方法,您通过 class 名称和方法名称(而不是实例和方法名称)来引用它。所以如果我想调用你给我的方法,我通常会做 myEx.accumulate(myCh)
。因此,我提供了两件事,WordCounterEx
实例和角色。因此,以这种方式使用该方法算作 BiFunction<WordCounterEx, ? super Character, WordCounterEx>
.
如果你给了我 this::accumulate
,调用方法的对象就会被给定 (this
),它不能再用作 BiFunction
(在我的 Eclipse 中,我得到“Stream 类型中的方法 reduce(U, BiFunction, BinaryOperator) 不适用于参数 (WordCounterEx, this::accumulate, WordCounterEx::combine)”)。
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
在下面的 class 中,我将方法引用 WordCounterEx::accumulate
作为第二个参数传递给 reduce 方法。 reduce方法的签名是:
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
因此reduce方法的第二个参数,必须满足BiFunction配方。 但是传递的 accumulate 方法不是 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*/);
}
}
accumulate()
是实例方法,您通过 class 名称和方法名称(而不是实例和方法名称)来引用它。所以如果我想调用你给我的方法,我通常会做 myEx.accumulate(myCh)
。因此,我提供了两件事,WordCounterEx
实例和角色。因此,以这种方式使用该方法算作 BiFunction<WordCounterEx, ? super Character, WordCounterEx>
.
如果你给了我 this::accumulate
,调用方法的对象就会被给定 (this
),它不能再用作 BiFunction
(在我的 Eclipse 中,我得到“Stream 类型中的方法 reduce(U, BiFunction, BinaryOperator) 不适用于参数 (WordCounterEx, this::accumulate, WordCounterEx::combine)”)。
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