在你开始前

了解对本教程的期望以及如何最大程度地利用本教程。

关于本教程

如果有人今天打算完全重写Java语言,那么Groovy与Java 2.0非常相似。 Groovy而不是替换Java,而是对其进行了补充,提供了一种更简单,更流畅的语法,其中类型检查在运行时动态完成。 您可以使用Groovy即时编写Java应用程序,将Java模块粘合在一起,甚至扩展现有的Java应用程序,甚至可以使用Groovy对Java代码进行单元测试。 它的优点在于,与编写纯Java代码相比,Groovy可使您更快地完成所有这些操作,有时甚至更快。

在本教程中,您将了解Groovy,这是一种动态语言,与Java语言本身一样,它在Java平台上的使用也很舒适。

目标

本教程将引导您逐步了解Groovy的基本概念。 您将了解Groovy集合,Groovy类,当然还有Groovy语法。 在完成了这一小时的教程之后,您将了解将Groovy与Java结合使用的好处(反之亦然),并且将被设置为在日常Java开发中开始使用Groovy。

先决条件

为了从本教程中获得最大收益,您应该熟悉Java语法和Java平台上面向对象开发的基本概念。

系统要求

要继续并尝试本教程的代码,您需要一个有效的安装

  • Sun的JDK 1.5.0_09 (或更高版本); 要么
  • IBM Java技术1.5.0 SR3开发人员套件

另外,本教程假设您正在使用Eclipse IDE 。 您无需安装Groovy,因为本教程将引导您完成Groovy Eclipse插件的安装。

本教程推荐的系统配置如下:

  • 支持具有至少500 MB主内存的Sun JDK 1.5.0_09(或更高版本)或IBM JDK 1.5.0 SR3的系统
  • 至少20 MB的磁盘空间用于安装所涵盖的软件组件和示例

本教程中的说明和示例均基于Microsoft Windows操作系统。 本教程中介绍的所有工具也可以在Linux和Unix系统上使用。

关于Groovy

在本节中,您将学习Groovy的基础知识:它是什么,它与Java语言和JVM之间的关系,以及一些编写Groovy代码的重点。

什么是Groovy?

Groovy是JVM的另一种语言- 替代的意思是,您可以像使用Java代码一样使用Groovy在Java平台上进行Java编程。 Groovy代码在编写新应用程序时可以与Java代码很好地结合在一起,也可以用于扩展现有应用程序。 Groovy当前为1.5.4版,可在Java 1.4和Java 5平台以及Java 6上运行。

关于Groovy的一件好事是,它的语法与Java语言中的语法非常相似。 尽管Groovy的语法是受Smalltalk和Ruby之类的语言启发的,但您可以将其视为Java语言上一种更简单,更具表现力的变体。 (Ruby在这方面与Groovy不同,因为它的语法与Java语法完全不同。)

许多Java开发人员都对Groovy代码和Java代码之间的相似性感到满意。 从学习的角度来看,如果您知道如何编写Java代码,那么您已经有点了解Groovy。 Groovy与Java语言之间的主要区别在于,Groovy使您可以编写更少的代码(有时少得多!)来完成您可能在Java代码中工作的相同任务。

Groovy快捷方式

在开始使用Groovy时,您会发现它使日常编程活动变得更快。 在完成本教程时,您将对Groovy的语法快捷方式了解很多。 现在,请考虑以下要点:

  • Groovy轻松的Java语法允许您删除分号和修饰符。
  • 除非另有说明,否则Groovy中的所有内容都是public
  • Groovy允许您定义简单的脚本,而不必定义正式的class对象。
  • Groovy在普通的日常Java对象上添加了一些神奇的方法和快捷方式,以使其更易于使用。
  • Groovy的语法还允许您删除变量的类型。

Groovy Extras

尽管Groovy允许您从Java语法中删除一些元素,但它还添加了新功能,例如本机集合,内置正则表达式和闭包。 在普通的Java代码中,如果要创建项目列表,请首先导入java.util.ArrayList (例如),然后以编程方式初始化ArrayList实例, 然后向其中添加项目。 在Groovy中,语法中内置了列表和地图-您无需导入任何内容。 正则表达式也不需要其他的导入或对象。 它们是通过特殊的Groovy语法创建的。

关于闭包

闭包是任何Java开发人员的绝招。 尽管这些神奇的构造将在即将发布的Java版本(很有可能是Java 7)中成为普通Java语法的一部分,但它们已经在Groovy中可用。 您可以将闭包视为可以定义的可执行代码块,然后在以后执行。 您可以使用这些强大的结构来完成许多整洁的事情,尽管它们以使迭代更容易而闻名。 开始使用Groovy,可能您将不再需要再次键入Iterator的实例。

动态槽

从技术上讲,Groovy是您最近可能经常听到的松散类型,动态语言之一。 在这方面,Groovy与Java语言(一种静态类型的语言)有很大不同。 在Groovy中,类型是可选的,因此您不必键入String myStr = "Hello"; 声明一个String变量。

更重要的是,Groovy代码可以在运行时轻松更改自身。 这实质上意味着,在运行时,可以轻松为对象赋予新的方法和属性。 Groovy很好地支持了整个编程领域,即元编程 。 在学习本教程的过程中,您将有机会进一步了解Groovy的动态特性。 到目前为止,只要说出Groovy多么容易地使用XML或普通的java.io.File实例,您就会感到惊讶。

一个样

您用Groovy编写的任何内容都可以编译成普通的Java类文件,并可以在Java代码中重复使用。 同样,您用普通Java代码编写的任何内容都可以在Groovy中重用。 因此,例如,您可以轻松地使用Groovy编写Java代码的单元测试。 而且,如果您在Groovy中编写了一个方便的实用程序,那么您也可以在Java程序中使用该实用程序。

Groovy的案例

学习新语言并非易事,即使是Groovy。 在本节中,更多地了解学习Groovy的动机。 此外,首先了解一些Groovy代码,并了解它与Java编程的比较。

为什么要学习Groovy?

即使Groovy与Java语言具有所有相似之处,它还是一种不同的语言。 您可能想知道为什么要花时间学习它。 简短的答案是Groovy是一种更具生产力的语言。 它提供了宽松的语法以及一些特殊功能,使您可以更快地编写代码。

