Groovy - Замыкания
Замыкание - это короткий анонимный блок кода. Обычно он занимает несколько строк кода. Метод может даже принимать блок кода в качестве параметра. Они анонимны по своей природе.
Ниже приведен пример простого закрытия и его внешний вид.
class Example {
static void main(String[] args) {
def clos = {println "Hello World"};
clos.call();
}
}
В приведенном выше примере строка кода - {println "Hello World"} известна как закрытие. Блок кода, на который ссылается этот идентификатор, может быть выполнен с помощью оператора call.
Когда мы запустим вышеуказанную программу, мы получим следующий результат -
Hello World
Формальные параметры в закрытии
Замыкания также могут содержать формальные параметры, чтобы сделать их более полезными, как и методы в Groovy.
class Example {
static void main(String[] args) {
def clos = {param->println "Hello ${param}"};
clos.call("World");
}
}
В приведенном выше примере кода обратите внимание на использование $ {param}, которое заставляет замыкание принимать параметр. При вызове закрытия через оператор clos.call теперь у нас есть возможность передать параметр в закрытие.
Когда мы запустим вышеуказанную программу, мы получим следующий результат -
Hello World
Следующая иллюстрация повторяет предыдущий пример и дает тот же результат, но показывает, что можно использовать неявный единственный параметр, называемый им. Здесь «это» - ключевое слово в Groovy.
class Example {
static void main(String[] args) {
def clos = {println "Hello ${it}"};
clos.call("World");
}
}
Когда мы запустим вышеуказанную программу, мы получим следующий результат -
Hello World
Замыкания и переменные
Более формально замыкания могут относиться к переменным во время определения замыкания. Ниже приводится пример того, как этого можно достичь.
class Example {
static void main(String[] args) {
def str1 = "Hello";
def clos = {param -> println "${str1} ${param}"}
clos.call("World");
// We are now changing the value of the String str1 which is referenced in the closure
str1 = "Welcome";
clos.call("World");
}
}
В приведенном выше примере, помимо передачи параметра в замыкание, мы также определяем переменную с именем str1. Замыкание также принимает переменную вместе с параметром.
Когда мы запустим вышеуказанную программу, мы получим следующий результат -
Hello World
Welcome World
Использование замыканий в методах
Замыкания также можно использовать как параметры методов. В Groovy многие встроенные методы для типов данных, таких как списки и коллекции, имеют замыкания в качестве типа параметра.
В следующем примере показано, как замыкание может быть отправлено методу в качестве параметра.
class Example {
def static Display(clo) {
// This time the $param parameter gets replaced by the string "Inner"
clo.call("Inner");
}
static void main(String[] args) {
def str1 = "Hello";
def clos = { param -> println "${str1} ${param}" }
clos.call("World");
// We are now changing the value of the String str1 which is referenced in the closure
str1 = "Welcome";
clos.call("World");
// Passing our closure to a method
Example.Display(clos);
}
}
В приведенном выше примере
Мы определяем статический метод Display, который принимает закрытие в качестве аргумента.
Затем мы определяем замыкание в нашем основном методе и передаем его нашему методу Display в качестве параметра.
Когда мы запустим вышеуказанную программу, мы получим следующий результат -
Hello World
Welcome World
Welcome Inner
Замыкания в коллекциях и строке
Некоторые методы List, Map и String принимают закрытие в качестве аргумента. Давайте посмотрим на пример того, как замыкания можно использовать в этих типах данных.
Использование замыканий со списками
В следующем примере показано, как замыкания можно использовать со списками. В следующем примере мы сначала определяем простой список значений. Затем тип коллекции списка определяет вызываемую функцию.each. Эта функция принимает закрытие в качестве параметра и применяет закрытие к каждому элементу списка.
class Example {
static void main(String[] args) {
def lst = [11, 12, 13, 14];
lst.each {println it}
}
}
Когда мы запустим вышеуказанную программу, мы получим следующий результат -
11
12
13
14
Использование замыканий с картами
В следующем примере показано, как замыкания можно использовать с Maps. В следующем примере мы сначала определяем простую карту элементов значения ключа. Затем тип коллекции карт определяет функцию с именем .each. Эта функция принимает закрытие в качестве параметра и применяет закрытие к каждой паре "ключ-значение" карты.
class Example {
static void main(String[] args) {
def mp = ["TopicName" : "Maps", "TopicDescription" : "Methods in Maps"]
mp.each {println it}
mp.each {println "${it.key} maps to: ${it.value}"}
}
}
Когда мы запустим вышеуказанную программу, мы получим следующий результат -
TopicName = Maps
TopicDescription = Methods in Maps
TopicName maps to: Maps
TopicDescription maps to: Methods in Maps
Часто мы можем захотеть перебрать элементы коллекции и применить некоторую логику только тогда, когда элемент соответствует определенному критерию. Это легко обрабатывается с помощью условного оператора в замыкании.
class Example {
static void main(String[] args) {
def lst = [1,2,3,4];
lst.each {println it}
println("The list will only display those numbers which are divisible by 2")
lst.each{num -> if(num % 2 == 0) println num}
}
}
В приведенном выше примере показано условное выражение if (num% 2 == 0), используемое в закрытии, которое используется для проверки, делится ли каждый элемент в списке на 2.
Когда мы запустим вышеуказанную программу, мы получим следующий результат -
1
2
3
4
The list will only display those numbers which are divisible by 2.
2
4
Методы, используемые с замыканиями
Сами замыкания предоставляют некоторые методы.
Sr. No. | Методы и описание |
---|---|
1 | найти() Метод find находит первое значение в коллекции, которое соответствует некоторому критерию. |
2 | найти все() Он находит все значения в принимающем объекте, соответствующие условию закрытия. |
3 | любой () и каждый () Метод any выполняет итерацию по каждому элементу коллекции, проверяя, действителен ли логический предикат хотя бы для одного элемента. |
4 | собирать () Метод collect выполняет итерацию по коллекции, преобразовывая каждый элемент в новое значение, используя замыкание в качестве преобразователя. |