Вывод типа в Java 8

30

Собирается ли введение новой лямбда-нотации (см., Например, эту статью ) в Java 8 какого-либо вывода типа?

Если да, то как новая система типов повлияет на язык Java в целом?

Джорджио
источник

Ответы:

47

В ответе фаната трещоток и в ветке комментариев есть немало неверной информации . Я отвечу здесь в ответе, так как комментарий слишком мал. Кроме того, так как это ответ в конце концов, я попытаюсь ответить и на оригинальный вопрос. (Обратите внимание, что я не эксперт по системам типов.)

Во-первых, краткими ответами на первоначальный вопрос являются «Да» и «Нет». Да, в Java 8 будет значительно больше выводов типов, чем в Java 7, и «Нет», в Java 8 нет «новой» системы типов, хотя есть некоторые небольшие изменения. ,

Java 8 по-прежнему будет статически типизированной, и у нее все еще будет дихотомия между классами и интерфейсами. Нет новых типов, таких как типы функций. Тип лямбды - это, по сути, «функциональный интерфейс», который представляет собой обычный интерфейс с одним абстрактным методом.

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

Любой тип, который определяется выводом типа, может быть записан явно. Чтобы использовать пример с трещоткой ,

Collections.<MyClass>sort(list, (a, b) -> { return a.order - b.order; });

в основном сахар для

Collections.<MyClass>sort(list,
    (Comparator<MyClass>)((MyClass a, MyClass b) -> { return a.order - b.order; }));

Так sparkleshy «s заявление„умозаключение типа не требует какого - либо расширения системы типа“в основном правильно.

Но чтобы вернуться к синтаксическому сахару, я повторю свое утверждение, что лямбда-выражение не является синтаксическим сахаром для анонимного внутреннего класса. Чокнутый Ratchet заявил, что лямбда-выражение транслируется в создание экземпляра анонимного внутреннего класса, и Спарклеши просто подтвердил, что лямбда является синтаксическим сахаром для анонимного внутреннего класса, но эти утверждения неверны. Вероятно, они основаны на устаревшей информации. Ранние лямбда-реализации действительно реализовывали лямбды таким образом, но все изменилось.

Лямбда-выражения семантически отличаются от внутренних классов и реализуются иначе, чем внутренние классы.

Лямбда-выражения семантически отличаются от внутренних классов несколькими способами. Оценка лямбда-выражения не должна каждый раз создавать новый экземпляр. Они также имеют различную семантику захвата, например, они фиксируют это по- разному. Во внутреннем классе, это является экземпляр внутреннего класса, в то время как в лямбда, это является экземпляр вшита. Учтите следующее:

public class CaptureThis {
    void a(Runnable r) { r.run(); }

    void b() {
        a(new Runnable() { public void run() { System.out.println(this); }});
        a(() -> System.out.println(this));
    }

    public String toString() { return "outer"; }

    public static void main(String[] args) { new CaptureThis().b(); }
}

В недавней лямбда-сборке JDK 8 (я использовал b69 ) вывод будет примерно таким:

CaptureThis$1@113de03
outer

Кроме того, лямбда-выражения реализованы совершенно иначе, чем внутренние классы. Если вы сравните дизассемблированный вывод, то увидите, что код внутреннего класса напрямую компилируется с созданием и вызывает конструктор CaptureThis $ 1, тогда как лямбда-выражение компилируется в вызываемую динамическую инструкцию, которая получает Runnable через, означает неопределенное. Полное объяснение того, как это работает и почему, см. В докладе Брайана Гетца «JavaOne 2012», « Лямбда: взгляд под капотом» .

Стюарт Маркс
источник
2
«Они воспринимают это по-разному. Во внутреннем классе это экземпляр внутреннего класса, тогда как в лямбда-выражениях это экземпляр включения. Рассмотрим следующее:« все еще можно сделать с синтаксическим сахаром, заменив все thisнаMyClass.this
ratchet freak
4
Все, что выходит за рамки ассемблера (и иногда даже этого), возможно, является синтаксическим сахаром. Но лямбды не являются синтаксическим сахаром для внутренних классов (больше). Они служат сходной цели и имеют некоторое сходство, но под капотом они (заметно) различны.
Иоахим Зауэр
1
«Лямбда-выражения семантически отличаются от внутренних классов и реализуются не так, как внутренние классы.»: Спасибо за очень хорошее объяснение (+1). Для меня все еще неясно, почему лямбды не были реализованы как синтаксический сахар для специальных анонимных классов или, другими словами, в чем преимущество дополнительной сложности, введенной новой семантикой? Какую проблему это решает, которая не может быть решена с помощью анонимных внутренних классов? (Но я все еще должен посмотреть на ссылку, которую вы разместили, может быть, я найду ответ там.)
Джорджио
1
@Joachim Sauer: я бы посчитал синтаксический сахар новым синтаксисом для существующей семантики. Когда вводится новая семантика, я думаю, что вы не можете говорить о синтаксическом сахаре. В этом смысле я не думаю, что вы можете утверждать, что все, кроме ассемблера, является синтаксическим сахаром.
Джорджио
3
@ Джорджио: о том, почему лямбда не просто синтаксический сахар для анонимных внутренних классов, выясняется, что об этом шла большая дискуссия. Это письмо от Брайана Гетца резюмирует решение: mail.openjdk.java.net/pipermail/lambda-dev/2011-August/… . TL; DR оставляет дверь открытой для будущей эволюции, и мы получаем лучшую производительность сегодня. Гетц фактически отвечает на связанный вопрос, являются ли объекты лямбды? Но если ответ «Нет» или даже «Может быть», это означает, что они не могут быть сахаром для внутренних классов.
Стюарт Маркс