仅举一个例子,一旦您看到使用Groovy导航集合有多么容易,您将永远不会再在Java中使用它们。 能够在Groovy中快速进行编码还意味着更快地收到反馈,更不用说将任务从待办事项列表中删除了。 从高层次上讲,如果您可以更快地将代码放在利益相关者面前,则可以在较短的时间内为他们提供更多版本。 本质上,Groovy比Java更适合于敏捷开发。

入门很容易

如果采用新语言的想法仍然令人生畏,请考虑将Groovy与您的开发环境集成起来有多么容易。 您不需要安装新的运行时实用程序或专用的IDE。 实际上,距离在类路径上使用Groovy仅一罐之遥。

另外,Groovy是一种开放源代码语言,由一群热情的Java开发人员管理。 由于Groovy是根据Apache软件许可2.0版获得许可的,因此您可以自由地使用它来开发免费的和专有的软件。

Groovy与Java语言

如果不进行测试就不会买摩托车,因此在要求您安装Groovy之前,我将向您展示一些代码。 首先,我快速提醒您使用Java创建,编译和运行标准Hello World示例的过程。 然后您会在Groovy代码中看到相同的过程。 比较这两个示例可以轻松理解两种语言之间的差异。

Java代码中的Hello World

Java代码中的原型Hello World示例如下所示:

public class HelloWorld {public static void main(String[] args) {    System.out.println("Hello World!");}
}

编译并运行Java示例

我已经为这个简单的HelloWorld类省略了一个程序包,并尝试不使用任何多余的编码约定来打印到控制台。 下一步是通过javac编译此类,如下所示:

c:>javac HelloWorld.java

最后,我运行生成的编译类:

c:>java HelloWorld

到目前为止,一切都很好–您可以想象很早以前就通过了Java 101,所以这只是一个更新。 接下来,在Groovy中查看相同的过程。

Groovy代码中的Hello World

正如我前面提到的,Groovy允许使用宽松的Java语法-例如,您不需要为诸如打印“ Hello World!”之类的简单动作定义类。

而且,Groovy使日常编码活动变得更加轻松。 例如,Groovy允许您键入println而不是System.out.println 。 Groovy足够聪明,可以在键入println时知道您的意思是System.out

因此,用Groovy编写Hello World程序非常简单:

println "Hello World!"

请注意,该短语周围没有类结构。 也没有方法结构! 我还使用了println而不是System.out.println

运行Groovy示例

假设我已将代码保存到名为MyFirstExample.groovy的文件中,则只需输入以下内容即可运行此示例

c:>groovy MyFirstExample.groovy

这就是单词“ Hello World!”的全部内容。 打印在我的控制台上。

行动捷径

您可能会注意到,我不必编译.groovy文件。 那是因为Groovy属于称为脚本语言的语言家族。 脚本语言的定义质量之一是可以在运行时解释它们。 (在Java中,字节码也作为编译源代码的结果进行解释和生成。区别在于脚本语言直接解释源代码。)

Groovy允许完全省略编译步骤,但你可以做到这一点,如果你想使用Groovy编译器, groovyc 。 用groovyc编译Groovy代码会产生正常的Java字节码,然后可以通过java命令运行它。 这是Groovy的一个关键方面,通常会被忽略:您在Groovy中编写的所有内容都可以通过正常的Java运行时进行编译和运行。

至于运行代码,如果我想更简洁一点,可以输入

c:>groovy -e "println 'Hello World!'"

完全不需要任何文件定义,即可达到相同的结果!

Groovy入门

在本节中,您实际上是从一些Groovy编程开始的。 首先,了解安装Groovy有多容易(通过Eclipse Groovy插件),然后从一些简单的示例开始,这些示例将帮助您了解Groovy。

Groovy的易于安装

为了快速使用Groovy,您需要做的就是安装Eclipse的Groovy插件。 打开Ecliplse并选择帮助菜单项> 软件更新 > 查找并安装...。

图1显示了执行上述步骤后所显示的对话框:

图1. Eclipse Feature Updates对话框

浏览选项

接下来,您将看到一个包含两个选项的对话框。 选择显示“ 搜索要安装的新功能”的单选按钮。 单击下一步按钮,然后选择新建远程站点...。 出现一个新对话框,其中有两个字段要填写:新位置的名称和该位置的URL,如图2所示:

图2.确保为新的远程站点提供有效的URL

输入“ Groovy plugin ”作为名称,并输入“ http://dist.codehaus.org/groovy/distributions/update/ ”作为位置。 单击OK ,然后确保在随后要包含在搜索框中的Sites中选择了名为“ Groovy plugin”的项目-您的列表应类似于图3所示。

图3. Eclipse中列出的远程站点

Wrapping up

单击“ 完成”按钮后,应显示“搜索结果”对话框。 再次确保您已选择“ Groovy插件”框,然后单击“ 下一步”按钮。 图4显示了此步骤:

图4.选择Groovy插件

在确认了许多内容之后,您将下载插件,然后您可能必须重新启动Eclipse。

创建一个Groovy项目

Eclipse重新启动后,您可以创建第一个Groovy项目。 确保创建两个源文件夹-一个称为“ groovy”,另一个称为“ java”。 您编写的Groovy代码在groovy文件夹中,而Java代码在java文件夹中。 我发现将两者分开很有帮助,如图5所示:

图5.两个源文件夹- Java和Groovy

将Groovy导入项目

创建项目后,右键单击其图标,您应该会看到Groovy选项,如图6所示。 选择该选项,然后选择添加Groovy Nature选项。 这样做会将必要的Groovy库,编译器和运行程序导入项目。

图6.在Eclipse中添加Groovy性质

创建一个Groovy类

创建Groovy类很简单。 选择groovy文件夹并右键单击它。 选择New ,然后选择Other ,如图7所示:

图7.通过New菜单创建一个Groovy类

给班级命名

从那里找到Groovy文件夹,然后选择Groovy Class-您应该看到一个如图8所示的对话框。

图8.选择创建一个Groovy类

单击下一步按钮,将要求您为班级命名。 键入HelloWorld

现在,您可以将HelloWorld Groovy类保留在默认包中,如图9所示。

图9.暂时不用担心软件包!

