Введіть умовивід у 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; }));

Таким чином, виразний вислів "умовивід типу не вимагає розширення системи типів" є в основному правильним.

Але повернусь до синтаксичного цукру, я повторю своє твердження, що лямбда-вираз не є синтаксичним цукром для анонімного внутрішнього класу. Ратчет урод заявив, що лямбда-вираз перекладається на анонімний внутрішній клас, і Спарклєші просто підтвердив, що лямбда - синтаксичний цукор для анонімного внутрішнього класу, але ці твердження є невірними. Вони, ймовірно, ґрунтуються на застарілій інформації. Ранні впровадження лямбда реалізували лямбдаси таким чином, але все змінилося.

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

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

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» Lambda: Peek Under the Hood .


2
"вони сприймають це по-різному. У внутрішньому класі це внутрішній клас екземпляра, тоді як у лямбда - це екземпляр, що додається. Враховуйте наступне:" все-таки можна зробити синтаксичний цукор, замінивши все thisнаMyClass.this
храповик урод

4
Все, що виходить за рамки асемблера (а іноді навіть і цього) - це, певно, синтаксичний цукор. Але лямбда - це не синтаксичний цукор для внутрішніх класів (більше). Вони служать подібній меті і мають деякі схожість, але під кришкою вони (спостережно) різні.
Йоахім Зауер

1
"Лямбда-вирази семантично відрізняються від внутрішніх класів, і вони реалізовані по-різному від внутрішніх класів.": Дякую за дуже хороше пояснення (+1). Що ще мені незрозуміло - це те, чому лямбда не були реалізовані як синтаксичний цукор для спеціальних анонімних класів, або, іншими словами, у чому полягає перевага додаткової складності, яку запроваджує нова семантика? Яку проблему вирішує ця проблема, яку неможливо вирішити анонімними внутрішніми класами? (Але я все ще мушу переглянути посилання, яке ви опублікували, можливо, там знайду відповідь.)
Джорджіо

1
@Joachim Sauer: Я вважав би синтаксичний цукор новим синтаксисом для існуючої семантики. Коли вводиться нова семантика, я думаю, що ви не можете говорити про синтаксичний цукор. У цьому сенсі я не думаю, що ви можете стверджувати, що все, що виходить за рамки асемблера, - це синтаксичний цукор.
Джорджіо

3
@ Джорджо: щодо того, чому лямбда - це не просто синтаксичний цукор для анонімних внутрішніх класів, виявляється, про це велика дискусія. Цей лист від Брайана Геца підсумовує рішення: mail.openjdk.java.net/pipermail/lambda-dev/2011-August/… . TL; DR це залишає двері відкритими для подальшої еволюції, і ми сьогодні отримуємо кращі показники. Насправді Гец відповідає на відповідне запитання, чи є об'єкти лямбда? Але якщо відповідь "Ні" чи "Можливо", це означає, що вони не можуть бути цукром для внутрішніх класів.
Стюарт Маркс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.