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

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

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;

Имеют ли случаи особые имена? Есть ли пример, похожий на использование?

Ответ 1

Прежде всего, это называется свидетелем типа (в официальном учебнике Oracle) или TypeArguments (в JLS Sec 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 - но это не общий характер, поэтому она игнорируется.

Ответ 2

В:

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

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

Пока в:

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

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


1 - В этом конкретном случае аргумент типа игнорируется в соответствии с JLS §15.12.2.1 :

Не общий метод может быть потенциально применим к вызову, который предоставляет аргументы явного типа.В таком случае аргументы типа просто игнорируются.

Ответ 3

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

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

Явные аргументы типа можно вывести

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

Аргументы типа являются избыточными для ссылки на не общий метод

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

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 не является общей), поэтому можно с уверенностью предположить, что обе ссылки на методы эквивалентны.