尽管这看起来似乎很多步骤,但与创建普通的Java类没有什么不同。

你好,世界! —用Groovy编写的Java程序

单击“ 完成”按钮后,应该显示如下代码片段:

class HelloWorld {static void main(args) {}
}

看起来很像以前的Java HelloWorld示例。 但是请注意,它不包含public修饰符。 另外,如果仔细查看main方法的参数,请注意没有类型。

编译程序

现在,继续在main方法内放置一个println "Hello World" ,如下所示:

class HelloWorld {static void main(args) {println "Hello World" }
}

您应该能够在源代码编辑器中右键单击,然后选择Compile Groovy File选项,如图10所示。

图10.右键单击Groovy文件以启用编译

运行程序

接下来,再次右键单击,然后选择“ 运行方式”选项,然后选择“ Groovy”选项。 您应该看到Eclipse控制台中印有“ Hello World”,如图11所示。

图11. Hello World从未如此令人愉悦

你学到了什么?

好的,这是提出重要观点的偷偷摸摸的方法。 Groovy 确实是 Java。 语法不同(大部分情况下较短),但是Groovy代码100%兼容Java字节码。 下一节将进一步探讨这两种语言的混合。

Groovy成为Java

您已经看到了第一个证明Groovy代码实际上可以与Java代码互换的证明。 当您继续玩Groovy构建的HelloWorld类时,本节将把这一点带回家。

您好,Java!

只是为了使自己确信Groovy是Java,请继续将public修饰符放在HelloWorld类声明和方法声明的前面,如下所示:

public class HelloWorld {public static void main(args) {println "Hello World"}
}

还是不服气?

没有理由不执行此代码。 但是,如果仍然不满意,请尝试在args参数前放置String[]

public class HelloWorld {public static void main(String[]args) {println "Hello World"}
}

现在不要停止

您已经走了这么远,所以您最好用System.out.println替换println ,并且不要忘了加上括号以取得良好效果。

public class HelloWorld {public static void main(String[] args) {System.out.println("Hello World")}
}

现在,回到以Java代码编写的原始Hello World示例开始的地方。 问题是,哪个示例更容易编写?

请注意,原始的基于Groovy的HelloWorld类如何缺少任何public修饰符,任何类型(没有String[] ),并提供快捷方式println而不带括号来引导。

您好,Groovy!

如果需要,您可以将这一过程彻底推翻。 只需回到基于Java的Hello World示例,删除文件中除System.out行以外的所有内容 ,然后在使用时删除System.out和括号。 这是剩下的东西:

println "Hello World"

现在,哪个程序更容易编写?

运行!

正如本练习所证明的那样,Groovy代码与Java字节码100%兼容。 在Eclipse中,选择“ 运行”菜单选项“ 打开运行对话框...” 。 选择一个新的Java应用程序配置。 确保该项目是您的Groovy项目。 对于Main类,单击“ 搜索”按钮,找到您的HelloWorld类。 请注意,单词class表示Eclipse Groovy插件已将您的.groovy文件编译为.class文件。

您可以在下面的图12中看到整个过程的运行情况-如果您以前在Eclipse中运行过Java类,则应该看起来很熟悉。

图12. Groovy代码与Java字节码100%兼容

点击运行按钮,您会看到什么? 确实是“ Hello World!” 从未如此显露。

Groovy是没有类型的Java代码

诱人的是,Groovy只是没有规则的Java代码,但实际上,它只有更少的规则。 本节着重于开始使用Groovy编写Java应用程序时遗留下来的Java编程的具体方面之一:类型定义。

为什么要输入类型?

在Java中,如果要声明String变量,则必须键入:

String value = "Hello World";

但是,如果考虑一下,等号右边的字符已经暗示String是变量value的类型。 因此,Groovy允许您将String类型变量放在value前面,并用def替换它。

def value = "Hello World"

本质上,Groovy通过其值推断对象的类型。

运行!

继续编辑您的HelloWorld.groovy文件,如下所示:

String message = "Hello World"
println message

运行此代码,您将在控制台上看到相同的旧“ Hello World”。 现在,用def替换String变量类型,然后重新运行代码。 你注意到同一件事了吗?

您可以通过以下调用来打印其类型,而不是打印message的值:

def message = "Hello World"
println message.class

现在,打印“ class java.lang.String ”应该是一个受欢迎的更改! 如果您想知道发生了什么,那么Groovy会发现该message必须是String类型的,因为它的值用引号引起来。

有关类型推断的更多信息

您可能已经听说过Groovy中的“一切都是对象”,但这对类型意味着什么? 好吧,让我们看看如果用数字替换上一个示例中的String会发生什么,如下所示:

def message = 12
println message.class

message变量的数值看起来像Java的原始int类型。 运行此代码表明Groovy使它成为Integer 。 那是因为Groovy中的“一切都是对象”,还记得吗?

Java中的每个对象都扩展了java.lang.Object ,这对于Groovy而言非常方便。 即使在Groovy运行时无法确定变量类型的最坏情况下,它所要做的就是将其设置为Object然后一切正常。

继续并使用此代码。 使message随心所欲:Groovy将尽最大努力在运行时推断其类型。

无类型的含义

因此,Groovy缺少类型意味着更少的键入。 诚然,用def代替String并不会真正节省您很多击键-几乎没有什么值得夸耀的! 但是在更高的层次上,在编写大量不仅仅包含变量声明的代码的过程中,类型的缺乏实际上确实使打字少了很多。 更重要的是,它意味着更少的代码可读取。 最后但并非最不重要的一点是,Groovy中类型的缺乏开辟了一个全新的灵活性世界-顺便说一句,这种灵活性不需要接口或抽象类。

瞧,您只需要在方法中声明独立变量时使用def关键字即可; 您不需要在方法声明中使用def关键字作为参数。 例如,您也不需要在for循环声明中使用它们,这意味着您无需编写(int x = 0; x < 5; x++) 。 相反,您可以删除int并将其留空。

通过Groovy循环

与大多数脚本语言一样,Groovy通常被吹捧为Java语言的一种更有生产力的替代方法。 您已经了解了Groovy缺乏类型是如何减少键入的。 在本节中,您将创建然后尝试repeat功能。 在此过程中,您将探索更多Groovy以详细程度进行交易以提高效率的方式。

