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