Ссылка на метод - неверная ссылка метода - не может быть ссылкой из статического контекста
У меня есть следующий фрагмент кода
StringJoiner joiner = new StringJoiner(", ");
joiner.add("Something");
Function<StringJoiner,Integer> lengthFunc = StringJoiner::length;
Function<CharSequence,StringJoiner> addFunc = StringJoiner::add;
Последняя строка вызывает ошибку
Error:(54, 53) java: invalid method reference
non-static method add(java.lang.CharSequence) cannot be referenced from a static context
Я понимаю, что этот метод нельзя использовать статическим способом, и я должен иметь что-то вроде:
Function<CharSequence,StringJoiner> addFunc = joiner::add;
вместо этого. Однако я не могу понять, почему третья строка, с StringJoiner::length;
для java-компилятора, абсолютно корректна. Может ли кто-нибудь объяснить мне, почему?
Ответы
Ответ 1
Потому что StringJoiner.length
принимает нулевые аргументы, поэтому общая ссылка метода принимает StringJoiner
(произвольный экземпляр) и возвращает Integer
. Другими словами, первый назначенный метод ref эквивалентен:
Function<StringJoiner, Integer> lengthFunc = new Function<StringJoiner, Integer>() {
@Override
public Integer apply(StringJoiner stringJoiner) {
return stringJoiner.length;
}
}
Вы бы назвали это Function
следующим образом:
StringJoiner sj1 = ... // an arbitrary StringJoiner
int sjLength1 = lengthFunc.apply(sj1);
В контракте StringJoiner.add(CharSequence)
принимает один аргумент, поэтому в целом Function
должен был бы взять (1) экземпляр arbirary из StringJoiner
, (2) CharSequence
и вернуть a StringJoiner
.
Вместо этого вы можете назначить ссылку на BiFunction
, которая делает это:
BiFunction<StringJoiner, CharSequence, StringJoiner> addFunc = StringJoiner::add;
что эквивалентно:
BiFunction<StringJoiner, CharSequence, StringJoiner> addFunc = new BiFunction<StringJoiner, CharSequence, StringJoiner>() {
@Override
public StringJoiner apply(StringJoiner stringJoiner, CharSequence charSequence) {
return stringJoiner.add(charSequence);
}
}
и будет использоваться следующим образом:
StringJoiner sj1 = ... // an arbitrary StringJoiner
sj1 = addFunc.apply(sj1, "a"); // no need to re-assign, but just to show the return type
Ответ 2
Function<StringJoiner,Integer> lengthFunc = StringJoiner::length;
lengthFunc
- это функция, которая принимает StringJoiner
и возвращает Integer
. Поэтому любой метод экземпляра StringJoiner
, который ничего не принимает и возвращает Integer
, соответствует этому интерфейсу. Экземпляр, вызванный этим методом, будет StringJoiner
, требуемый Function<StringJoiner,Integer>
.
С другой стороны, в
Function<CharSequence,StringJoiner> addFunc = StringJoiner::add
addFunc
- это Function
, который принимает CharSequence
и возвращает StringJoiner
. Никакой метод экземпляра StringJoiner
не соответствует этому интерфейсу, так как функция не имеет входного экземпляра StringJoiner
для применения метода add
.
Вам понадобится BiFunction
для соответствия сигнатуре StringJoiner::add
:
BiFunction<StringJoiner,CharSequence,StringJoiner> addFunc = StringJoiner::add;