更好,循环更短

这是一种欣赏Groovy缺少类型的有趣方法:首先,以与创建HelloWorld相同的方式创建一个新的Groovy类。 将该类MethodMadness并删除自动生成的类主体:您将改为定义一个独立的repeat函数。 现在,在控制台中输入以下内容:

def repeat(val){for(i = 0; i < 5; i++){println val}
}

刚开始,这个小功能在您受Java训练的眼睛中可能看起来很奇怪(实际上,它看起来很像JavaScript)。 但是,您看到的是Java代码。 它只是以Groovy风格编写的。

内部方法

repeat函数采用一个变量val 。 注意该参数如何不需要def 。 该方法的主体实质上是for循环。

调用此功能

repeat("helloworld")

打印五次“ hello world”。 请注意, for循环如何使我可以删除int 。 没有变量类型的for循环比通常的Java价格短一些。 现在看看将范围投入混合时会发生什么。

Groovy的范围

范围是值的序列。 例如,“ 0..4 ”表示包含整数0、1、2、3、4。Groovy还支持互斥范围,其中“ 0..<4 ”表示0、1、2、3。您也可以创建字符范围:“ a..e ”等于a,b,c,d,e。 “ a..<e ”将是所有这些值减去e 。

循环范围

范围可以很好地促进循环。 例如,您之前的for循环将整数从0递增到4,如下所示:

for(i = 0; i < 5; i++)

一个范围将做出for循环更干净漂亮阅读:

def repeat(val){for(i in 0..5){println val}
}

设置范围

如果尝试运行此示例,可能会注意到一个小问题:“ Hello World”打印六次而不是五次。 有三种方法可以解决此问题:

  • 将包含范围限制为4:

    for(i in 0..4)
  • 从1开始而不是0:
    def repeat(val){for(i in 1..5){println val}
    }
  • 将范围从“包含”更改为“专有”:
    def repeat(val){for(i in 0..<5){println val}
    }

无论用哪种方式裁剪,都可以回到开始的地方-打印“ Hello World”五次。

默认参数值

到目前为止,您已经通过使用Groovy的range表达式设法缩短了repeat函数。 但是,该功能仍存在一些限制。 如果您想重复八次“ Hello World”怎么办? 实际上,如果您想以不同的方式重复某些值,比如说八次“ Hello World”,而又说两次“再见阳光”,该怎么办?

每次拨打repeat电话时都必须指定所需的重复次数会变旧,特别是如果您已经习惯了默认行为(即重复五次)时,尤其如此。

Groovy支持默认参数值 ,该默认值允许您在函数或方法的形式定义中指定参数的默认值。 该函数的调用者可以选择省略该参数并接受默认值。

更复杂的参数值

使用较早版本的repeat函数,如果要提供允许调用者指定重复值的选项,则可以按以下方式对其进行编码:

def repeat(val, repeat=5){for(i in 0..<repeat){println val}
}

调用函数,如下

repeat("Hello World", 2)
repeat("Goodbye sunshine", 4)
repeat("foo")

结果是“ Hello World”打印两次,“再见阳光”打印四次,“ foo”默认打印五次。

Groovy集合

在Groovy提供的所有方便的快捷方式和功能中,最有用的功能之一可能是内置的集合。 想一想关于如何在Java编程中使用集合的方法-在此处导入java.util类,在那里进行初始化,然后向其中添加一些项目。 仅这三个步骤就构成了多行代码。

另一方面,Groovy有助于直接在语言内使用集合。 在Groovy中,您不需要导入专门的类,也不需要初始化对象。 集合是语言本身的本地成员。 Groovy还通过直观地帮助添加和删除项目,使使用集合(或列表,如果您愿意)非常容易。

范围可以是一个集合

在上一节中,您学习了如何使用Groovy的范围来简化循环。 范围表达式“ 0..4 ”表示数字的集合 — 0、1、2、3和4。要对此进行测试,请创建一个新类并将其命名为Ranger 。 保留类定义和main方法声明。 但是这次,添加以下内容:

def range = 0..4
println range.class
assert range instanceof List

注意assert短语如何证明范围是java.util.List实例。 继续并运行以下代码以验证范围现在是List类型的集合。

广泛的支持

Groovy的集合支持广泛,其优点在于,在魔术的作用下,一切都是普通的Java对象。 每个Groovy集合都是java.util.Collectionjava.util.Map的实例。

如前所述,Groovy的语法提供了本地列表和地图。 例如,尝试将以下两行代码添加到Ranger类中:

def coll = ["Groovy", "Java", "Ruby"]
assert  coll instanceof Collection
assert coll instanceof ArrayList

您会注意到coll对象看起来像Java语言中的数组。 实际上,这是一个Collection 。 要在普通的Java代码中实现集合的相同实例,您必须执行以下操作:

Collection<String> coll = new ArrayList<String>();
coll.add("Groovy");
coll.add("Java");
coll.add("Ruby");

在Java代码中,必须使用add()方法将项目添加到ArrayList的实例。

加起来

Groovy提供了多种向项目列表中add()方法-您可以使用add()方法(因为基础集合是常规ArrayList类型),但是您也可以尝试许多快捷方式。

例如,以下代码中的每一行都会向基础集合添加一些内容:

coll.add("Python")
coll << "Smalltalk"
coll[5] = "Perl"

注意Groovy如何启用运算符重载- <<运算符已重载以允许将项添加到集合中。 另外,您可以通过位置参数直接添加项目。 在这种情况下,由于集合中只有四个项目,因此[5]运算符将“ Perl”放在最后一个位置。 继续并打印出收藏,亲自看看吧。

检索很容易

如果需要从集合中获取特定项目,则可以通过类似于上面的位置参数来获取它。 例如,如果要获取第二个项目“ Java”,则可以编写如下内容(请记住,集合和数组是从零开始的):

assert coll[1] == "Java"

Groovy还允许您彼此添加或减去集合,如下所示:

def numbers = [1,2,3,4]
assert numbers + 5 == [1,2,3,4,5]
assert numbers - [2,3] == [1,4]

注意,在上面的代码片段中,您已经创建了一个新的集合实例,正如代码中的最后一行所暗示的那样。

