Я не следил за процессом и развитием лямбда-предложения Java 7, я даже не уверен в том, какова последняя формулировка предложения.Рассматривайте это как разглагольствование / мнение, а не заявления правды.Кроме того, я не использовал Java целую вечность, поэтому синтаксис может быть ржавым и неправильным в некоторых местах.
Во-первых, каковы лямбды для языка Java?Синтаксический сахар.Хотя в целом лямбда-коды позволяют коду создавать небольшие функциональные объекты на месте, эта поддержка уже была задана - в некоторой степени - в языке Java с помощью внутренних классов.
Так насколько лучше синтаксислямбды?Где он превосходит предыдущие языковые конструкции?Где это может быть лучше?
Для начала мне не нравится тот факт, что есть два доступных синтаксиса для лямбда-функций (но это идет в строке C #, поэтому я думаю, что мое мнение не является широко распространенным. Я думаю, еслимы хотим приукрашивать, тогда #(int x)(x*x)
слаще #(int x){ return x*x; }
, даже если двойной синтаксис ничего не добавляет. Я бы предпочел второй синтаксис, более общий, за дополнительную плату написания return
и ;
в коротких версиях.
Чтобы быть действительно полезными, лямбды могут брать переменные из области видимости, в которой они определены, и из замыкания . В соответствии с внутренними классами, лямбды ограничены захват «эффективно окончательных» переменных. Согласованность с предыдущими функциями языка - хорошая возможность, но для удобства было бы хорошо иметь возможность собирать переменные, которые могут быть переназначены. Для этой цели ониучитывая, что переменные, присутствующие в контексте и помеченные @Shared
, будут захвачены по ссылкеrence , разрешающий присваивания.Мне это кажется странным, так как лямбда может использовать переменную, которая определяется в месте объявления переменной, а не там, где определяется лямбда.Одна переменная может использоваться в более чем одной лямбде, и это приводит к одинаковому поведению во всех них.
Лямбды пытаются симулировать реальные функциональные объекты, но предложение не доходит до конца: сохранить синтаксический анализатор простым, поскольку до настоящего времени идентификатор обозначает либо объект, либо метод, который был согласованным, и для вызова лямбда-выражения требуется использовать !
после имени лямбда-выражения: #(int x)(x*x)!(5)
вернет 25
.Это дает новый синтаксис для использования с лямбдами, которые отличаются от остального языка, где !
обозначает каким-то образом как синоним для .execute
в виртуальном универсальном интерфейсе Lambda<Result,Args...>
, но почему бы не сделатьон завершен?
Можно создать новый универсальный (виртуальный) интерфейс Lambda
.Он должен быть виртуальным, поскольку интерфейс не является реальным интерфейсом, а представляет собой семейство таких элементов: Lambda<Return>
, Lambda<Return,Arg1>
, Lambda<Return,Arg1,Arg2>
... Они могут определять один метод выполнения, на который я бы хотел походитьC ++ operator()
, но если это бремя, тогда подойдет любое другое имя, приняв !
в качестве ярлыка для выполнения метода:
interface Lambda<R> {
R exec();
}
interface Lambda<R,A> {
R exec( A a );
}
Тогда компилятору нужно только перевести identifier!(args)
до identifier.exec( args )
, что просто.Перевод лямбда-синтаксиса потребовал бы, чтобы компилятор идентифицировал надлежащий реализуемый интерфейс, и мог бы соответствовать:
#( int x )(x *x)
// translated to
new Lambda<int,int>{ int exec( int x ) { return x*x; } }
Это также позволило бы пользователям определять внутренние классы, которые можно использовать как лямбда-выражения, в болеесложные ситуации.Например, если лямбда-функция должна была захватывать переменную, аннотированную как @Shared
только для чтения, или поддерживать состояние захваченного объекта в месте захвата, ручная реализация лямбды будет доступна:
new Lambda<int,int>{ int value = context_value;
int exec( int x ) { return x * context_value; }
};
Таким же образом, как текущее определение классов Inner, и, следовательно, естественным для текущих пользователей Java.Это может быть использовано, например, в цикле для генерации лямбда-множителя:
Lambda<int,int> array[10] = new Lambda<int,int>[10]();
for (int i = 0; i < 10; ++i ) {
array[i] = new Lambda<int,int>{ final int multiplier = i;
int exec( int x ) { return x * multiplier; }
};
}
// note this is disallowed in the current proposal, as `i` is
// not effectively final and as such cannot be 'captured'. Also
// if `i` was marked @Shared, then all the lambdas would share
// the same `i` as the loop and thus would produce the same
// result: multiply by 10 --probably quite unexpectedly.
//
// I am aware that this can be rewritten as:
// for (int ii = 0; ii < 10; ++ii ) { final int i = ii; ...
//
// but that is not simplifying the system, just pushing the
// complexity outside of the lambda.
Это позволит использовать лямбда-выражения и методы, которые принимают лямбда-выражения как с новым простым синтаксисом: #(int x){ return x*x; }
или с болеесложный ручной подход для особых случаев, когда сахарное покрытие мешает предполагаемой семантике.
В целом, я считаю, что лямбда-предложение может быть улучшено в разных направлениях, что способ добавления синтаксического сахара - это утечка абстракции (вы имеете дело с внешними проблемами, характерными для лямбды), и это не предоставляяинтерфейс уровня делает пользовательский код менее читаемым в случаях использования, которые не совсем подходят для простого варианта использования.: