ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Learn X in Y Minutes 系列:Groovy 动态语言完整实战入门——集合、闭包与元编程(基于 learnxinyminutes-docs)

Learn X in Y Minutes 系列:Groovy 动态语言完整实战入门——集合、闭包与元编程(基于 learnxinyminutes-docs) 文档教程【免费下载链接】learnxinyminutes-docsCode documentation written as code! How novel and totally my idea!项目地址https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs点击查看免费下载本文以 learnxinyminutes-docs 仓库中的 es/groovy.md西班牙语版 Groovy 教程为骨架系统讲解 Groovy——这门运行于 Java 平台之上的动态语言的核心语法与高阶能力。读完本文你将掌握 Groovy 的安装启动、动态变量、集合与映射的增删改查、Groovy Beans 的编译规则、分支迭代、实用操作符、闭包及其记忆化、Expando 动态 Bean、MOP 元编程以及 TypeChecked/CompileStatic 静态化手段并可直接把文中的代码示例粘贴到 groovyConsole 或脚本中运行验证。环境准备一分钟跑通 GroovyGroovy 教程文档在正式进入语法之前首先给出了最精简的启动路线见 es/groovy.md 开头的配置注释块安装 GVMGroovy enVironment ManagerGroovy 环境管理器其后续版本即今天广泛使用的 SDKMAN用于管理 Groovy 及其生态工具的版本通过 GVM 安装 Groovy命令为gvm install groovy在终端输入groovyConsole启动 Groovy 的图形化控制台即可交互式地逐行执行 Groovy 代码。除了groovyConsole日常更常用的是命令行方式将代码保存为.groovy文件后直接运行groovy 文件名.groovy或者用groovy -e println Hello执行单行脚本。仓库根目录的英文原版 groovy.md 中给出的安装工具是 SDKMAN对应命令为sdk install groovy本质是同一套工具链的新旧版本名称读者可任选其一。值得注意的是本仓库中 Groovy 教程还有 中文版、加泰罗尼亚语版 与 葡萄牙语版多语言版本内容保持一致便于对照阅读。注释与 Hello WorldGroovy 的注释语法与 Java 完全兼容见文档注释小节单行注释以两条斜线//开头多行注释使用/* ... */包裹。入门仪式自然是 Hello World。Groovy 中println是语言的默认方法无需引入任何包即可直接调用println Hola mundo! // 输出Hola mundo!相比 Java 需要完整的类声明与public static void main样板代码Groovy 脚本直接书写语句即可运行这正是它作为可执行代码即文档的轻量特性的体现——本仓库 README.md 也明确说明所有教程都以带注释、可运行的代码形式呈现。动态变量def的魔力Groovy 是一门动态类型语言变量不需要声明类型。文档用一个x变量连续演示了它可以在不同时刻承载完全不同的类型def x 1 // 整数 println x x new java.util.Date() // 日期对象 println x x -3.1499392 // 浮点数 println x x false // 布尔值 println x x Groovy! // 字符串 println xdef关键字声明一个动态类型的变量其真实类型在运行时由赋值决定即便不用defGroovy 脚本中直接给未声明变量赋值如文档后文的contained ...、displayName ...也会被隐式创建。这种变量即类型的灵活性让原型开发极其高效也为后文的元编程能力埋下伏笔。集合与映射实战文档用相当大的篇幅演示了 Groovy 对列表List与映射Map的原生语法糖——它们既兼容 Java 的java.util集合 API又提供了大量 Groovy 独有的快捷写法。列表List增、删、遍历、检查、排序与操作创建空列表只需[]def technologies []添加元素有三种方式// 方式一与 Java 完全相同的 add 方法 technologies.add(Grails) // 方式二左移运算符 追加元素并返回列表本身可链式调用 technologies Groovy // 方式三一次添加多个元素 technologies.addAll([Gradle, Griffon])是 Groovy 对List重载的运算符语义等价于add但返回值是列表自身因此特别适合链式追加与流式构建。删除元素也有两条路径// 与 Java 相同 technologies.remove(Griffon) // Groovy 风格列表减法返回新列表不修改原列表 technologies technologies - Grails遍历列表使用闭包Closuretechnologies.each { println Technology: $it } technologies.eachWithIndex { it, i - println $i: $it }each中未命名参数以隐式变量it引用eachWithIndex则额外传入下标i闭包参数列表为{ 元素, 索引 - ... }。检查内容返回布尔值contained technologies.contains(Groovy) // Java 风格 contained Groovy in technologies // Groovy 的 in 操作符 technologies.containsAll([Groovy, Grails]) // 同时检查多个元素in操作符是contains的语法糖可读性更强日常推荐优先使用。排序分原地排序与非破坏性排序两种technologies.sort() // 修改原列表 sortedTechnologies technologies.sort(false) // 不修改原列表返回新列表其他操作则演示了 Groovy 与java.util.Collections工具类的无缝互操作// 替换列表中的所有指定元素 Collections.replaceAll(technologies, Gradle, gradle) // 用随机源打乱列表顺序 Collections.shuffle(technologies, new Random()) // 清空列表 technologies.clear()映射Map创建、赋值、遍历与查询映射字典是 Groovy 中与列表并列的另一大核心数据结构创建语法极为简洁def devMap [:] // 创建空映射 devMap [name:Roberto, framework:Grails, language:Groovy] // 字面量创建 devMap.put(lastName, Perez) // Java 风格添加键值遍历映射同样基于闭包且it是一个Map.Entry可通过it.key与it.value访问键值devMap.each { println $it.key: $it.value } devMap.eachWithIndex { it, i - println $i: $it }查询操作包括键与值的包含性判断、键集合与值集合的获取assert devMap.containsKey(name) // 是否包含某键 assert devMap.containsValue(Roberto)// 是否包含某值 println devMap.keySet() // 获取所有键 println devMap.values() // 获取所有值assert是 Groovy 内建断言关键字条件为假时抛出异常非常适合在脚本中做快速自检。Groovy Beans极简 JavaBean文档专门用一个注释块完整列出了 Groovy 编译为字节码时对属性property的处理规则这是理解 Groovy 对象模型的关键。汇总如下 8 条规则属性名带访问修饰符public、private、protected时编译后生成的是一个普通字段field属性名不带访问修饰符时会生成一个private字段并配套生成public的 getter 与 setter——即一个属性property属性声明为final时私有字段也是final且不会生成 setter只读属性可以同时声明属性和自定义的 getter/setter可以声明同名的属性与字段此时属性将使用该字段若希望属性是private或protected必须自行提供同样为private/protected的 getter 与 setter在类内部以隐式或显式this如this.foo或直接foo访问属性时Groovy 在编译期直接访问字段本身而不经过 getter/setter若访问一个不存在的属性隐式或显式fooGroovy 会经由元类meta class尝试解析这一过程可能在运行时失败。文档给出的示例类Foo集中体现了上述规则class Foo { // 只读属性final 字段无 setter final String name Roberto // 只读属性public getter protected setter String language protected void setLanguage(String language) { this.language language } // 动态类型属性 def lastName }可以看到name是final的只读属性language默认生成 public getter但通过自定义protected的 setter 收紧了写权限lastName用def声明类型完全动态。相比 JavaBean 动辄几十行的样板代码Groovy Bean 用三行声明即可表达完整的数据模型。逻辑分支与迭代经典的 if-elseGroovy 完全支持 Java 风格的if-else if-else结构def x 3 if (x 1) { println One } else if (x 2) { println Two } else { println X greater than Two }三元操作符def y 10 def x (y 1) ? worked : failed assert x workedElvis 操作符三元表达式的捷径当需要取非空值否则用默认值时三元写法冗长displayName user.name ? user.name : AnonymousGroovy 提供了 Elvis 操作符?:直接省略重复部分displayName user.name ?: Anonymous其语义为若user.name为真非 null、非 false、非空字符串等 Groovy 真值规则则取其值否则取Anonymous。该操作符在配置默认值、参数兜底等场景中极为常用是 Groovy 最具辨识度的语法特性之一。for 循环的四种形态Groovy 的for-in语法可以对范围、列表、数组、映射四种对象统一迭代// 1. 数值范围0..30 是闭区间 Range含 0 与 30 def x 0 for (i in 0 .. 30) { x i } // 2. 列表 x 0 for (i in [5, 3, 2, 1]) { x i } // 3. 数组先把范围转成数组再迭代 array (0..20).toArray() x 0 for (i in array) { x i } // 4. 映射e 是 Map.Entry用 e.value 取当前值 def map [name:Roberto, framework:Grails, language:Groovy] x for (e in map) { x e.value x } assert x.equals(Roberto Grails Groovy )最后一条assert验证了遍历映射时按插入顺序逐个取出值并拼接的结果。实用操作符文档挑选了两个在 Groovy 中高频使用的特色操作符完整的操作符重载清单见 Groovy 官方文档的操作符章节此处不作外部链接展开。展开操作符*.用于对聚合对象中的所有元素统一调用某个方法等价于collect与安全导航的组合def technologies [Groovy, Grails, Gradle] technologies*.toUpperCase() // 等价于technologies.collect { it?.toUpperCase() }该表达式返回一个新列表其中每个元素都被执行了toUpperCase()。*.内部对每个元素使用了安全导航语义?.即使存在 null 元素也不会抛异常。安全导航操作符?.用于避免空指针异常NPEdef user User.get(1) // 假设从数据层取用户可能返回 null def username user?.username // 若 user 为 null则 username 直接为 null而非抛 NPE当user为 null 时user?.username整体求值为 null而不是抛出NullPointerException有效消除了 Java 中大量冗长的判空样板。Closures闭包闭包Closure是 Groovy 最核心的语法构件可以理解为代码块或方法指针——一段被定义、稍后才执行的代码。文档给出的入门示例def clos { println Hello World! } println Executing the Closure: clos() // 调用闭包输出 Hello World!闭包定义使用花括号{ ... }调用方式与普通方法一致clos()或clos.call()。传递参数参数列表位于-左侧多个参数以逗号分隔def sum { a, b - println a b } sum(2, 4) // 输出 6捕获外部变量闭包可以引用其定义作用域中的变量这一点不同于 Java 的 lambda这是闭包最强大的特性之一def x 5 def multiplyBy { num - num * x } println multiplyBy(10) // 输出 50隐式参数it若闭包只接收一个参数可以省略参数声明直接用it引用def clos { print it } clos(hi) // 输出 hi正是这个it让前文technologies.each { println Technology: $it }这类遍历写法变得极为简洁。Closure 记忆化Memoize缓存计算结果Groovy 为 Closure 内置了记忆化memoization能力对相同参数的调用结果会被缓存第二次调用同一组参数时直接返回缓存值不再重新执行闭包体。文档用一个模拟耗时处理的闭包演示了这一点def cl { a, b - sleep(3000) // 模拟耗时 3 秒的处理 a b } mem cl.memoize() def callClosure(a, b) { def start System.currentTimeMillis() mem(a, b) println Inputs(a $a, b $b) - took ${System.currentTimeMillis() - start} msecs. } callClosure(1, 2) // 首次调用约 3000 msecs callClosure(1, 2) // 命中缓存接近 0 msecs callClosure(2, 3) // 首次调用约 3000 msecs callClosure(2, 3) // 命中缓存 callClosure(3, 4) // 首次调用约 3000 msecs callClosure(3, 4) // 命中缓存 callClosure(1, 2) // 再次命中缓存 callClosure(2, 3) // 再次命中缓存 callClosure(3, 4) // 再次命中缓存运行后可观察到每个参数组合的第一次调用耗时约 3000 毫秒之后的重复调用耗时趋近于 0 毫秒。memoize()的默认实现以参数组合为键缓存结果此外 Groovy 还提供memoizeAtMost(n)、memoizeAtLeast(n)、memoizeBetween(min, max)等带容量上限的变体适合在计算昂贵但结果稳定的场景如配置解析、数据聚合中直接使用。Expando动态 BeanExpando类是一个动态 Bean可以像操作普通对象一样为其实例动态添加属性甚至把闭包作为方法挂到实例上见文档 Expando 小节def user new Expando(name: Roberto) assert Roberto user.name // 动态添加属性 user.lastName Pérez assert Pérez user.lastName // 动态添加方法闭包闭包内可直接引用 this 上的属性 user.showInfo { out - out Name: $name out , Last name: $lastName } def sw new StringWriter() println user.showInfo(sw)构造时传入的name:Roberto会被直接转为属性随后lastName在运行期被动态创建showInfo则是一个以闭包形式挂载的方法内部通过隐式this访问name与lastName。StringWriter接收闭包写入的内容最终输出Name: Roberto, Last name: Pérez。Expando 非常适合需要临时组装带行为的轻量对象的场景如测试替身、动态配置对象。元编程MOPMetaprogrammingGroovy 的元对象协议Meta Object Protocol, MOP允许在运行时动态修改类的行为这是它区别于普通 Java 的标志性能力。文档依次展示了三种 MOP 用法。ExpandoMetaClass给既有类动态加方法// 给所有 String 实例动态添加 testAdd 方法 String.metaClass.testAdd { println we added this } String x test x?.testAdd() // 输出we added this通过类的.metaClass.方法名 闭包无需修改 String 类源码即可为整个类注入新方法此处挂载在String上影响所有字符串实例。?.保证即使x为 null 也不会抛异常。GroovyInterceptable拦截全部方法调用实现GroovyInterceptable接口并覆写invokeMethod类上的一切方法调用都会被拦截class Test implements GroovyInterceptable { def sum(Integer x, Integer y) { x y } def invokeMethod(String name, args) { System.out.println Invoke method $name with args: $args } } def test new Test() test?.sum(2, 3) // 不执行 sum 本体输出Invoke method sum with args: [2, 3] test?.multiply(2, 3) // 连不存在的方法也会被拦截注意拦截后sum的实际计算逻辑被invokeMethod完全接管因此输出的是拦截日志而非5multiply方法并不存在同样被统一拦截处理。这种机制是 AOP面向切面编程在语言层面的直接体现。propertyMissing处理属性解析失败当访问对象上不存在的属性时Groovy 会回调propertyMissing方法见文档最后一段示例class Foo { def propertyMissing(String name) { name } } def f new Foo() assertEquals boo, f.boo // 访问不存在的 boo 属性返回属性名 boof.boo本不存在但被propertyMissing捕获并返回属性名boo从而避免了运行时异常。类似的还有methodMissing用于拦截不存在的方法调用。这一机制被广泛用于构建 DSL领域特定语言例如让脚本中的自由标识符映射到数据字段。TypeChecked 与 CompileStatic为动态语言引入静态检查Groovy 本质上是且始终是动态语言但它同时提供了TypeChecked与CompileStatic两个编译期注解让开发者按需获得静态类型检查甚至静态编译的性能收益。TypeChecked编译期类型检查TypeChecked只做编译期检查不改变运行时的动态行为。文档第一个示例故意写了拼写错误的标识符import groovy.transform.TypeChecked void testMethod() {} TypeChecked void test() { testMeethod() // 拼写错误编译期报错 def name Roberto println naameee // 拼写错误编译期报错 }在普通动态模式下testMeethod()与naameee这类错误要等到运行时才暴露加上TypeChecked后编译器会直接判定其为未定义的方法/变量并报错将错误前移到编译期。第二个示例展示了类型不符时的检查import groovy.transform.TypeChecked TypeChecked Integer test() { Integer num 1 // 字符串赋给 Integer编译期报错 Integer[] numbers [1, 2, 3, 4] Date date numbers[1] // Integer 赋给 Date编译期报错 return Test // 返回 String 与声明返回类型 Integer 不符 }CompileStatic静态编译CompileStatic则在TypeChecked的基础上更进一步让方法按静态编译方式生成字节码牺牲部分动态能力换取更优的性能import groovy.transform.CompileStatic CompileStatic int sum(int x, int y) { x y } assert sum(2, 5) 7对于性能敏感的热点路径如数值计算、频繁调用的工具方法CompileStatic是 Groovy 项目中的常见优化手段。实践中可以遵循整体动态、热点静态的策略业务脚本保持动态以享受灵活性关键计算路径加上静态注解换取性能。延伸学习与仓库资源本文内容完整对应仓库中的 es/groovy.md如果你想继续深入仓库内还提供以下同主题资源groovy.md英文原版教程内容与本篇基本一致额外包含带默认参数的方法一节展示 Groovy 对方法默认参数值的支持def say(msg Hello, name world)可分别以零参、一参、两参三种方式调用zh-cn/groovy.md中文版教程适合快速对照查阅ca/groovy.md 与 pt-br/groovy.md加泰罗尼亚语与葡萄牙语版本多语言并行验证同一份语法事实。在书籍层面文档推荐了经典学习资料包括持续更新的 Groovy 技巧合集《Groovy Goodness》、体系完整的《Groovy in Action》第二版以及面向 Java 开发者讲动态生产力的《Programming Groovy 2: Dynamic Productivity for the Java Developer》。这些书籍与本文的语法速览互为补充前者讲技巧细节后者讲完整方法论适合在入门后按需选读。若要在团队中系统引入 Groovy官方文档、官方用户组与在线控制台都是文档原文推荐的延伸去处此处按仓库规范不再展开外部链接可自行在 Groovy 官网检索。赞分享文档教程【免费下载链接】learnxinyminutes-docsCode documentation written as code! How novel and totally my idea!项目地址https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs点击查看免费下载相关推荐Learn X in Y MinutesHTML5 标记语言实战指南基于 learnxinyminutes-docs 阿拉伯语版精讲Learn X in Y MinutesHTML5 标记语言实战指南基于 learnxinyminutes docs 阿拉伯语版精讲 HTMLHyper文档教程Learn X in Y minutes 之 JavaScript基于 cs/javascript.md 的语言核心完整实战指南Learn X in Y minutes 之 JavaScript基于 cs/javascript.md 的语言核心完整实战指南 本文以 learnxinym文档教程Learn Groovy in Y Minutes面向 Java 开发者的 Groovy 动态语言速成指南Learn Groovy in Y Minutes面向 Java 开发者的 Groovy 动态语言速成指南 Groovy 是运行于 Java 平台JVM之文档教程上一篇FIO项目中的MD5校验失败问题分析与解决方案下一篇Weighted-Boxes-Fusion算法原理深度解析从理论到实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表