Учебники

Groovy — Закрытие

Закрытие — это короткий анонимный блок кода. Обычно он занимает несколько строк кода. Метод может даже принять блок кода в качестве параметра. Они анонимны по своей природе.

Ниже приведен пример простого замыкания и как оно выглядит.

Live Demo

class Example {
   static void main(String[] args) {
      def clos = {println "Hello World"};
      clos.call();
   } 
}

В приведенном выше примере строка кода — {println «Hello World»} называется замыканием. Блок кода, на который ссылается этот идентификатор, может быть выполнен с помощью оператора вызова.

Когда мы запустим вышеуказанную программу, мы получим следующий результат —

Hello World

Формальные параметры в замыканиях

Замыкания также могут содержать формальные параметры, чтобы сделать их более полезными, как и методы в Groovy.

Live Demo

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

Замыкания и Переменные

Более формально, замыкания могут ссылаться на переменные во время определения замыкания. Ниже приведен пример того, как этого можно достичь.

Live Demo

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 многие встроенные методы для типов данных, таких как списки и коллекции, имеют в качестве типа параметра замыкания.

В следующем примере показано, как замыкание можно отправить методу в качестве параметра.

Live Demo

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 в качестве параметра.

Мы определяем статический метод с именем Display, который принимает замыкание в качестве аргумента.

Затем мы определяем замыкание в нашем основном методе и передаем его в наш метод Display в качестве параметра.

Когда мы запустим вышеуказанную программу, мы получим следующий результат —

Hello World 
Welcome World 
Welcome Inner

Замыкания в коллекциях и строках

Несколько методов List, Map и String принимают в качестве аргумента замыкание. Давайте рассмотрим пример использования замыканий в этих типах данных.

Использование замыканий со списками

В следующем примере показано, как замыкания можно использовать со списками. В следующем примере мы сначала определяем простой список значений. Тип коллекции списка затем определяет вызываемую функцию. каждый Эта функция принимает замыкание в качестве параметра и применяет замыкание к каждому элементу списка.

Live Demo

class Example {
   static void main(String[] args) {
      def lst = [11, 12, 13, 14];
      lst.each {println it}
   } 
}

Когда мы запустим вышеуказанную программу, мы получим следующий результат —

11 
12 
13 
14

Использование замыканий с картами

В следующем примере показано, как замыкания можно использовать с Картами. В следующем примере мы сначала определяем простую карту элементов значения ключа. Тип коллекции карт затем определяет функцию с именем .each. Эта функция принимает замыкание в качестве параметра и применяет замыкание к каждой паре ключ-значение на карте.

Live Demo

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

Часто нам может потребоваться перебрать членов коллекции и применить некоторую логику только в том случае, если элемент удовлетворяет некоторому критерию. Это легко обрабатывается условным оператором в замыкании.

Live Demo

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 

Методы, используемые с замыканиями

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

Метод find находит первое значение в коллекции, которое соответствует некоторому критерию.

Он находит все значения в принимающем объекте, соответствующие условию закрытия.

Метод any перебирает каждый элемент коллекции, проверяя, является ли логический предикат действительным хотя бы для одного элемента.

Метод collect перебирает коллекцию, преобразуя каждый элемент в новое значение, используя замыкание в качестве преобразователя.