- 浏览: 5166503 次
- 性别:
- 来自: 天津
博客专栏
-
实战 Groovy
浏览量:29349
文章分类
- 全部博客 (639)
- 代码之谜 (6)
- JavaScript quirks (5)
- 程序员 (92)
- Java (93)
- BT编程 (7)
- html/css (64)
- Groovy&Grails (42)
- Android (20)
- C/C++ (5)
- PHP/Perl/Python (46)
- 经典文章 (51)
- CodeIgniter (14)
- JQuery (10)
- 笑话 (4)
- 其他 (32)
- javascript (69)
- 云计算 (0)
- html5 (7)
- 面试 (8)
- google (3)
- nosql (2)
- nodejs (11)
- go (5)
- erlang (1)
- 小常识 (3)
- 冷知识 (5)
- database (4)
- web (12)
- 架构 (12)
- Exception (0)
最新评论
-
jqw1992:
https://www.chromefor.com/libra ...
[福利] 开发者必备的 Chrome 插件——ChromeSnifferPlus -
litjerk:
初步算了一下,目前最最精简的Win98版是5M,他5个小时多敲 ...
让人目瞪口呆的三位世界级电脑大师 -
379855529:
。。似乎重点没说NIO啊,前面基础只是铺垫的很好的,可是我要的 ...
Java NIO与IO的详细区别(通俗篇) -
springmvc_springjpa:
spring mvc demo教程源代码下载,地址:http: ...
一步步开发 Spring MVC 应用 -
匡建武:
Good
四个程序员的一天
在 Groovy 中处处都是闭包,Groovy 闭包惟一的问题是:当每天都使用它们的时候,看起来就有点平淡了。在本文中,客座作者 Ken Barclay 和 John Savage 介绍了如何对标准的闭包(例如闭包复合和 Visitor 设计模式)进行 curry 处理。curry()
方法是由 Haskell Curry 发明的,在 JSR 标准发布之前就已经在 Groovy 语言中了。
几乎从一年前实战 Groovy 系列开始,我就已经提供了多个让您了解闭包的机会。在首次作为 alt.lang.jre 系列的一部分写 Groovy 时(“感受 Groovy”,2004 年 8 月),我介绍了 Groovy 的闭包语法,而且 就在上一期文章中,我介绍了最新的 JSR 标准对相同语法的更新。学习至今,您知道了 Groovy 闭包是代码块,可以被引用、带参数、作为方法参数传递、作为返回值从方法调用返回。而且,它们也可以作为其他闭包的参数或返回值。因为闭包是 Closure
类型的对象,所以它们也可以作为类的属性或集合的成员。
虽然这些技术都是很神奇的,但是本期文章要学习的闭包技术要比您迄今为止尝试过的都要更火辣一些。客座作者 John Savage 和 Ken Barclay 已经用 Groovy 闭包中的 curry()
方法做了一些有趣的实验,我们非常有幸可以见识他们的技艺。
Barclay 和 Savage 的 curry 过的闭包不仅会重新激起您对熟悉的操作(例如复合)和 Visitor 设计模式的兴奋,还会用 Groovy 打开函数式编程的大门。
curry 过的函数 一般可在函数式编程语言(例如 ML 和 Haskell)中找得到(请参阅 参考资料)。curry 这个术语来自 Haskell Curry,这个数学家发明了局部函数的概念。Currying 指的是把多个参数放进一个接受许多参数的函数,形成一个新的函数接受余下的参数,并返回结果。令人兴奋的消息是,Groovy 的当前版本(在编写本文时是 jsr-02 版)支持在闭包
上使用 curry()
方法 —— 这意味着,我们这些 Groovy 星球的公民,现在可以利用函数式编程的某些方面了!
您以前可能从未用过 curry()
,所以我们先从一个简单的、熟悉的基础开始。清单 1 显示了一个叫做 multiply
的闭包。它有形式参数 x
和 y
,并返回这两个值的乘积。假设没有歧义存在,然后代码演示了用于执行 multiply
闭包的两种方法:显式(通过 call
的方式)或隐式。后一种样式引起了函数调用方式。
def multiply = { x, y -> return x * y } // closure def p = multiply.call(3, 4) // explicit call def q = multiply(4, 5) // implicit call println "p: ${p}" // p is 12 println "q: ${q}" // q is 20 |
这个闭包当然很好,但是我们要对它进行 curry 处理。在调用 curry()
方法时,不需要提供所有的实际参数。curry 过的 调用只引起了闭包的部分应用程序。闭包的 部分应用程序 是另一个 Closure
对象,在这个对象中有些值已经被修正。
清单 2 演示了对 multiply
闭包进行 curry 处理的过程。在第一个例子中,参数 x
的值被设置为 3。名为 triple
的闭包现在有效地拥有了 triple = { y -> return 3 * y }
的定义。
def multiply = { x, y -> return x * y } // closure def triple = multiply.curry(3) // triple = { y -> return 3 * y } def quadruple = multiply.curry(4) // quadruple = { y -> return 4 * y } def p = triple.call(4) // explicit call def q = quadruple(5) // implicit call println "p: ${p}" // p is 12 println "q: ${q}" // q is 20 |
可以看到,参数 x
已经从 multiply
的定义中删除,所有它出现的地方都被 3 这个值代替了。
从基本数学可能知道,乘法运算符是可交换的(换句话说 x * y = y * x
)。但是,减法运算符是不可交换的;所以,需要两个操作来处理减数和被减数。清单 3 为这个目的定义了闭包 lSubtract
和rSubtract
(分别在左边和右边),结果显示了 curry
函数的一个有趣的应用。
def lSubtract = { x, y -> return x - y } def rSubtract = { y, x -> return x - y } def dec = rSubtract.curry(1) // dec = { x -> return x - 1 } def cent = lSubtract.curry(100) // cent = { y -> return 100 - y } def p = dec.call(5) // explicit call def q = cent(25) // implicit call println "p: ${p}" // p is 4 println "q: ${q}" // q is 75 |
您会回忆起这个系列以前的文章中,闭包一般用于在 List
和 Map
集合上应用的迭代器方法 上。例如,迭代器方法 collect
把闭包应用到集合中的每个元素上,并返回一个带有新值的新集合。清单 4 演示了把 collect
方法应用于 List
和 Map
。名为 ages
的 List
被发送给 collect()
方法,使用单个闭包 { element -> return element + 1 }
作为参数。注意方法的最后一个参数是个闭包,在这个地方 Groovy 允许把它从实际参数列表中删除,并把它直接放在结束括号后面。在没有实际参数时,可以省略括号。用名为 accounts
的 Map
对象调用的 collect()
方法可以展示这一点。
def ages = [20, 30, 40] def accounts = ['ABC123' : 200, 'DEF456' : 300, 'GHI789' : 400] def ages1 = ages.collect({ element -> return element + 1 }) def accounts1 = accounts.collect { entry -> entry.value += 10; return entry } println "ages1: ${ages1}" // ages1: [21, 31, 41] println "accounts1: ${accounts1}" // accounts1: [ABC123=210, GHI789=410, DEF456=310] def ages2 = ages.collect { element -> return dec(element) } println "ages2: ${ages2}" // ages2: [19, 29, 39] |
最后一个例子搜集名为 ages
的 List
中的所有元素,并将 dec
闭包 (来自清单 3)应用于这些元素。
闭包更重要的一个特征可能就是复合(composition),在复合中可以定义一个闭包,它的目的是组合其他闭包。使用复合,两个或多个简单的闭包可以组合起来构成一个更复杂的闭包。
清单 5 介绍了一个漂亮的 composition
闭包。现在请注意仔细阅读:参数 f
和 g
代表 单个参数闭包。到现在还不错?现在,对于某些参数值 x
,闭包 g
被应用于 x,而闭包 f
被应用于生成的结果!哦,只对前两个闭包参数进行了 curry 处理,就有效地形成了一个组合了这两个闭包的效果的新闭包。
清单 5 组合了闭包 triple
和 quadruple
,形成闭包 twelveTimes
。当把这个闭包应用于实际参数 3 时,返回值是 36。
def multiply = { x, y -> return x * y } // closure def triple = multiply.curry(3) // triple = { y -> return 3 * y } def quadruple = multiply.curry(4) // quadruple = { y -> return 4 * y } def composition = { f, g, x -> return f(g(x)) } def twelveTimes = composition.curry(triple, quadruple) def threeDozen = twelveTimes(3) println "threeDozen: ${threeDozen}" // threeDozen: 36 |
非常漂亮,是么?
现在我们来研究闭包的一些更刺激的方面。我们先从一个机制开始,用这个机制可以表示包含计算模式 的闭包,计算模式是一个来自函数式编程的概念。计算模式的一个例子就是用某种方式把 List
中的每个元素进行转换。因为这些模式发生得如此频繁,所以我们开发了一个叫做 Functor
的类,把它们封装成 static Closure
。清单 6 显示了一个摘要。
package fp abstract class Functor { // arithmetic (binary, left commute and right commute) public static Closure bMultiply = { x, y -> return x * y } public static Closure rMultiply = { y, x -> return x * y } public static Closure lMultiply = { x, y -> return x * y } // ... // composition public static Closure composition = { f, g, x -> return f(g(x)) } // lists public static Closure map = { action, list -> return list.collect(action) } public static Closure apply = { action, list -> list.each(action) } public static Closure forAll = { predicate, list -> for(element in list) { if(predicate(element) == false) { return false } } return true } // ... } |
在这里可以看到名为 map
的闭包,不要把它与 Map
接口混淆。map
闭包有一个参数 f
代表闭包,还有一个参数 list
代表(不要惊讶)List
。它返回一个新 List
,其中 f
已经映射到 list
中的每个元素。当然,Groovy 已经有了用于 Lists
的 collect()
方法,所以我们在我们的实现中也使用了它。
在清单 7 中,我们把事情又向前进行了一步,对 map
闭包进行了 curry 处理,形成一个块,会将指定列表中的所有元素都乘以 12。
import fp.* def twelveTimes = { x -> return 12 * x } def twelveTimesAll = Functor.map.curry(twelveTimes) def table = twelveTimesAll([1, 2, 3, 4]) println "table: ${table}" // table: [12, 24, 36, 48] |
现在,这 就是我们称之为五星计算的东西!
关于闭包的技艺的讨论很不错,但是更关注业务的人会更欣赏下面这个例子。在考虑计算特定 Book
条目净值的问题时,请考虑商店的折扣和政府的税金(例如 增值税)。如果想把这个逻辑作为 Book
类的一部分包含进来,那么形成的解决方案可能是个难缠的方案。因为书店可能会改变折扣,或者折扣只适用于选定的存货,所以这样一个解决方案可能会太刚性了。
但是猜猜情况如何。变化的业务规则非常适合于使用 curry 过的闭包。可以用一组简单的闭包来表示单独的业务规则,然后用复合把它们以不同的方式组合起来。最后,可以用 计算模式 把它们映射到集合。
清单 8 演示了书店的例子。闭包 rMultiply
是个局部应用程序,通过使用一个不变的第二操作数,把二元乘法改变成一元闭包。两个图书闭包 calcDiscountedPrice
和 calcTax
是 rMultiply
闭包的实例,为乘数值设置了值。闭包 calcNetPrice
是计算净价的算法:先计算折扣价格,然后在折扣价格上计算销售税。最后, calcNetPrice
被应用于图书价格。
import fp.* class Book { @Property name @Property author @Property price @Property category } def bk = new Book(name : 'Groovy', author : 'KenB', price : 25, category : 'CompSci') // constants def discountRate = 0.1 def taxRate = 0.17 // book closures def calcDiscountedPrice = Functor.rMultiply.curry(1 - discountRate) def calcTax = Functor.rMultiply.curry(1 + taxRate) def calcNetPrice = Functor.composition.curry(calcTax, calcDiscountedPrice) // now calculate net prices def netPrice = calcNetPrice(bk.price) println "netPrice: ${netPrice}" // netPrice: 26.325 |
已经看到了如何把 curry 过的闭包应用于函数模式,所以现在我们来看看在使用相似的技术重新访问重要的面向对象设计模式时发生了什么。对于面向对象系统来说,必须遍历对象集合并在集合中的每个元素上执行某个操作,是非常普通的使用情况。假设一个不同的场景,系统要遍历相同的集合,但是要执行不同的操作。通常,需要用 Visitor 设计模式(请参阅 参考资料)来满足这一需求。Visitor
接口引入了处理集合元素的动作协议。具体的子类定义需要的不同行为。方法被引进来遍历集合并对每个元素应用 Visitor
动作。
如果到现在您还没猜出来,那么可以用闭包实现同的效果。这种方法的一个抽象是:使用闭包,不需要开发访问者类的层次结构。而且,可以有效地使用闭包复合和映射来定义集合的动作和效果遍历。
例如,考虑用来表示图书馆库存的类 Library
和类 Book
之间的一对多关系。可以用 List
或 Map
实现这个关系;但是 Map
提供的优势是它能提供快速的查询,也就是说用图书目录编号作为键。
清单 9 显示了一个使用 Map
的简单的一对多关系。请注意 Library
类中的两个显示方法。引入访问者时,两者都是重构的目标。
class Book { @Property title @Property author @Property catalogNumber @Property onLoan = false String toString() { return "Title: ${title}; author: ${author}" } } class Library { @Property name @Property stock = [ : ] def addBook(title, author, catalogNumber) { def bk = new Book(title : title, author : author, catalogNumber : catalogNumber) stock[catalogNumber] = bk } def lendBook(catalogNumber) { stock[catalogNumber].onLoan = true } def displayBooksOnLoan() { println "Library: ${name}" println "Books on loan" stock.each { entry -> if(entry.value.onLoan == true) println entry.value } } def displayBooksAvailableForLoan() { println "Library: ${name}" println "Books available for loan" stock.each { entry -> if(entry.value.onLoan == false) println entry.value } } } def lib = new Library(name : 'Napier') lib.addBook('Groovy', 'KenB', 'CS123') lib.addBook('Java', 'JohnS', 'CS456') lib.addBook('UML', 'Ken and John', 'CS789') lib.lendBook('CS123') lib.displayBooksOnLoan() // Title: Groovy; author: KenB lib.displayBooksAvailableForLoan() // Title: UML; author: Ken and John // Title: Java; author: JohnS |
清单 10 包含 Library
类中的几个闭包,模拟了访问者的用法。action
闭包(与 map
闭包有点相似)把 action
闭包应用于 List
的每个元素。如果某本书被借出,则闭包 displayLoanedBook
显示它;如果某本书未被借出,则闭包 displayAvailableBook
显示它。两者都扮演访问者和相关的动作。用 displayLoanedBook
对 apply
闭包进行 curry 处理,会形成闭包 displayLoanedBooks
,它为处理图书集合做好了准备。类似的方案也用来生成可供借阅的图书显示,如清单 10 所示。
import fp.* class Book { @Property title @Property author @Property catalogNumber @Property onLoan = false String toString() { return " Title: ${title}; author: ${author}" } } class Library { @Property name @Property stock = [ : ] def addBook(title, author, catalogNumber) { def bk = new Book(title : title, author : author, catalogNumber : catalogNumber) stock[catalogNumber] = bk } def lendBook(catalogNumber) { stock[catalogNumber].onLoan = true } def displayBooksOnLoan() { println "Library: ${name}" println "Books on loan" displayLoanedBooks(stock.values()) } def displayBooksAvailableForLoan() { println "Library: ${name}" println "Books available for loan" displayAvailableBooks(stock.values()) } private displayLoanedBook = { bk -> if(bk.onLoan == true) println bk } private displayAvailableBook = { bk -> if(bk.onLoan == false) println bk } private displayLoanedBooks = Functor.apply.curry(displayLoanedBook) private displayAvailableBooks = Functor.apply.curry(displayAvailableBook) } def lib = new Library(name : 'Napier') lib.addBook('Groovy', 'KenB', 'CS123') lib.addBook('Java', 'JohnS', 'CS456') lib.addBook('UML', 'Ken and John', 'CS789') lib.lendBook('CS123') lib.displayBooksOnLoan() // Title: Groovy; author: KenB lib.displayBooksAvailableForLoan() // Title: UML; author: Ken and John // Title: Java; author: JohnS |
在结束之前,我们来看一下 Groovy 闭包的一个附加用途。请考虑一个被建模为具有许多 Employee
的 Company
的应用程序。递归的关系在单个 Employee
(团队领导)和许多 Employee
(团队成员)之间进一步建立起一对多的聚合。图 1 是这样一个组织的类图。
可以用闭包来表述模型架构上的完整性。例如,在这个例子中,可能想确保每个员工都分配了一个经理。简单的闭包 hasManager
为每个员工表达了这个需求: def hasManager = { employee -> return (employee.manager != null) }
。
来自清单 6 的 Functor
类中的 forAll
闭包的局部应用程序能够描述架构的需求:def everyEmployeeHasManager = Functor.forAll.curry(hasManager)
。
清单 11 演示了 curry 过的闭包的应用:测试系统架构的完整性。
import fp.* /** * A company with any number of employees. * Each employee is responsible * to a team leader who, in turn, manages a team of staff. */ import java.util.* class Employee { @Property id @Property name @Property staff = [ : ] @Property manager = null String toString() { return "Employee: ${id} ${name}" } def addToTeam(employee) { staff[employee.id] = employee employee.manager = this } } class Company { @Property name @Property employees = [ : ] def hireEmployee(employee) { employees[employee.id] = employee } def displayStaff() { println "Company: ${name}" println "====================" employees.each { entry -> println " ${entry.value}" } } } def co = new Company(name : 'Napier') def emp1 = new Employee(id : 123, name : 'KenB') def emp2 = new Employee(id : 456, name : 'JohnS') def emp3 = new Employee(id : 789, name : 'JonK') co.hireEmployee(emp1) co.hireEmployee(emp2) co.hireEmployee(emp3) emp3.addToTeam(emp1) emp3.addToTeam(emp2) co.displayStaff() // Architectural closures def hasManager = { employee -> return (employee.manager != null) } def everyEmployeeHasManager = Functor.forAll.curry(hasManager) def staff = new ArrayList(co.employees.values()) println "Every employee has a manager?: ${everyEmployeeHasManager.call(staff)}" // false |
在本文中您已看到了大量闭包,但是希望能激起您对更多闭包的渴望。在学习乘法例子时,curry 过的闭包使得实现计算的函数模式出奇得容易。一旦掌握了这些模式,就可以把它们部署到常见的企业场景中,例如我们在书店例子中把它们应用于业务规则。把闭包应用于函数模式是令人兴奋的,一旦这么做了之后,再把它们应用于面向对象设计模式,就不是什么大事情了。Curry 过的闭包可以用来模拟 Visitor 模式的基本元素,正如在 Library
例子中显示的。它们在软件测试期间执行完整性测试时也会有用,就像用 Company
例子所展示的。
本文中看到的全部例子都是企业系统常见的用例。看到 Groovy 闭包和 curry
方法能够如此流畅地应用于众多编程场景、函数模式和面向对象模式,真是激动人心。Haskell Curry 肯定发现了这个可怕的groovy!
发表评论
-
实战 Groovy: 用 Groovy 打造服务器端
2010-07-10 11:07 2720Groovlet 和 GroovyServer P ... -
实战 Groovy: 用 Groovy 生成器作标记
2010-07-10 11:07 2060Groovy 生成器让您能够利用诸如 Swing 这样 ... -
实战 Groovy: for each 剖析
2010-07-10 11:07 18189在这一期的 实战 Groovy 中,Scott Davi ... -
实战 Groovy: 用 Groovy 进行 Ant 脚本编程
2010-07-10 11:07 2059Ant 和 Maven 两者在构建处理工具的世界中占统 ... -
实战 Groovy: 在 Java 应用程序中加一些 Groovy 进来
2010-07-10 11:06 4321您有没有想过在自己相对复杂的 Java 程序中嵌入 G ... -
实战 Groovy: Groovy 的腾飞
2010-07-10 11:06 2182随着 Groovy JSR-1(及其后续发行版本)的发 ... -
实战 Groovy: 关于 MOP 和迷你语言
2010-07-10 11:06 2064将耳朵贴到地上仔细听 —— MOP 正在前进!了解一下 ... -
实战 Groovy: 用 Groovy 更迅速地对 Java 代码进行单元测试
2010-07-10 11:06 2301不久以前,developerWor ... -
实战 Groovy: 构建和解析 XML
2010-07-10 11:05 7116通过本文,您将了解 ... -
实战 Groovy: 用 Groovy 进行 JDBC 编程
2010-07-10 11:05 5183这个月,随着 Andrew G ... -
实战 Groovy: 美妙的操作符
2010-07-10 11:05 2283Java™ 取消了操作符重载,但是新兴的 Groovy ... -
实战 Groovy: 使用 Groovy 模板进行 MVC 编程
2010-07-10 11:04 2910视图是 MVC 编程的一个重要部分,而 MVC 编程本 ... -
实战 Groovy: 用 Groovy 减少代码冗余
2010-07-10 11:04 2055Groovy 简洁的语法将 ... -
实战 Groovy: Groovy:Java 程序员的 DSL
2010-07-10 11:04 3079Groovy 专家 Scott Davis 将重新开始 ... -
精通 Grails: 构建您的第一个 Grails 应用程序
2010-07-06 09:37 1646Java™ 程序员不需要 ... -
Grails 部署
2010-07-06 09:36 6071部署 Grails可以使用很多种方式来部署,每一种 ... -
Grails 脚手架
2010-07-05 08:20 4075脚手架 根据指定的领域类,脚手架为你自动生成 ... -
Grails Grails 与 Hibernate
2010-07-05 08:19 2699Grails 与 Hibernate 如果 GOR ... -
Grails Grails和 Spring
2010-07-05 08:19 7901Grails和 Spring 这一节适合于高级用户 ... -
Grails Web服务
2010-07-05 08:19 3956Web服务 Web服务就是让你的web应用提供一套 ...
相关推荐
赠送jar包:groovy-3.0.9.jar; 赠送原API文档:groovy-3.0.9-javadoc.jar; 赠送源代码:groovy-3.0.9-sources.jar; 赠送Maven依赖信息文件:groovy-3.0.9.pom; 包含翻译后的API文档:groovy-3.0.9-javadoc-API...
在Groovy中,函数式编程的核心概念包括高阶函数、闭包、不可变数据结构和惰性计算。让我们逐一深入探讨这些概念: 1. **高阶函数**:高阶函数是可以接受一个或多个函数作为参数,或者返回一个函数的函数。Groovy中...
4. 文件I/O和网络编程:学习如何使用Groovy进行文件操作和网络通信。 5. 测试与调试:掌握Spock测试框架,进行单元测试和集成测试。 6. 深入理解Groovy与Java的互操作性,以便在既有Java项目中无缝引入Groovy。 五...
在一次代码拉取中,出现了以下问题:Could not download groovy-all.jar (org.codehaus.groovy:groovy-all:2.4.15) 详细的报错信息如下: // 报错信息如下 Could not resolve all files for configuration ':jcore-...
赠送jar包:groovy-all-2.4.5.jar; 赠送原API文档:groovy-all-2.4.5-javadoc.jar; 赠送源代码:groovy-all-2.4.5-sources.jar; 赠送Maven依赖信息文件:groovy-all-2.4.5.pom; 包含翻译后的API文档:groovy-all...
Groovy 脚本化Bean jar包下载
与传统的命令式编程不同,函数式编程中避免使用副作用,强调纯函数,即相同的输入永远产生相同的输出,不受外部状态的影响。这种编程方式有助于代码的可读性、可维护性和并行处理。 【Scala与Clojure】 Scala和...
最近的groovy-all-2.4.12.jar包供使用,解决as编译时报错问题
微服务-spring-boot-groovy 使用 Spring Boot 和 Groovy 构建微服务创建这些项目是为了在当地的达拉斯 Groovy Grails 用户组会议上展示微服务架构这些服务使用您需要安装才能开始使用的各种外部服务。 您将需要安装 ...
读书笔记:函数式编程 scala,java8,groovy 学习
在Groovy语言中,闭包是一种强大的特性,它允许我们创建可执行的代码块,并可以在不同的上下文中使用。闭包有三个重要的变量:`this`, `owner`, 和 `delegate`,它们各自扮演着不同的角色。 1. **this**: `this`...
Groovy也支持函数式编程范式,包括高阶函数、闭包和惰性求值。闭包是Groovy中的重要特性,它类似JavaScript的函数引用,可以作为参数传递或作为返回值。这使得代码更易于理解和维护,同时减少了副作用的可能性。 3...
groovy-all-2.4.15.jar文件,MAC使用时需存放在/Users/用户名/.gradle/caches/jars-3/某一缓存目录下,找不到就都看一下,我遇到的问题是缓存目录中下载的是2.4.17版本,应该跟gradle版本升级有关
在编程世界中,Groovy是一种基于Java...闭包不仅提高了代码的灵活性,还让我们的程序更符合函数式编程的原则,使得复杂问题的解决方案变得更加清晰。在Groovy的实践中,熟练掌握闭包的运用将大大提升我们的编程技能。
8. **函数式编程**: Groovy支持函数式编程风格,包括闭包和柯里化等高级特性。 9. **元编程(MOP)**: Groovy的元编程能力非常强大,可以通过反射等方式动态地修改类的行为。 #### 五、Groovy的未来 随着Groovy的不断...
2. 函数式编程支持:Groovy提供了闭包和高阶函数,使得函数式编程风格在Java平台上成为可能。 3. 隐式类型转换:Groovy可以自动将字符串转换为数字,简化了常见的类型转换操作。 4. GString:Groovy的GString(类似...
赠送jar包:groovy-3.0.9.jar; 赠送原API文档:groovy-3.0.9-javadoc.jar; 赠送源代码:groovy-3.0.9-sources.jar; 赠送Maven依赖信息文件:groovy-3.0.9.pom; 包含翻译后的API文档:groovy-3.0.9-javadoc-API...
Groovy的动态类型系统允许我们在编写代码时省略类型声明,同时在编译时进行类型检查,这种灵活性与函数式编程的简洁性相得益彰。 通过深入学习和实践"Functional Groovy"演讲中的示例,开发者可以更好地理解和运用...
7. **函数式编程支持**:Groovy支持闭包和高阶函数,这使得函数式编程风格在Groovy中变得非常自然,提高了代码的可读性和可维护性。 8. **动态和静态类型**:Groovy允许开发者在同一个项目中同时使用动态和静态类型...
Groovy jar包 3.0.