Groovy - 閉包



閉包是一個簡短的匿名程式碼塊。它通常只包含幾行程式碼。方法甚至可以將程式碼塊作為引數。它們本質上是匿名的。

下面是一個簡單的閉包示例及其外觀。

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

在上面的示例中,程式碼行 - {println "Hello World"} 被稱為閉包。可以透過呼叫語句執行此識別符號引用的程式碼塊。

執行上述程式後,我們將得到以下結果:

Hello World

閉包中的形式引數

閉包也可以包含形式引數,使其更像Groovy中的方法一樣有用。

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

在上面的程式碼示例中,請注意${param}的使用,它使閉包能夠接受引數。當透過clos.call語句呼叫閉包時,我們現在可以選擇向閉包傳遞引數。

執行上述程式後,我們將得到以下結果:

Hello World

下一個示例重複了前面的示例併產生相同的結果,但它顯示可以使用稱為it的隱式單引數。“it”是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

使用閉包與對映

以下示例顯示如何將閉包與對映一起使用。在下面的示例中,我們首先定義一個簡單的鍵值對對映。對映集合型別然後定義一個名為.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 

與閉包一起使用的方法

閉包本身提供了一些方法。

序號 方法和描述
1 find()

find方法查詢集合中第一個匹配某些條件的值。

2 findAll()

它查詢接收物件中所有匹配閉包條件的值。

3 any() & every()

any方法迭代集合的每個元素,檢查布林謂詞對至少一個元素是否有效。

4 collect()

collect方法迭代集合,使用閉包作為轉換器將每個元素轉換為新值。

廣告