Java Lambdas и закрытие

Я слышал, что lambdas скоро появятся на Java рядом с вами (J8). Я нашел пример того, как они будут выглядеть на каком-то блоге:

SoccerService soccerService = (teamA, teamB) -> {
    SoccerResult result = null;
    if (teamA == teamB) {
        result = SoccerResult.DRAW;
    }
    else if(teamA < teamB) {
        result = SoccerResult.LOST;
    }
    else {
        result = SoccerResult.WON;
    }

    return result;
};

Итак, прямо с места в карьер:

  • Где указаны teamA и teamB? Или они (как какая-то странная форма дженериков)?
  • Является ли лямбда типом закрытия, или это наоборот?
  • Какие преимущества это даст мне типичную анонимную функцию?

Ответ 1

Выражение Lambda - это просто синтаксический сахар для реализации целевого интерфейса, это означает, что вы реализуете конкретный метод в интерфейсе посредством выражения лямбда. Компилятор может вывести типы параметров в интерфейсе и почему вам не нужно явно определять их в выражении лямбда.

Например:

Comparator<String> c = (s1, s2) -> s1.compareToIgnoreCase(s2);

В этом выражении выражение лямбда очевидно реализует строки Comparator, поэтому это означает, что лямбда-выражение является синтаксическим сахаром для реализации compare(String, String).

Таким образом, компилятор может с уверенностью предположить тип s1 и s2 is String.

Тип вашего целевого интерфейса предоставляет всю информацию, которую компилятор должен определить, каковы фактические типы параметров лямбда.

Брайант Гетц, разработчик Java Language Architect в Oracle Corportion, опубликовал пару статей, посвященных работе JDK 8 Lambdas. Я считаю, что ответы на ваши вопросы есть:

Эта вторая статья объясняет, как лямбда-выражения реализуются на уровне байт-кода и могут помочь вам углубиться в детали вашего второго вопроса.

Ответ 2

См. эту страницу для полной версии этого примера (однако соответствующие разделы показаны ниже).

Типы выводятся из интерфейса SoccerService и перечисления SoccerResult, не показаны в вашем фрагменте:

enum SoccerResult{
    WON, LOST, DRAW
}

interface SoccerService {
    SoccerResult getSoccerResult(Integer teamA, Integer teamB);
}

Выгода (от lambdas по сравнению с обычными анонимными классами) - это просто сокращенная многословность:

(x, y) => x + y

против чего-то вроде:

new Adder()
{
  public int add(int x, int y)
  {
    return x + y;
  }
}

Для разницы между замыканием и лямбдой см. этот вопрос.

Ответ 3

  • Где введена командаA и teamB? Или они (как какая-то странная форма дженериков)?

Использовать целевую типизацию Lambda, так же как вызовы общих методов (начиная с 1.5) и алмазный [не an] оператор (начиная с 1.7). Грубо говоря, где тип, к которому применяется результат, указан (или может быть выведен), который используется для обеспечения типа базового типа Single Abstract Method (SAM) и, следовательно, типов параметров метода.

В качестве примера вывода общего метода в 1.5:

Set<Team> noTeams = Collections.emptySet(); 

И оператор алмаза в 1.7:

Set<Team> aTeams = new HashSet<>();

Команда, команда, команда, команда, команда, команда. Мне даже нравится говорить слово команда.

  • Является ли лямбда типом закрытия, или это наоборот?

Лямбда - ограниченная форма закрытия почти так же, как анонимные внутренние классы, но с некоторыми случайными различиями, чтобы выгнать вас:

Внешний this не скрывается внутренней this. Это означает, что тот же текст в лямбде и анонимном внутреннем классе может означать тонко, но совершенно разные вещи. Это должно держать Qaru занятым странными вопросами.

Чтобы восполнить недостаток внутренней this, если она назначена непосредственно локальной переменной, это значение доступно в пределах лямбда. IIRC (я мог бы проверить, но не привык), в анонимном внутреннем классе локальный будет в области видимости и скрыть переменные во внешнем пространстве, но вы не сможете его использовать. Я считаю, что отсутствие инициализатора экземпляра делает это намного проще.

Локальные поля, которые не помечены final, но могут быть обработаны так, как будто они final. Таким образом, они не входят в сферу действия, но вы можете читать (хотя и не писать) их.

  • Какие преимущества это даст мне типичную анонимную функцию?

Брачный синтаксис. Что об этом.

Конечно, остальная часть синтаксиса Java так же безнадежно плоха, как когда-либо.

Я не считаю, что это в начальной реализации, но вместо того, чтобы быть реализованным как [внутренние] классы, lambdas может использовать обработчики методов. Производительность ручек метода несколько отстает от предыдущих прогнозов. Уход с классами должен уменьшить охват байт-кода, возможно, время выполнения и, конечно же, время загрузки класса. Может существовать реализация, в которой большинство анонимных внутренних классов (не Serializable, тривиальный статический инициализатор) не прошли через плохо продуманный механизм загрузки классов без каких-либо особо заметных несовместимостей.

(Надеюсь, у меня есть правильная терминология, верная.)