Статьи

Что готовит в Java 8 — Project Lambda

Что такое проект лямбда : Проект лямбда — это проект для включения лямбда-выражений в синтаксисе языка Java. Лямбда-выражения являются основным синтаксисом в функциональных языках программирования, таких как lisp. Groovy будет ближайшим родственником java, который поддерживает лямбда-выражения, также известные как замыкания.

Так что же такое лямбда-выражение? Это блок кода, который можно присвоить переменной или передать в качестве аргумента методу или передать в качестве аргумента другому лямбда-выражению, как и любые другие данные. Код также может быть вызван при необходимости. Основная мотивация поддержки этого в java состоит в том, чтобы убрать много лишнего кода при использовании определенного API, который требует некоторого кода от пользователя API, но в конечном итоге использует внутренние классы только из-за требований синтаксиса java. Наиболее распространенным таким API-интерфейсом является API-интерфейс потоков Java, в котором нам необходимо указать API-интерфейсу, какой код выполнять в новом потоке, но в итоге реализовать Runnable.

Спецификация все еще находится в стадии разработки и постоянно меняется. Эта статья просто дает представление о том, чего ожидать.

Функциональные интерфейсы . Разработчики спецификации Java вряд ли когда-либо захотят изменить спецификацию JVM, и этот случай не является исключением. Таким образом, они создают спецификацию таким образом, чтобы лямбда могла быть реализована без каких-либо изменений в JVM. Таким образом, вы можете легко скомпилировать класс с исходной версией 1.8 и целевой версией 1.5.

Таким образом, лямбда-код будет храниться в реализации анонимного класса, реализующего интерфейс, который имеет только один метод. Ну, не совсем, интерфейс может иметь более одного метода, но он должен быть реализован классом, который определяет только один метод. Мы назовем такой интерфейс функциональным интерфейсом. Ниже приведены некоторые примеры функциональных интерфейсов.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//A simple case, only one method
//This is a functional interface
public interface Test1{
    public void doSomething(int x);
}
 
//Defines two methods, but toString() is already there in
//any object by virtue of being subclass of java.lang.Object
//This is a functional interface
public interface Test2{
    public void doSomething(int x);
    public String toString();
}
 
//The method in Test3 is override compatible with
//the method in Test1, so the interface is still
//functional
public interface Test3 extends Test1{
    public void doSomething(int x);
}
 
//Not functional, the implementation must
//explicitly implement two methods.
public interface Test4 extends Test1{
    public void doSomething(long x);
}

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

argumentsList -> body

Параметр argumentsList аналогичен списку аргументов метода java — запятые разделяются и заключаются в круглые скобки, за одним исключением — если имеется только один аргумент, скобки являются необязательными. Также необязательно указывать типы аргументов. Если типы не указаны, они выводятся. Тело может быть двух типов — тело выражения и тело блока кода. Тело выражения — это просто допустимое выражение Java, которое возвращает значение. Тело блока кода содержит блок кода точно так же, как тело метода. Тело блока кода имеет тот же синтаксис, что и тело метода, включая обязательную пару фигурных скобок.

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

1
2
//The thread will keep printing "Hello"
new Thread(() -> { while(true){ System.out.println("Hello"); }}).start();

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

1
2
3
4
5
6
public interface RandomLongs{
    public long randomLong();
}
 
RandomLongs randomLongs = () -> ((long)(Math.random()*Long.MAX_VALUE));
System.out.println(randomLongs.randomLong());

Дженерики и лямбда : но что если мы захотим реализовать универсальный метод с использованием лямбда? Разработчики спецификации придумали хороший синтаксис, параметры типа объявляются перед аргументами типа. Ниже приведен пример —

01
02
03
04
05
06
07
08
09
10
11
public interface NCopies{
    public <T extends Cloneable> List<T> getCopies(T seed, int num);
}
 
//Inferred types for arguments also supported for generic methods
NCopies nCopies = <T extends Cloneable> (seed, num) -> {
                    List<T> list = new ArrayList<>();
                    for(int i=0; i<num; i++)
                        list.add(seed.clone());
                    return list;
                };

Обратите внимание : фактический интерфейс и метод, реализованные лямбда-выражением, зависят от контекста, в котором оно используется. Контекст может быть установлен с помощью существования операции присваивания или передачи параметра в вызове метода. Без контекста лямбда не имеет смысла, поэтому некорректно просто вызывать метод непосредственно для лямбда-выражения. Например, следующее даст ошибку компиляции —

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public interface NCopies{
    public <T extends Cloneable> List<T> getCopies(T seed, int num);
}
 
//This code will give a compilation error,
//As the lambda is meaningless without a context
(<T extends Cloneable> (seed, num) -> {
                    List<T> list = new ArrayList<>();
                    for(int i=0; i<num; i++)
                        list.add(seed.clone());
                    return list;
                }).getCopies(new CloneableClass(), 5);
 
 
However, the following would be perfectly alright, because there is an assignment context for the lambda.
 
NCopies nCopies = <T extends Cloneable> (seed, num) -> {
                    List<T> list = new ArrayList<>();
                    for(int i=0; i<num; i++)
                        list.add(seed.clone());
                    return list;
                };
                 
nCopies.getCopies(new CloneableClass(), 5);

Урезанная лямбда : поддержка лямбда в Lisp гораздо более гибкая, чем эта. Весь язык lisp основан на лямбде. Тем не менее, Java должен ограничить синтаксис, чтобы вписаться в свой собственный синтаксис. Кроме того, lisp — это интерпретируемый язык, у которого есть преимущество в том, чтобы делать вещи во время выполнения, когда доступна вся информация. Java, являющаяся скомпилированным языком, должна придерживаться гораздо более строгих правил для типов, потоков управления и т. Д., Чтобы избежать неожиданностей во время выполнения. Учитывая это, урезанная лямбда в Java 8 выглядит не так уж плохо.

Ссылка: Что готовит в Java 8 — Проект Lambda от нашего партнера JCG   Дебашиш Рэй Чаудхури в блоге Geeky Articles .