引导的魔术方法

Groovy还向集合添加了其他一些方便的功能。 例如,您可以获取集合的实例并在其上调用专用方法,如下所示:

def numbers = [1,2,3,4]
assert numbers.join(",") == "1,2,3,4"
assert [1,2,3,4,3].count(3) == 2

join()count()只是可用于对任何项目列表进行调用的许多不同便利方法中的两种。 散布运算符是一种特别方便的实用程序,它有助于在集合中的每个项目上调用方法,而不必迭代集合。

给定一个String列表,如果您想将它们全部大写,则可以编写

assert ["JAVA", "GROOVY"] == ["Java", "Groovy"]*.toUpperCase()

注意*. 符号。 对于上面列表中的每个值,将调用toUpperCase() ,以每个大写String实例生成一个集合。

Groovy地图

除了具有广泛的列表处理功能之外,Groovy还提供了一种强大的映射机制。 就像列表一样,地图是本机数据结构。 与往常一样,Groovy中的任何映射机制都是在后台的java.util.Map实例。

Java语言映射

Java语言中的映射是名称-值对的集合。 因此,要在Java代码中创建典型的地图,您必须执行以下操作:

Map<String, String>map = new HashMap<String, String>();
map.put("name", "Andy");
map.put("VPN-#","45");

一个HashMap实例包含两个名称-值对,每个对都是String一个实例。

通过Groovy进行映射

Groovy使使用地图和使用列表一样容易—例如,您可以在Groovy中将上面的基于Java的地图编写为

def hash = [name:"Andy", "VPN-#":45]

请注意,Groovy映射中的键不必是String 。 在这种情况下, name看起来像一个变量,但是Groovy在幕后将其String

都是Java

现在继续创建一个名为Mapper的新类,并添加该代码。 然后添加以下行,以验证您在下面使用真实的Java代码:

assert hash.getClass() == java.util.LinkedHashMap

您会看到Groovy使用了Java的LinkedHashMap类型,这意味着您可以使用常规Java习惯用法从该hash putget项目。

hash.put("id", 23)
assert hash.get("name") == "Andy"

地图是如此古怪

希望您现在已经看到Groovy在任何方程式中添加了自己的魔力; 因此,您可以使用将项目放入地图中. 符号。 如果要向地图添加新的名称/值对(例如dob和“ 01/29/76”),则可以这样做,例如:

hash.dob = "01/29/76"

. 符号也可用于获取项目。 例如,以下是获取dob值的方法:

assert hash.dob == "01/29/76"

当然是. 比调用get()更具趣味性,不是吗?

位置图

您还可以使用伪位置语法将项放入地图并从其中获取项,如下所示:

assert hash["name"] == "Andy"
hash["gender"] = "male"
assert hash.gender == "male"
assert hash["gender"] == "male"

但是请注意,通过[]语法从地图中获取项目时,必须将项目引用为String

Groovy中的闭包

闭包现在是Java世界中的一个大话题,而闭包可能包含在Java 7中仍是热门话题。 有人问为什么Groovy中已经存在Java闭包的原因。 在本节中,了解Groovy中的闭包。 如果没什么别的,一旦闭包成为Java语言语法的正式组成部分,您将在这里学到的东西会派上用场。

没有更多的迭代器

在上一部分中,您对集合进行了大量编码,但实际上尚未遍历一个。 当然,您知道Groovy是Java,因此您可以随时获取旧Java Iterator的实例,并像这样遍历一个集合:

def acoll = ["Groovy", "Java", "Ruby"]for(Iterator iter = acoll.iterator(); iter.hasNext();){println iter.next()
}

但是,实际上您不需要在for循环内for类型声明,因为Groovy已使迭代成为任何集合的直接成员。 在这种情况下,您不必直接获取Iterator并直接对其进行操作,而可以直接对集合进行迭代。 而且,通常原本打算驻留在循环结构中的行为(例如for循环主体中的println )随后被放入闭包中。 在我们走得太远之前,让我们来看一下实际情况。

您能发现封盖吗?

从上面获取相同的代码,您可以更简洁地遍历集合,如下所示:

def acoll = ["Groovy", "Java", "Ruby"]acoll.each{println it
}

请注意如何在acoll实例上直接调用each实例,您已经知道它们是ArrayList类型的。 each调用之后, each引入新的语法- { ,然后是一些代码,然后是} 。 The block of code signified by the {} is what's known as a closure.

Execute it

Closures are blocks of executable code. They don't require names, and they can be executed after they've been defined. So, in the case above, the nameless closure whose body has the behavior of printing it (I'll explain what it is shortly) is called for every value in the acoll collection type.

At a high level, the code between the {} is executed three times, thus printing what you see in Figure 13.

Figure 13. Iteration has never been so easy

The it variable inside the closure is a keyword that points to the individual value of the outside collection being invoked — it is a default value that can easily be overridden by passing a parameter into the closure. So for instance, the following code does the same exact thing, but uses its own item variable:

def acoll = ["Groovy", "Java", "Ruby"]acoll.each{ value ->println value
}

In this case, value is used instead of Groovy's default it .

Ubiquitously iterating

Closures appear frequently in Groovy; however, you'll use them most often when iterating over a series of values. Keep in mind, a series of values can be represented in more ways than just as a list — for example you can iterate over a map, a String , a JDBC Rowset , a line in a File , and more.

If you wanted to iterate over the hash object from the previous section of mapping in Groovy, you could write the following:

def hash = [name:"Andy", "VPN-#":45]
hash.each{ key, value ->println "${key} : ${value}"
}

Note how closures also permit multiple parameters — in this case, the code above contains two parameters ( key and value ).

Iteration in Java code

Just as a friendly reminder, here's how you would do the same iteration using typical Java constructs:

Map<String, String>map = new HashMap<String, String>();
map.put("name", "Andy");
map.put("VPN-#","45");for(Iterator iter = map.entrySet().iterator(); iter.hasNext();){Map.Entry entry = (Map.Entry)iter.next();System.out.println(entry.getKey() + " : " + entry.getValue());
}

The above code is verbose compared to Groovy's, isn't it? If you find yourself working a lot with collections, it just makes sense to do it in Groovy.

Total iteration

Remember, anything that is a collection or series of some sort can be iterated as shown in the code below.

"ITERATION".each{println it.toLowerCase()
}

More ways to use closures

While you'll probably find yourself using closures most often for iteration, they do have other uses. Because a closure is a block of code, closures can be passed around as parameters (which you can't do with functions or methods in Groovy). The fact that closures are executed when called (rather than during definition) makes them quite useful for particular scenarios.

