Вложенные классы и лямбда-выражения в Java
Язык Java примечателен тем, что внутри одного класса возможно размещать другой. И таким образом, получается вложенный класс. Они могут быть статическими или же вообще внутренними (без static). Вложенный класс является элементом, в чей класс он вложен.
Внутренние классы имеют доступ к элементам, в которые они вложены, даже если присутствует модификатор private. Подробнее о вложенных и внутренних классах, а также о лямбда-выражениях пользователи смогут узнать, если посветят немного времени данному материалу.
Когда использовать вложенные классы, локальные классы, анонимные классы и лямбда-выражения
Можно быстро объяснить всю суть вложенных, локальных, анонимных классов. Ниже в списке будет описана ситуация для каждого класса, когда требуется применять тот или иной:
- Локальный класс. Требуется для того, чтобы создавать несколько экземпляров класса, использовать специализированный конструктор или же применять в своей структуре именованный класс. В общем – для продвинутого создания классов рекомендуется локальный тип, с которым доступно много разных функций;
- Анонимные классы. Они необходимы в использовании тогда, когда требуется добавочное поле или же дополнительные методы;
- Вложенный класс. О нем уже говорилось во вступлении, но рекомендуется также понять, когда его использовать, а когда прибегнуть к другому варианту. Фактически, вложенный класс является более доступным по функционалу локальным вариантом. Нужен доступ к переменным, находящимся во внешнем классе – можно использовать нестатический вложенный класс(иначе, внутренний), в противном случае рекомендуется применение статического вложенного класса;
- Лямбда-выражения. Это самое интересное среди перечисленного.Требуется это для того, чтобы создать один экземпляр функционального интерфейса, а также специальное действие для передачи того или иного действия из одного метода в другой. Примером может стать обработчик события.
Так как последнее пользователи начального уровня нигде почти не видели(или вовсе не было замечено нигде), то рекомендуется обратить внимание на следующие пункты. Там будет рассмотрено все основное, а также пример применения лямбда-выражений с углубленной информацией насчет каждого момента, связанного с этим элементом.
Введение в лямбда-выражения
Перед тем, как начать изучение лямбда-выражений на более детальном уровне, требуется понять, что это вообще такое и какие особенности есть. Лямбда-выражения связаны с анонимными классами. Последние создают только один абстрактный метод, а при помощи первых можно записать код более быстро, коротко и понятно.
Интерфейс, содержащий только один абстрактный метод, имеет название функционального. Его особенность в том, что он может содержать не один метод, а несколько. Но только не абстрактных, а статических и default. Это рекомендуется взять на заметку, так как пригодится при разборе лямбда-выражений более детально впоследствии.
Чтобы понять, как писать лямбда-выражения, требуется сначала разузнать, из чего вообще оно состоит. Здесь, к счастью, ничего сложного нет. Вот, какие компоненты находятся в обычных лямбда-выражениях:
- Список формальных параметров, которые разделяются простой запятой и заключаются в скобки. Однако, бывает случай, когда параметров лишь один и последний знак препинания не требуется. Но когда вообще нет таковых, то устанавливаются простые скобки без каких-либо символов. Тип формальных операторов в любом случае не имеет почти никакой роли в структуре – его можно как указывать, так и упустить, так как без него ничего не изменится;
- Токен стрелки, который обозначается привычным образом – сочетанием двух символов, выглядящих так «->»;
- Тело, состоящее из оператора или инструкции, либо же, целого блока первых или вторых. Если значение блока операторов отличается от void, то для возврата значения, ранее присутствовавшего используется команда return. Если выражение одно, то результатом лямбда-выражения станет решение. Касательно блока операторов – он может быть пустым, зависимо от случая, в котором тот применяется.
Важная деталь касается области применения лямбда-выражений. Необходимо учитывать, что тип результата зависит от того, как его определит Java. А бывает таковых несколько и все они касаются математических выражений.
Также, можно коснуться небольшого момента, который важен. Он касается сериализации лямбда-выражений. Это допускается языком Java. Однако, не стоит так делать, так как все обусловлено тем, что могут быть плохие последствия – к примеру, ошибки с вычислениями или «поломка» всего кода.
Пример лямбда-выражений
Чтобы узнать, как вообще выглядят лямбда-выражения, следует обратиться к примерам. Их достаточно, чтобы пользователям было ясно, какие разновидности могут быть и какой у них синтаксис. Вот простые варианты записи:
- () -> {};
- x -> x * 2 – 3;
- x->{
System.out.println(x);
int z = x * 2 — 3;
System.out.println(x);
return z;
}; - (x,y) -> x + y;
- x -> System.out.println(x).
Это – основа основ, которая присутствует в лямбда-выражениях, а точнее, в их видах. Гораздо интереснее выглядит пример применения таких выражений. Вот первый такой:
class Main {
interface Operation {
int operation(int x, int y);
}interface SimpleOperation {
void simpleOperation(int x);
}static int[] arrayOperation(int[] x, int[] y, Operation operation) {
int[] result = new int[x.length];
for (int n = 0; n < x.length; n++) {
result[n] = operation.operation(x[n], y[n]);
}
return result;
}static void arraySimpleOperation(int[] x, SimpleOperation simpleOperation) {
for (int n = 0; n < x.length; n++) {
simpleOperation.simpleOperation(x[n]);
}
}public static void main(String[] args) {
// Пример сложения элементов массива:
int[] resultSum = arrayOperation(new int[] {1, 0, 3},
new int[] {2, 1, 0}, (int x, int y) -> x + y);
// Пример вычитания элементов массива:
int[] resultMinus = arrayOperation(new int[] {1, 2, 3, 4},
new int[] {2, 2, 3, 1}, (x, y) -> x — y);// Вывод в консоль
SimpleOperation writelnOperation = x -> System.out.println(x);
System.out.println(«Sum result:»);
arraySimpleOperation(resultSum, writelnOperation);
System.out.println(«Minus result:»);
arraySimpleOperation(resultMinus, writelnOperation);
}
}
Этот – самый простой. Но также можно увидеть и такой вариант, когда локальные, анонимные классы, а также обращаются к локальным переменным, обозначенным как final. Лямбда выражения не станут порождать в таком случае новую область видимости переменных, а будут использовать ту же, что и метод:
class LambdaScopeTest {
int x = 23;interface A {
void method2(int y);
};class InnerClass {
int x = 10;public void method1(int x) {
A a = z -> {
System.out.println(«z=» + z);// можем обратиться к параметру method1,
// так как он final по действию,
// то есть его значение не меняется.
System.out.println(«x=» + x);System.out.println(«this.x=» + this.x);
System.out.println(«LambdaScopeTest.this.x=»
+ LambdaScopeTest.this.x);
};a.method2(x);
}
}public static void main(String[] args) {
LambdaScopeTest lsc = new LambdaScopeTest();
LambdaScopeTest.InnerClass ic = lsc.new InnerClass();
ic.method1(44);
}
}
И вот, что получится в результате выполнения такой программы с лямбда-выражениями:
z=44
x=44
this.x=10
LambdaScopeTest.this.x=23
Лямбда-выражения, как уже говорилось выше, используют ту же область видимости переменных, что и метод. Потому, затенения переменных быть просто-напросто не может. А если ввести такой код:
A a = x -> {
…
Тогда произойдет ошибка, так как переменная xуже объявлена.
Также, стоит отметить то, что присутствует пакет выражений java.util.function с множеством разных вариантов интерфейсов, специально подобранных для использования с лямбда-выражениями. А значит, можно будет работать на разный манер, задействовав какой-либо из предоставленных вариантов. Главное – корректно подобрать и правильно использовать.
Терминальные лямбда-выражения
Помимо стандартных лямбда-выражений есть еще и терминальные. С ними тоже стоит разобраться, так как возможно, они пригодятся пользователю в будущем при построении сложных структур.
Терминальные лямбда-выражения, как правило, ничем почти не отличаются от обычных. Но все-таки, есть одна очень значимая деталь для пользователей. Все дело в том, что терминальные не возвращают значение, в отличие от стандартных выражений.
Найти применение можно, к примеру, когда не нужно оглашать вариант человеку, пользующемуся программой, а воспринять его исключительно программой или что-то еще. В общем – применение нестандартное в таком случае.
Вот таким образом выглядит терминальное лямбда-выражение:
interface Printable{
void print(String s);
}public class LambdaApp {
public static void main(String[] args) {
Printable printer = s->System.out.println(s);
printer.print(«HelloJava!»);
}
}
Как можно видеть, выглядит эта структура немного сложнее, чем стандартные лямбда-выражения. Но это можно понять, так как терминальный вариант необычен и имеет определенные условия. Значит, что пользователь немного больше времени потратит на написание программы с участием такого типа лямбда-выражений.
Передача параметров в лямбда-выражение
У лямбда-выражений есть важная черта – их значения должны соответствовать параметрам метода из стандартного интерфейса. Если писать сам тип лямбда-выражений, то добавлять тип данных нет особой необходимости. Однако, это можно сделать – вот таким образом, который не отличается особой сложностью:
operation = (int x, int y)->x+y;
Однако, бывает случай, когда метод не принимает никаких параметров. В таком варианте событий не стоит паниковать, так как возможно применение дополнительного способа. Выглядит он даже еще проще и выполняется только с помощью цифр, а также знаков выражения:
()-> 30 + 20;
А когда параметр один – то же самое используется, но только теперь есть некоторые изменения. Первое – вместо цифр используются латинские буквы, обозначающие «какое-либо значение». А также, не требуется никаких скобок. В общем – вот так выглядит код:
n-> n * n;
Вот, как делается передача параметров в лямбда-выражения. А значит, пользователь может без каких-либо проблем заняться этим во время написания кода, затратив пару секунд на такое действие. Да и вообще, писать код с участием лямбда-выражений – легко.
Как уже можно понять из примеров, представленных в статье – здесь важна лишь математика и логика, чтобы разобраться в работе лямбда-выражений. Причем не важно – терминальные они или обычные (у них нет разницы в работе), это уже пользователи узнали из материала по Java8, что был сейчас прочитан.