Статьи

Lambdas in Java Preview. Часть 5. Apache Wicket

Это пятая часть в серии постов в блоге (см. Предыдущую часть ), в которой приводятся некоторые практические примеры лямбд, как может выглядеть функциональное программирование на Java и как лямбды могут влиять на некоторые из известных библиотек на земле Java. На этот раз я посмотрю, как добавление лямбд может изменить API веб-фреймворка Apache Wicket .

Если вы не знакомы с Wicket, я не могу сказать, какой смысл для вас читать эту статью. Но Wicket — это компонентно-ориентированный веб-фреймворк, и его модель программирования в некотором роде аналогична модели фреймворка Swing. Некоторые из способов, которыми лямбды будут менять Wicket, могут также применяться к платформе Swing, поэтому, возможно, эта статья на самом деле все еще полезна для вас.

Причина, по которой Wicket является хорошим примером того, как введение лямбда-выражений в язык Java может изменить API, заключается в том, что он интенсивно использует анонимные внутренние классы. Теперь анонимные внутренние классы в Java часто бывают болезненными, и одной из основных причин добавления лямбда-выражений в Java является снижение потребности в анонимных внутренних классах или, что лучше, упрощение их использования. Это делается главным образом посредством преобразования SAM, что означает, что лямбда-выражение или анонимная функция могут быть преобразованы в тип SAM, т. Е. Интерфейс или абстрактный класс, с помощью одного абстрактного метода, когда он появляется в позиции, где ожидается тип SAM ( см. предыдущие части для примеров).И поскольку Wicket интенсивно использует анонимные реализации абстрактных классов (а некоторые из этих классов на самом деле являются простыми классами обратного вызова, которые на самом деле являются типами SAM), может появиться множество мест, где мы можем заменить эти анонимные внутренние классы лямбда-выражениями. ,

AbstractReadOnlyModels

Одним из классов, которые в основном реализованы анонимно, является AbstractReadOnlyModel. У него есть единственный абстрактный метод getObject (). Другими словами, это тип SAM.

IModel<String> nameModel = 
new AbstractReadOnlyModel<String>() {
@Override
public String getObject() {
Person person = personModel.getObject();
return person.getFirstName() + ", "
+ person.getLastName();
}
};

TextField<String> name = new TextField<String>("name", nameModel);

Важной частью этого является только тело метода getObject, но примерно столько же кода является просто шумом. С лямбдами мы могли бы удалить большую часть этого шума.
Здесь мы в основном заменили анонимный внутренний класс лямбда-выражением, которое имеет то же тело, что и метод getObject () ранее. Это лямбда-выражение будет автоматически преобразовано в AbstractReadOnlyModel.

Следует отметить, что компилятор должен иметь возможность вывести целевой тип SAM. В приведенном выше примере мы явно объявили переменную типа AbstractReadOnlyModel, но, например, если вы вызываете конструктор TextField (String wicketId, модель IModel), вы не можете передать встроенное лямбда-выражение, как это

потому что IModel не является типом SAM, и компилятор не может сделать вывод, что вы хотите, чтобы лямбда была преобразована в AbstractReadOnlyModel.

LoadableDetachableModels

Другим обычно используемым классом модели является LoadableDetachableModel, в котором метод load () является единственным абстрактным методом.
Так же, как и с AbstractReadOnlyModel, мы можем заменить его лямбда-выражением.

Компоненты

Компоненты — еще один важный тип классов в Wicket. Есть некоторые компоненты Wicket типа SAM, особенно те, которые обрабатывают какое-то событие. Часто такие компоненты реализуются как анонимные внутренние классы. Возьмем, к примеру, AjaxButton.
Его единственный абстрактный метод — onSubmit (), но есть важное отличие от типов SAM, показанных ранее. Компоненты не имеют конструктора без аргументов, все они принимают по крайней мере wicketId в качестве аргумента конструктора. Предложения не дают ответа, если разрешить список аргументов для других, чем конструктор без аргументов для преобразования SAM. Если бы это было разрешено, это могло бы выглядеть так

С другой стороны, будущая версия Wicket может быть разработана по-другому, чтобы лучше поддерживать преобразование SAM. Давайте создадим подкласс AjaxButton, который больше полагается на композицию, а не на наследование (хотя в Wicket все наоборот). Наш подкласс вместо переопределения onSubmit может принимать аргумент обратного вызова:
IAjaxButtonOnSubmitCallback является типом SAM,
поэтому мы можем вызвать конструктор нашей кнопки с лямбда-выражением в качестве последнего аргумента (здесь с синтаксисом стрелки и выводом типа последнее предложение)

Тот же принцип (составление по наследованию) будет работать для многих других компонентов Wicket, как правило, для всех компонентов, имеющих некоторый механизм обратного вызова для определенных событий, например, события отправки формы, события ошибки проверки формы, события щелчка по ссылке, измененный выбор раскрывающегося списка события и тд. Если бы все эти события выполнялись обратными вызовами, а не абстрактными методами, преобразование SAM могло бы использоваться эффективно.

В общем, есть два случая, когда мы могли бы подумать о введении дополнительных классов обратного вызова: во-первых, если класс является типом SAM, но не имеет конструктора без аргументов, мы могли бы заменить один абстрактный метод вызовом обратный вызов мы даем этому компоненту. И, во-вторых, если класс не является типом SAM, но вместо этого имеет более одного абстрактного метода, мы можем предоставить обратный вызов для каждого из этих абстрактных методов. Это полностью изменило бы дизайн Wicket, но лучше поддержало бы преобразование SAM.

Другой класс компонентов, где применяется этот принцип, это всевозможные популяторы. Возьмем, к примеру, столбцы таблицы данных.
Опять же, AbstractColumn не имеет конструктора без аргументов, поэтому мы (вероятно) не можем использовать преобразование SAM напрямую. Но вместо этого мы могли бы написать наш собственный подкласс AbstractColumn, который принимает IColumnPopulator (тип SAM) и вызывает его из своего метода populateItem.
Столбец может быть создан более кратким, как это:

Таким образом, у Wicket есть много возможностей использовать преобразование SAM, что уменьшит потребность в анонимных внутренних классах. В тех случаях, когда эти типы SAM не имеют конструктора без аргументов, пока не ясно, можно ли применить к ним преобразование SAM. Однако для этих типов другой дизайн, который предпочитает композицию, а не наследование, допускает преобразование SAM. То же самое верно для классов, которые имеют более одного абстрактного метода, который может использовать классы обратного вызова вместо абстрактных методов.

От http://stronglytypedblog.blogspot.com/2010/07/lambdas-in-java-preview-part-5-apache.html