Groovy - Zamknięcia
Zamknięcie to krótki anonimowy blok kodu. Zwykle obejmuje kilka wierszy kodu. Metoda może nawet przyjąć blok kodu jako parametr. Mają charakter anonimowy.
Poniżej znajduje się przykład prostego zamknięcia i jego wyglądu.
class Example {
static void main(String[] args) {
def clos = {println "Hello World"};
clos.call();
}
}
W powyższym przykładzie linia kodu - {println "Hello World"} jest znana jako zamknięcie. Blok kodu, do którego odwołuje się ten identyfikator, można wykonać za pomocą instrukcji call.
Po uruchomieniu powyższego programu otrzymamy następujący wynik -
Hello World
Parametry formalne w domknięciach
Zamknięcia mogą również zawierać parametry formalne, aby były bardziej przydatne, podobnie jak metody w Groovy.
class Example {
static void main(String[] args) {
def clos = {param->println "Hello ${param}"};
clos.call("World");
}
}
W powyższym przykładzie kodu zwróć uwagę na użycie $ {param}, które powoduje, że zamknięcie przyjmuje parametr. Wywołując zamknięcie za pomocą instrukcji clos.call, mamy teraz możliwość przekazania parametru do zamknięcia.
Po uruchomieniu powyższego programu otrzymamy następujący wynik -
Hello World
Następna ilustracja powtarza poprzedni przykład i daje ten sam wynik, ale pokazuje, że niejawny pojedynczy parametr, o którym mowa, może być użyty. Tutaj „to” jest słowem kluczowym w Groovy.
class Example {
static void main(String[] args) {
def clos = {println "Hello ${it}"};
clos.call("World");
}
}
Po uruchomieniu powyższego programu otrzymamy następujący wynik -
Hello World
Zamknięcia i zmienne
Bardziej formalnie, zamknięcia mogą odnosić się do zmiennych w czasie definiowania zamknięcia. Poniżej znajduje się przykład tego, jak można to osiągnąć.
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");
}
}
W powyższym przykładzie, oprócz przekazania parametru do zamknięcia, definiujemy również zmienną o nazwie str1. Zamknięcie przejmuje również zmienną wraz z parametrem.
Po uruchomieniu powyższego programu otrzymamy następujący wynik -
Hello World
Welcome World
Stosowanie domknięć w metodach
Zamknięcia mogą być również używane jako parametry metod. W Groovy wiele wbudowanych metod dla typów danych, takich jak listy i kolekcje, ma zamknięcia jako typ parametru.
Poniższy przykład pokazuje, jak zamknięcie można wysłać do metody jako parametr.
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);
}
}
W powyższym przykładzie
Definiujemy statyczną metodę o nazwie Display, która przyjmuje zamknięcie jako argument.
Następnie definiujemy zamknięcie w naszej głównej metodzie i przekazujemy je do naszej metody Display jako parametr.
Po uruchomieniu powyższego programu otrzymamy następujący wynik -
Hello World
Welcome World
Welcome Inner
Zamknięcia w kolekcjach i ciągach
Kilka metod List, Map i String akceptuje zamknięcie jako argument. Spójrzmy na przykład, jak domknięcia mogą być używane w tych typach danych.
Używanie domknięć z listami
Poniższy przykład pokazuje, jak domknięcia mogą być używane z listami. W poniższym przykładzie najpierw definiujemy prostą listę wartości. Typ zbioru list definiuje następnie funkcję o nazwie.each. Ta funkcja przyjmuje zamknięcie jako parametr i stosuje zamknięcie do każdego elementu listy.
class Example {
static void main(String[] args) {
def lst = [11, 12, 13, 14];
lst.each {println it}
}
}
Po uruchomieniu powyższego programu otrzymamy następujący wynik -
11
12
13
14
Używanie zamknięć z mapami
Poniższy przykład pokazuje, jak zamknięcia mogą być używane w Mapach. W poniższym przykładzie najpierw definiujemy prostą mapę kluczowych elementów wartości. Typ zbioru map definiuje następnie funkcję o nazwie .each. Ta funkcja przyjmuje zamknięcie jako parametr i stosuje zamknięcie do każdej pary klucz-wartość mapy.
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}"}
}
}
Po uruchomieniu powyższego programu otrzymamy następujący wynik -
TopicName = Maps
TopicDescription = Methods in Maps
TopicName maps to: Maps
TopicDescription maps to: Methods in Maps
Często możemy chcieć przeprowadzić iterację w obrębie elementów kolekcji i zastosować jakąś logikę tylko wtedy, gdy element spełnia jakieś kryterium. Można to łatwo załatwić za pomocą instrukcji warunkowej w zamknięciu.
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}
}
}
Powyższy przykład pokazuje warunkowe wyrażenie if (num% 2 == 0) używane w zamknięciu, które służy do sprawdzenia, czy każda pozycja na liście jest podzielna przez 2.
Po uruchomieniu powyższego programu otrzymamy następujący wynik -
1
2
3
4
The list will only display those numbers which are divisible by 2.
2
4
Metody używane z zamknięciami
Same zamknięcia dostarczają pewnych metod.
Sr.No. | Metody i opis |
---|---|
1 | odnaleźć()
Metoda find znajduje pierwszą wartość w kolekcji, która pasuje do jakiegoś kryterium. |
2 | Znajdź wszystko()
Znajduje wszystkie wartości w obiekcie odbierającym pasujące do warunku zamknięcia. |
3 | dowolne () i co ()
Metoda any wykonuje iterację w każdym elemencie kolekcji, sprawdzając, czy predykat boolowski jest prawidłowy dla co najmniej jednego elementu. |
4 | zbierać()
Metoda collect wykonuje iterację w kolekcji, konwertując każdy element na nową wartość, używając zamknięcia jako transformatora. |