For instance, create a ClosureExample object via Eclipse and leave in the default class syntax it gives you. In the resulting main() method, add this bit of code:

def excite = { word ->return "${word}!!"
}

This code is a closure named excite . This closure takes one parameter (named word ) and returns a String with the word variable along with two exclamation points. Note the use of substitution within the String instance. Using the ${value} syntax within a String tells Groovy to replace the value of a particular variable within the String itself. Think of this syntax as a handy way to do the equivalent of return word + "!!"

Delayed execution

Now that you have a closure, it's time to actually use it. You can call closures one of two ways: either directly or via the call() method.

Using your ClosureExample class, go ahead and add the following two lines of code below the closure's definition:

assert "Groovy!!" == excite("Groovy")
assert "Java!!" == excite.call("Java")

As you can see, either style of invocation works, though calling it directly is more concise. Don't forget that closures are first-class objects in Groovy too — they can be passed around as parameters and of course, executed at some later point. Replicating the same behavior in normal Java is possible, but not exactly easy. But that's no surprise to you by now, right?

Classes in Groovy

Thus far, you've printed "Hello World" numerous times via Groovy, you've worked with collections, you've iterated over collections using closures, and you've even defined a closure on your own. You have managed to do all of this without discussion of a concept that is fundamental to Java developers — classes.

Of course, you've been working with classes for a while in this tutorial already: the last few examples you coded were in the main() method of various classes. And, as you already know, you can define classes in Groovy just like you do in your Java code. The only difference is, you don't need to put in public modifiers and you can drop types for method parameters. This section introduces you to all the other things you can do with Groovy classes.

The Song class

Start by defining a simple, JavaBeans-like class in Groovy called Song .

The first step, naturally, is to create a class in Groovy called Song . This time, create a package structure for it too — go ahead and create a package name like org.acme.groovy .

Once you've created this class, remove main() that was automatically generated for you by the Groovy plugin.

A song has a few properties — the artist who created it, the name of the song, and a genre, to name a few. Add those properties to your newly created Song class, like so:

package org.acme.groovyclass Song {def namedef artistdef genre
}

So far so good, right? It's nothing too complex for the new Groovy developer!

A Groovy class is a Java class

You should recall from earlier in this tutorial that the Groovy compiler creates a normal Java .class for every class you define in Groovy. Remember how you defined a HelloWorld class in Groovy and found the .class and ran it? You could do the same with your newly defined Song class. If you do compile the code via Groovy's groovyc compiler (which, by the way, the Eclipse Groovy plugin is already doing for you), a Song .class file is generated.

All this means that if you want to use your new Song class in another Groovy class or Java class, you'll have to import it (unless, of course, the code that will use Song resides in the same package as Song ).

Accordingly, go ahead and create a new class, called SongExample and put it into another package structure, say org.thirdparty.lib .

You should now be looking at some code that looks like this:

package org.thirdparty.libclass SongExample {static void main(args) {}
}

Class relationships

Now it's time to use that Song class. First import the instance and add this code into SongExample 's main() method.

package org.thirdparty.libimport org.acme.groovy.Songclass SongExample {static void main(args) {def sng = new Song(name:"Le Freak", artist:"Chic", genre:"Disco")}
}

Now that's a Song instance you can dance to! Look closely, though, at the initialization of the Song class you defined earlier. Do you notice anything special? You should notice the auto-generated constructor.

Class initialization

Groovy automatically gives you a constructor that takes a map of name-value pairs, which correspond to class properties. This, by the way, is an out-of-the-box feature of Groovy — for any properties you define in a class, Groovy permits you to pass a map full of values into a constructor. The use of a map does have implications; for instance, you don't actually have to initialize every property of an object.

You can just as well add this code, too:

def sng2 = new Song(name:"Kung Fu Fighting", genre:"Disco")

You are also free to directly manipulate properties of a class, like so:

def sng3 = new Song()
sng3.name = "Funkytown"
sng3.artist = "Lipps Inc."
sng3.setGenre("Disco")assert sng3.getArtist() == "Lipps Inc."

Looking at this code, it is evident that not only did Groovy create a constructor that permits passing in a map of properties and their values, but you can semi-directly access properties via the . syntax. Moreover, Groovy also generated normal setter and getter methods.

What's particularly groovy about Groovy, when it comes to property manipulation, is that setters and getters are always called — even if you access a property directly via the . syntax.

Flexibility at the core

Groovy is an inherently flexible language. For instance, see what happens when you drop the parentheses from the setGenre() method invocation from the previous panel; like so:

sng3.setGenre "Disco"
assert sng3.genre == "Disco"

In Groovy, for methods that take parameters, you can optionally drop the parentheses — in some ways, doing so makes the code a bit easier to read.

Method overriding

So far you've managed to create a few instances of the Song class. Although, right now they don't do anything particularly interesting. You can print one using the following command:

println sng3

All that does is print the default toString() implementation of all objects in Java, namely the class and it's hashcode (that is, org.acme.groovy.Song@44f787 ). Let's see what happens when you override the default toString() implementation to print something a bit nicer.

In your Song class, add the following code:

String toString(){"${name}, ${artist}, ${genre}"
}

Based on what you've learned in this tutorial, you were able to drop the public modifier on the toString() method. You still needed to specify a return type ( String ) in order to actually override the proper method. The body of the method is tersely defined — but where is the return statement?

No return needed

You've probably already figured out that in Groovy you can omit the return statement. Groovy assumes the last line in a method should be returned. So in this case, a String is returned containing the values of the class's properties.

Go ahead and re-run the SongExample class. You should see something a bit more interesting when you do. The toString() method returns a description instead of a hashcode.

Specialized access

Groovy's auto-generation is handy for a few features, but sometimes you need to override default behavior. For instance, let's say you need to override the getGenre() method in the Song class, so that the returned String is all capitalized.

