Неоднозначность в ссылках на методы

Рассмотрим следующий фрагмент:

public static void main(String[] args) {
        Function<String, String> function = String::toUpperCase;        //OK
//        Comparator<String> comparator = String::toUpperCase;          //Compilation error(makes sense, as String.toUpperCase(Locale locale) & String.toUpperCase() are not compatible)
        fun(String::toUpperCase);                                       // java: reference to fun is ambiguous
    }

    public static void fun(Function<String, String> function) { // String apply(String obj)
        System.out.println("Function");
    }

    public static void fun(Comparator<String> comparator) {     // int compare(String s1, String s2)
        System.out.println("Comparator");
    }

Я не понимаю причину ошибки неоднозначности при вызове метода fun(String::toUpperCase).

Поскольку обе перегруженные версии String::toUpperCase сами по себе несовместимы с int compare(String s1, String s2) из класса Comparator, тогда почему компилятор вообще жалуется на неоднозначность?

Я что-то упускаю?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
12
0
590
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

toUpperCase имеет перегрузку, не принимающую параметров, и другую перегрузку, принимающую один параметр (Locale).

Это делает выражение String::toUpperCaseнеточным выражением ссылки на метод. Выражение может относиться либо к перегрузке без аргументов, либо к перегрузке с одним аргументом.

Оба fun определены как «потенциально применимые», в частности, из-за этого пункта:

  • Выражение ссылки на метод потенциально совместимо с типом функционального интерфейса T if, где арность тип функции T равен n, существует хотя бы одна потенциально применимый метод, когда выражение ссылки на метод нацелено на тип функции с арностью n и верно одно из следующих условий:

    • Выражение ссылки на метод имеет форму ReferenceType :: [TypeArguments] Identifier и по крайней мере одно потенциально применимое метод либо (i) статический и поддерживает арность n, либо (ii) не статический и поддерживает арность n-1.
    • [не имеющий отношения]

String::toUpperCase потенциально совместим с Function<String, String>, поскольку Function<String, String> имеет арность 1 (принимает один параметр), а toUpperCase нестатичен и имеет перегрузку без аргументов.

String::toUpperCase потенциально совместим с Comparator<String>, поскольку Comparator<String> имеет арность 2, а toUpperCase нестатичен и имеет перегрузку с одним аргументом. Обратите внимание, что на этом шаге вообще не проверяются типы параметров или типы возвращаемых значений. Не имеет значения, что тип параметра — Locale, но на самом деле ожидается String.

Найдя потенциально применимые методы, мы переходим к Определить методы сопоставления арности, применимые путем строгого вызова . Здесь все идет не так. Помните, String::toUpperCase является неточной ссылкой на метод? Это означает, что это не имеет отношения к применимости — компилятор вообще не учитывает ссылку на метод на этом этапе. См. также другой вопрос, который также включает неточное выражение ссылки на метод, вызывающее ошибки разрешения перегрузки.

Таким образом, оба fun применимы при строгом вызове. Следующий шаг — найти наиболее конкретный метод. На этом этапе учитывается подтип, например, String более конкретен, чем Object. Но Comparator<String> не связан с Function<String, String>, поэтому мы не можем найти наиболее конкретный метод, и возникает ошибка.

Что касается утверждения «Итак, обе забавы применимы при строгом вызове», вы имели в виду, что вместо этого они неприменимы? Поскольку String::toUpperCase действительно является неточным выражением ссылки на метод.

Rohan Jaiswal 31.05.2024 11:23

@RohanJaiswal Нет, что касается этого конкретного шага, они оба применимы, поскольку выражение ссылки на метод не имеет отношения к применимости. т. е. он не участвует в определении того, применима ли перегрузка или нет. Более строгие проверки применяются позже, но компилятор уже столкнулся с ошибкой (а именно, не существует наиболее конкретного метода) до этого момента.

Sweeper 31.05.2024 11:29

@RohanJaiswal Просто чтобы быть на одной странице: мы не определяем применимость toUpperCase. Определяем, какие перегрузки fun применимы. И на этапе строгого призыва оба варианта оказываются применимыми. Цитата: «Если m не является универсальным методом, то m применим путем строгого вызова, если для 1 ≤ i ≤ n либо ei совместим в контексте строгого вызова с Fi (§5.3), либо ei не имеет отношения к применимости. " Ссылка на метод не имеет отношения к применимости, поэтому оба fun применимы при строгом вызове, независимо от других факторов.

Sweeper 31.05.2024 13:58

@RohanJaiswal Обратите внимание, что нет необходимости учитывать, совместимо ли «ei в строгом контексте вызова с Fi», поскольку последнее дизъюнктивное «ei не имеет отношения к применимости» всегда верно. Поскольку оба метода применимы путем строгого вызова, шаги с произвольной и переменной арностью пропускаются. И да, ошибка возникает на этапе «выбора наиболее конкретного метода».

Sweeper 31.05.2024 14:01

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