Почему имя класса/объекта должно быть явно указано для ссылок на методы?

Когда я хочу сослаться на метод в текущей области, мне все равно нужно указать имя класса (для статических методов) или this перед оператором ::. Например, мне нужно написать:

import java.util.stream.Stream;

public class StreamTest {
    public static int trimmedLength(String s) {
        return s.trim().length();
    }

    public static void main(String[] args) {
        System.out.println(Stream.of("  aaa  ", "  bb ", " c ")
                .mapToInt(StreamTest::trimmedLength).sum());
    }
}

Это не такая уж большая проблема для this, но иногда статические методы выглядят переполненными, так как имя класса может быть довольно длинным. Было бы неплохо, если бы компилятор позволил мне вместо этого написать просто ::trimmedLength:

public static void main(String[] args) {
    System.out.println(Stream.of("  aaa  ", "  bb ", " c ")
            .mapToInt(::trimmedLength).sum());
}

Однако компилятор Java-8 этого не позволяет. Мне кажется, что было бы вполне логично, если бы имя класса/объекта разрешалось так же, как это делается для обычного вызова метода. Это также будет поддерживать статический импорт для ссылок на методы, что также может быть полезно в некоторых случаях.

Итак, вопрос в том, почему такой или подобный синтаксис не был реализован в Java 8? Возникнут ли проблемы с таким синтаксисом? Или это просто вообще не рассматривалось?


person Tagir Valeev    schedule 15.05.2015    source источник
comment
Вы смотрели обсуждение этого синтаксиса в JCP? Бьюсь об заклад, есть много, что вы можете найти об этой и других идеях.   -  person    schedule 15.05.2015
comment
Нет, я не. Было бы неплохо, если бы вы указали точные сообщения/мнения по моему вопросу.   -  person Tagir Valeev    schedule 15.05.2015


Ответы (1)


Я не могу говорить за разработчиков Java, но есть некоторые вещи, которые следует учитывать:

Существуют определенные виды ссылок на методы:

  1. Ссылка на статический метод, например. ContainingClass::staticMethodName
  2. Ссылка на метод экземпляра конкретного объекта, например. containingObject::instanceMethodName
  3. Ссылка на метод экземпляра произвольного объекта определенного типа, например. ContainingType::methodName
  4. Ссылка на конструктор, например. ClassName::new

Компилятор уже должен проделать некоторую работу, чтобы устранить неоднозначность форм 1 и 3, и иногда это не удается. Если форма ::methodName была разрешена, компилятор должен был устранить неоднозначность между тремя различными формами, поскольку это могла быть любая из трех форм от 1 до 3.

Тем не менее, если разрешить форме ::methodName сокращать любую из форм с 1 по 3, это все равно не будет означать, что она эквивалентна форме methodName(…), поскольку выражение simpleName ( argopt ) может относиться к

  • метод экземпляра в области действия текущего класса или его суперклассов и интерфейсов
  • метод static в рамках текущего класса или его суперклассов
  • метод экземпляра в области внешнего класса или его суперклассов и интерфейсов
  • метод static в области внешнего класса или его суперклассов
  • метод static, объявленный через import static

Таким образом, высказывание чего-то вроде «::name должно быть разрешено ссылаться на любой метод, на который может ссылаться name(…)», подразумевает объединение возможностей этих двух списков, и вам следует дважды подумать, прежде чем загадывать желание.


И последнее замечание: у вас все еще есть возможность написать лямбда-выражение, такое как args -> name(args), которое подразумевает разрешение name как простой вызов метода формы name(args), в то же время решая проблему неоднозначности, поскольку он устраняет вариант 3 видов ссылки на метод , если только вы явно не напишете (arg1, otherargs) -> arg1.name(otherargs).

person Holger    schedule 18.05.2015
comment
Спасибо за подробный ответ. Я надеялся, что Java-разработчики ответят, но, видимо, мой вопрос им не очень интересен. - person Tagir Valeev; 18.05.2015
comment
@Holger после использования ссылки на метод в течение последних 3 месяцев я также склонен думать в стиле Тагира. Трудно понять, что ожидаемая форма ссылки на метод была опущена только потому, что компилятору нужно выполнить немного больше задач. Вместо этого компилятор может попытаться разрешить проблему. Он всегда может запросить устранение неоднозначности с полной формой, если не может разрешить. - person Mrinal; 13.09.2015
comment
@Mrinal K. Samanta: не только компилятор должен устранять неоднозначность. Человеческий читатель тоже должен это сделать. И неправильное представление о цели метода причинит больше вреда, чем может когда-либо компенсировать ввод на несколько букв меньше. - person Holger; 14.09.2015
comment
Для тех, кто ищет, здесь был ответ от @Brian Goetz: stackoverflow.com/questions/31665393/ - person xdhmoore; 20.11.2015