Providing this new behavior is quite easy, just define a getGenre() method. You can have either have the method's declaration return a String or you can omit it entirely if you wish. Go ahead and do the simplest possible thing:

def getGenre(){genre.toUpperCase()
}

Like before, your simple method omits a return type and a return phrase. Now run your SongExample class again. You should see something unexpected ---there is now a nullpointer exception.

Nullpointer safety

If you've followed along so far, you should at some point have added this line to your SongExample class:

assert sng3.genre == "Disco"

The result was an assertion failure when you re-ran SongExample — which is why all that ugly red text printed out in your Eclipse console. (Sorry about pulling such a dirty trick, by the way.)

Fortunately, you can easily fix the error: just add the following line of code to the SongExample class:

println sng2.artist.toUpperCase()

But wait, now more red text is streaming down your console — what happened?!

Nasty nulls

If you remember, the sng2 instance didn't define an artist value. As a result, a Nullpointer exception was generated when you invoked the toUpperCase() method.

Luckily, Groovy provides a safety net, via the ? operator — preceding a method call with ? is like putting a conditional in front of the call which guards calling a method on a null object.

For example, replace the line sng2.artist.toUpperCase() with sng2.artist?.toUpperCase() . Note that you are also free to omit the trailing parentheses in this case. (Groovy actually permits you to drop parentheses on methods without parameters, too. Doing so can cause issues if Groovy thinks you are accessing a class' properties rather than a method, however.)

Re-running the SongExample class now demonstrates the ? operator's usefulness. In this case, you aren't presented with a nasty exception. Now go ahead and place this code in the same class and re-run the whole song.

def sng4 = new Song(name:"Thriller", artist:"Michael Jackson")
println sng4

Just being Java

You'll notice that no exception was generated, though you may have expected one. Even though you didn't define a genre , the getGenre() method invoked toUpperCase() .

You remember that Groovy is Java, right? So in Song 's toString() s you referenced the genre property itself; hence, getGenre() wouldn't be called. Go ahead and change the toString() method to use getGenre() , and then see what happens.

String toString(){"${name}, ${artist}, ${getGenre()}"
}

Re-running SongExample reveals a similar exception. Now, see what happens when you try fixing it on your own.

Another handy little operator

Hopefully, your fix is similar to mine. As you can see below, I augmented the getGenre() method in the Song class to make use of Groovy's handy ? 操作员。

def getGenre(){genre?.toUpperCase()
}

The ? operator is quite useful from time to time and most certainly cuts down on conditional phrases.

Unit testing Groovy

This tutorial has emphasized the fact that Groovy is just another variation of Java. You've even seen that you can code normal Java using Groovy and get away with it. To drive this point home one last time, you conclude this tutorial by testing your Song class with JUnit using Java .

Add JUnit to your Eclipse project

In order to follow the examples in this section, you need to add JUnit to your Eclipse project. First, right-click on your project and select Build Path and then select Add Libraries as Figure 14 shows:

Figure 14. Adding JUnit to a project's build path

You are presented with the Add Library dialog box like the one in Figure 15.

Figure 15. Select JUnit from the list of libraries

Select JUnit and hit the Next button. You should see a dialog box like the one in Figure 16. Select JUnit3 or 4 — the choice is entirely up to you — and hit the Finish button.

Figure 16. To JUnit 3 or to JUnit 4

Set up a new test case

Now that you've got JUnit in your project's classpath, you can write a JUnit test. Right-click on the java source folder and select New followed by JUnit Test Case . Define a package, give the test case a name (like SongTest ) and in the Class Under Test section, hit the Browse button.

Note that you can select the Song class that you defined in Groovy. Figure 17 demonstrates this step:

Figure 17. Find the Song class

Select that class and hit OK (you should see a dialog box similar to the one in Figure 18) and then hit the Finish button in the New JUnit Test Case dialog.

Figure 18. A new test case for Song

Define the test method

I chose to use JUnit 4; consequently, I went ahead and defined a test method named testToString() like so:

package org.acme.groovy;import org.junit.Test;public class SongTest {@Testpublic void testToString(){}}

Test toString

Obviously, you want to verify that the toString() method is clean, so what's your first step? If you thought to yourself "import the Song class" you are thinking too hard — the Song class is in the same package. Consequently, the first step is to create an instance of it.

In creating an instance of Song to test, note that you don't have the ability to fully initialize an instance via a map passed into a constructor — what's more, if you attempt auto-completion of the instance's setter methods, see that each setter takes an Object rather than a String (look closely at Figure 19, just in case). 这是为什么?

Figure 19. All the setters and getters are there

Groovy makes it work

If you remember at the beginning of the tutorial, I said:

Because every object in Java extends java.lang.Object , even in the worst case scenario where Groovy can't ascertain what a variable's type is, all Groovy has to do is make it an Object and things will, believe it or not, work out.

Now recall that when you defined the Song class, you omitted each property's type. Groovy, being pretty groovy, naturally made each property an Object . So, when you attempt to use the Song class in normal Java, you are presented with a lot of getters and setters that all have Object as both a return type and parameter type.

Refining return types

Just for fun, open up the Groovy Song class and change the artist property to be of type String rather than typeless, like so:

package org.acme.groovyclass Song {def nameString artistdef genreString toString(){"${name}, ${artist}, ${getGenre()}"}def getGenre(){genre?.toUpperCase()}
}

Now, go back to your JUnit test, and tap the auto-completion shortcut on your Song instance — do you see what I see?

In Figure 20 (and hopefully in your own follow-along code) the setArtist() method takes a String rather than an Object . Once again, Groovy proves that it is Java under the hood; and thus applies the same rules.

Figure 20. Strings rather than objects

It's always plain old Java

Going back to writing the test, please also note that, by default, Groovy's compiled class properties are private, so you can't directly access them in Java. Instead, you have to use setters like the following:

@Test
public void testToString(){Song sng = new Song();sng.setArtist("Village People");sng.setName("Y.M.C.A");sng.setGenre("Disco");Assert.assertEquals("Y.M.C.A, Village People, DISCO", sng.toString());
}

Coding the remainder of this test case is trivial. What it nicely demonstrates is that anything you do in Groovy can be easily re-used in your Java programs. Don't forget that the opposite is also true. Everything you do and have written in the Java language is also available to you in Groovy.

结论

If there's one thing you take away from this tutorial (other than your first experiences of programming Groovy) it should be the deep understanding that Groovy is Java without a lot of the syntactical rules you're used to. Groovy is Java without types, without modifiers, without returns, without Iterator s, without importing collections. In short, Groovy is Java without a lot of the baggage that can weigh down your Java projects when you really need them to fly.

And yet, under the hood, Groovy is just Java.

I hope you've had fun on this first journey toward Groovy fluency. You've played around with Groovy's syntax, created a few classes that exercised its productivity-enhancing features, and seen how easy it is to test a Groovy class using Java. You've also encountered some of the pitfalls common to first-time Groovy developers, and seen how to work around them without creating too much of a mess.

While you probably don't consider yourself quite fluent in Groovy at this point, you've taken the first steps. You can use what you've learned so far as a basis for writing your own first Groovy programs — after all, you've got your dual Groovy-and-Java programming environment all set up! For an interesting exercise, try setting up your next round of automated builds with Gant , an Ant-based build tool that uses Groovy rather than XML to define the build. Once you're more comfortable with the language you can try building a Web application module using Groovy on Grails — which, incidentally, is the subject of my next tutorial.


翻译自: https://www.ibm.com/developerworks/java/tutorials/j-groovy/j-groovy.html

groovy_流利的Groovy相关推荐

  1. gradle groovy_适用于Java开发人员的Groovy吗? 认识Gradle,Grails和Spock

    gradle groovy Java开发人员最感兴趣的Groovy用例有哪些? 尽管已经有一段时间了,但似乎只有Groovy最近才开始使用Groove. 对于某些人来说,它基本上只是另一种深奥的JVM ...

  2. java 嵌入groovy_嵌入Groovy

    原文链接  译者: 李璟(jlee381344197@gmail.com) (本站正在翻译groovy系列文章,有兴趣同学可以加入我们) Groovy就其本身而言,在不同的场景下都算是一门非常不错的编 ...

  3. groovy lambda_Java Lambda流和Groovy Clouse的比较

    groovy lambda 这篇博客文章将研究List数据结构上的一些谚语操作,并对Java 8/9和Groovy语法进行一些比较. 因此,首先是数据结构. 这只是一个简单的橄榄球球员,具有名字和等级 ...

  4. Java Lambda流和Groovy Clouse的比较

    这篇博客文章将探讨List数据结构上的一些谚语操作,并对Java 8/9和Groovy语法进行一些比较. 因此,首先是数据结构. 这只是一个简单的橄榄球球员,有名字和等级. Java class Ru ...

  5. Idea groovy表生成实体类带注释

    Idea groovy表生成实体类带注释 1.点开datasourse,打开idea带的数据库工具,具体添加数据库连接,这里不描述. 这时点击会生成一个poji 这时生成的pojo中是不带中文注释的, ...

  6. groovy–流程控制

    在本篇文章中,我们将介绍逻辑分支,循环,以及如何从if-else以及try-catch代码块中返回值. if – else Groovy 支持Java传统的if-else语法: def x = fal ...

  7. groovy–运算符重载

    Groovy支持运算符重载,各种运算符被映射到普通的java对象的方法调用,这就使得开发者可以利用运算符重载的优势来编写自己的Java或者groovy对象. 下面的表格描述了groovy中的操作符所映 ...

  8. 便捷,轻巧的Groovy数据库操作

    本文主要介绍Groovy对数据的CRUD操作,熟悉groovy.sql包,测试使用的数据库是H2. 1.数据库连接配置 //数据库连接配置 def db = [url:'jdbc:h2:mem:gro ...

  9. ElasticSearch Groovy脚本远程代码执行漏洞

    什么是ElasticSearch? 它是一种分布式的.实时性的.由JAVA开发的搜索和分析引擎. 2014年,曾经被曝出过一个远程代码执行漏洞(CVE-2014-3120),漏洞出现在脚本查询模块,由 ...

最新文章

  1. word表格自动编号
  2. [BZOJ1724][Usaco2006 Nov]Fence Repair 切割木板
  3. CTFshow php特性 web93
  4. Java线程之核心概念
  5. (旧)子数涵数·Flash——遮罩动画
  6. ubuntu-基本命令篇-18-压缩包管理
  7. java分页数据导出excel
  8. win7 右键计算机 服务 设备管理器,win7系统计算机右键菜单添加设备管理器的操作方法...
  9. Raphael学习笔记(4)--绘图(路径【贝塞尔曲线】)
  10. 一步一步学做一个CPU——2,Logisim的简单入门
  11. 想让你的Mac桌面清爽整洁?试试Mac临时文件存储小助手Yoink
  12. 安装ie9提示未能完成安装_win10系统安装iE提示“internet Explorer未能完成安装”的方法介绍...
  13. 浩辰3D软件中装配零件的操作技巧
  14. 流利阅读12.28 Seriously, Prada, what were you thinking? Why the fashion industry keeps bumbling into rac
  15. Android OCR数字识别
  16. 英语口语七十五之[火锅大杂烩]
  17. 最全面的gtest的TEST宏源码解析及自动调度机制
  18. Postfix邮箱部署
  19. 多商户商城系统-v2.2.3版本发布
  20. Kali2022 系统语言怎么切换中文

热门文章

  1. mat1 and mat2 shapes cannot be multiplied (3584x7 and 512x4096)
  2. 蓝桥杯——测试次数·摔手机(2018JavaB组第4题,17分)
  3. C专家编程 第11章 你懂得C,所以C++不再话下 11.1 初识OOP
  4. .Net程序员学用Oracle系列(9):系统函数(上)
  5. 【表格设置】HTML中合并单元格,对列组合应用样式,适应各浏览器的内容换行
  6. 基于java的圆通快递单号自动识别api接口代码实例
  7. netty权威指南笔记-以回车换行结尾的消息如何处理半包问题
  8. SQLSTATE[HY000]: General error: 1366 Incorrect string value: ‘\xF0\x9F\x98\x84‘ for column ‘content‘
  9. P68-70 王者荣耀
  10. python读书笔记—读写文件