Тип ссылки на универсальный метод, определяющий до / после :: оператор

В чем разница между следующими ссылками на методы,

BiPredicate<List<String>,String> contains1 = List<String>::contains;

BiPredicate<List<String>,String> contains2 = List::<String>contains;

BiPredicate<List<String>,String> contains3 = List<String>::<String>contains;

У кейсов есть особые названия? Есть ли какой-нибудь пример, похожий на использование?

Связанный: stackoverflow.com/questions/31245127/…. Кажется, что первый синтаксис определяет аргумент типа для List, тогда как второй указывает аргумент типа для contains (в этом случае необязательно, потому что метод не является универсальным)

ernest_k 10.08.2018 14:44

И, конечно же, BiPredicate<List<String>,String> contains1 = List<String>::<String>contains;.

Andy Turner 10.08.2018 14:45

В качестве дополнительного примечания и частичного объяснения: разрешено передавать аргументы типа неуниверсальному методу, например list.<Number>contains("foo"). Их просто игнорируют. (Что касается того, почему авторы JLS решили разрешить это, я не знаю.)

Radiodef 10.08.2018 18:53

@Radiodef Я не знаю точной причины, но подозреваю, что вы Герберт Шильдт

snr 10.08.2018 19:36

@Radiodef кстати действительно интересно, list.<RandomAccess>contains("foo"); и list.<ClassLoader>contains("foo");

snr 10.08.2018 19:44

@snr Почему разрешено передавать аргументы типа неуниверсальному методу? Вы можете найти ответ здесь.

Oleksandr Pyrohov 10.08.2018 22:03
17
6
780
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вот что мне о них рассказывает Intellij:

BiPredicate<List<String>, String> contains1 = List<String>::contains;

Explicit type arguments can be inferred

BiPredicate<List<String>, String> contains2 = List::<String>contains;

Type arguments are redundant for the non-generic method reference

Если бы вы разбили их на соответствующие лямбда-функции, я полагаю, вы бы увидели следующее:

BiPredicate<List<String>, String> contains1 = (List<String> strings, String o) -> strings.contains(o);
BiPredicate<List<String>, String> contains2 = (strings, o) -> strings.<String>contains(o);

Как мы знаем, (List<String> strings, String o) можно заменить на (strings, o), а <String> во второй строке не нужен (поскольку String#contains не является универсальным), поэтому можно с уверенностью предположить, что обе ссылки на методы эквивалентны.

Ответ принят как подходящий

Прежде всего, это называется тип свидетель (в официальном руководстве Oracle) или ТипАргументыJLS, раздел 15.12), и вы эффективно помогаете компилятору с такими конструкциями.

Один пример:

private static void test(Callable<Object> call) {

}

private static void test(Runnable run) {

}

static class Gen<T> {

}

И вызовите его через test(Gen::new); (это не удастся, неважно почему), но дело в том, что вы добавляете тип свидетель, чтобы помочь компилятору, так что это сработает

test(Gen<String>::new);

Итак, когда вы пишете List<String>, вы добавляете тип-свидетель для целевого типа - то есть List; во втором случае вы добавляете один для метода contains, но он не является универсальным, поэтому игнорируется.

Откуда появился термин «типовой свидетель»? Я не могу найти его в спецификации языка.

Andy Turner 10.08.2018 14:50

@AndyTurner docs.oracle.com/javase/tutorial/java/generics/… ищите "тип свидетель", я не говорил, что он находится в JLS (может быть, не уверен)

Eugene 10.08.2018 14:51

@Lino в официальном руководстве по java это называется так, я буду придерживаться этого :)

Eugene 10.08.2018 14:56

Слово «свидетель» не встречается в JLS (по крайней мере, 9). Там их просто называют TypeArguments.

Andy Turner 10.08.2018 14:58

В:

BiPredicate<List<String>, String> contains2 = List::<String>contains;

<String> - это аргумент типа неуниверсального метода List.contains1.

Пока в:

BiPredicate<List<String>, String> contains1 = List<String>::contains;

<String> - это аргумент типа для List.


1 - In this particular case a type argument is ignored according to the JLS §15.12.2.1:

A non-generic method may be potentially applicable to an invocation that supplies explicit type arguments. In such a case, the type arguments will simply be ignored.

Есть ли разница между терминами параметр типа и аргумент типа в этом контексте? Если да, то что это?

snr 10.08.2018 20:41

Да, разница есть. E в List<E> - это параметр типа, а String в List<String> - это аргумент типа. Вы можете думать о вызове универсального типа как о вызове обычного метода, но вместо передачи аргумента методу вы передаете аргумент типа - в данном случае String - самому List(источник).

Oleksandr Pyrohov 10.08.2018 21:09

Другие вопросы по теме