Groovy 学习手册(2)
二. 工具
1. 控制台
groovyConsole:
Groovy 控制台是一个非常易于使用和简单的轻量级的编辑器。你可以在里面做很多事情。
在编辑器里面可以书写代码,Windows 下,按下Ctrl + R
来运行代码,清除工作台的输出信息使用Ctrl + W
快捷键。
2. 编译
groovyc:
可以借助 Java 7 的动态调用设计的优势,可以使用--indy
标识符。这个在 Groovy 命令行下也同样适用。
动态调用可以帮助编译器提高性能,例如鸭子类型,元编程,方法缺失调用等。
3. Shell
groovysh:
在不需要交互的 shell 命令行下可以使用 groovysh 来执行 Groovy 代码。
4. 文档
groovydoc:
使用此命令可以从代码中生成文档。Groovy 里的代码的注释与 Java 是一样一样的。
/** This is a documentation comment. */
/* This is not */
// This is a one-line comment.
三. GDK
GDK(Groovy Development Kit ) 提供了很多适用和方便的方法,操作符,实用类还有其他的一些帮助类。
有些方法可以用在任何 Java 类中,例如each
, 还有更多。
1. 集合
Groovy 提供了很多方便快捷的方法来操作集合。
- sort —— 为集合排序
- findAll —— 根据匹配的闭包条件,查找所有的元素
- collect —— 一个遍历器,用来生成一个新的集合
- inject —— 遍历循环所有元素,但最后返回一个值
- each —— 根据给定的闭包条件遍历循环所有元素
- eachWithIndex —— 根据值和对应的索引来遍历循环所有的元素
- findIndexOf —— 根据核定的闭包条件返回第一个匹配的元素的索引
- any—— 如果匹配了闭包条件则返回 true
- every —— 如果匹配了闭包条件则返回 true
- first —— 获取 List 的第一个元素
- last —— 获取 List 的最后一个元素
- tail —— 返回 List 里面除了第一个元素意外剩下所有的元素
2.“*”操作符
“*”操作符可以用来访问集合里面所有元素的属性。在很多情况下,可以与collect
方法替换使用。
例如你想打印在变量名为dragons的集合里面每个对象的 name 的值,可以使用
dragons*.name.each { println it }
3. GPath
在 GPath 里面, GPath很多地方类似于XPath。List 和 Map 都支持属性标记,Groovy 提供了语法糖来非常容易地处理集合。请看下面的代码:
def listOfMaps = [['a': 11, 'b': 12], ['a': 21, 'b': 22]]
assert listOfMaps.a == [11, 21] //GPath notation
assert listOfMaps*.a == [11, 21] //spread dot notation
listOfMaps = [['a': 11, 'b': 12], ['a': 21, 'b': 22], null]
assert listOfMaps*.a == [11, 21, null] // caters for null values
assert listOfMaps*.a == listOfMaps.collect { it?.a } //equivalent notation
// But this will only collect non-null values
assert listOfMaps.a == [11,21]
4. IO
GDK 对 IO操作做了很多工作。
(1).Files
GDK 增加了很多方法用来非常便利地进行读写。
println path.toFile().text
在File 类中增加了 getText()
方法,非常简洁地读取整个文件。
new File("books.txt").text = "Modern Java"
使用 File 类中新增的setText()
方法,用来对文件进行写操作。关于二进制文件,可以使用bytes
属性。
byte[] data = new File('data').bytes
new File('out').bytes = data
如果你用InputStream 和 Reader 读取类,或者使用OutputStream 和Writer 写入类,还有如下方法:
new File('dragons.txt').withInputStream {in -> }
new File('dragons.txt').withReader {r -> }
new File('dragons.txt').withOutputStream {out ->}
new File('dragons.txt').withWriter {w -> }
最后,你可以使用eachLine
方法来读取文件的一行,例如:
new File('dragons.txt').eachLine { line->
println "$line"
}
//OR
new File('dragons.txt').eachLine { line, num ->
println "Line $num: $line"
}
在所有的情况中,即使出现异常,Grovvy 都能关闭 IO资源。
(2). URLs
GDK 提供了一个超级简单的方式来访问 URL。
下面的例子,是用 Java 代码来打开 Http 连接,从谷歌地址上读取数据并存放在 btye 数组中,然后打印所有的内容:
URL url = new URL("http://google.com");
InputStream input = (InputStream) url.getContent();
ByteArrayOutputStream out = new ByteArrayOutputStream();
int n = 0;
byte[] arr = new byte[1024];
while (-1 != (n = input.read(arr)))
out.write(arr, 0, n);
System.out.println(new String(out.toByteArray()));
然而,上面的代码用 Groovy 一句话就能搞定!!
println "http://google.com".toURL().text
(3.)Range
Range是 Groovy 内置类型。它可以被用在循环,switch 语句,抽取子字符串等。Range 的语法为start .. end
。
Range 用在each
方法和循环中非常便利:
(1..4).each {print it} //1234
for (i in 1..4) print i //1234
在 switch 语句中:
case 12..30: // Range 12 to 30
Tip
在 switch 语句中 Range 里的数据类型必须一致。
你还可以使用 Range 的 getAt
方法从字符串中截取子字符串:
def text = 'learning groovy'
println text[0..4] //learn
println text[0..4,8..-1] //learn groovy
Tip
-1表示集合或是字符串里最后一个元素。
你甚至可以在集合中使用 Range。
def list = ['hank', 'john', 'fred']
println list[0..1] //[hank, john]
你可以使用 “..<” 操作符定义 Range 的最后元素的开区间。
(1..<5).each {print it} //1234
(4.) 实用工具类
ConfigSlurper实用类用来读取配置信息,它是一种 Groovy 脚本。像 Java 中的*.properties的文件,可以使用“.”导航符进行访问,它也可以应用在闭包的配置的值和任何对象类型中。
def config = new ConfigSlurper().parse('''
app.date = new Date()
app.age = 42
app {
name = "Test${42}"
}
''')
def properties = config.toProperties()
assert properties."app.date" instanceof String
assert properties."app.age" == '42'
assert properties."app.name" == 'Test42'
Expando工具类用来创建动态扩展对象。你可以为对象添加属性和方法,在动态元编程中此类非常实用。例如:
def expando = new Expando()
expando.name = { -> 'Draco' }
expando.say = { String s -> "${expando.name} says: ${s}" }
expando.say('hello') // Draco says: hello
ObservableList/Map/Set
Groovy 提供了可供观察的 List,Map和 Set。当这些集合在新增,删除,修改元素时会触发PropertyChangeEvent( java.beans package)事件。需要注意的是,这个事件不仅会触发,它还持有属性的名字以及属性的新旧值。
例如,下面的例子使用ObservableList来打印所有触发的事件类。
def list = new ObservableList()
def printer = {e -> println e.class}
list.addPropertyChangeListener(printer)
list.add 'Harry Potter'
list.add 'Hermione Granger'
list.remove(0)
println list
// 打印结果为:
class groovy.util.ObservableList$ElementAddedEvent
class java.beans.PropertyChangeEvent
class groovy.util.ObservableList$ElementAddedEvent
class java.beans.PropertyChangeEvent
class groovy.util.ObservableList$ElementRemovedEvent
class java.beans.PropertyChangeEvent
[Hermione Granger]
四. 源于 Java
1. 静态方法默认值
Groovy 为方法参数提供了默认值,例如,下面的代码fly 方法有个名为 text 的参数
def fly(String text = "flying") {println text}
从 Java 的角度来看这需要创建两个重载的方法:
def fly() {println "flying"}
def fly(String text) {println text}
这个方法只要不与现存的方法冲突,可以设置任意长度的参数。
2. Equals, Hashcode , 更多方法
在 Java 中一项比较繁琐的操作就是提供 equal,hashcode 等方法。为了解决这个问题,Groovy 提供了 @EqualsAndHashCode 注解。只要放在类定义的上面,万事大吉了!
除此之外,我们通常根据属性来创建不同的构造方法,为此,Groovy 提供了 @TupleConstructor 注解。此注解非常容易第根据你属性的定义来定义构造方法。注意,此注解要放在定义类关键字 class 的前面。
当然,还有 @ToString 注解,用在放在 toString() 上。
当然,如果你想实现上面所有的功能,只需要一个 @Canonical 注解就全部搞定。
import groovy.transform.*
@Canonical class Dragon {def name}
println new Dragon("Smaug")
// prints: Dragon(Smaug)
assert new Dragon("").equals(new Dragon(""))
3. 正则表达式
在 Groovy 中使用了非常简单的方式来匹配正则表达式。在 Java 中你必须使用 java.util.regex.Pattern 类,在 Groovy 中只是一行就能搞定。
按照规范你必须使用斜杠来包围正则表达式。这样才允许你使用一些特殊的正则语法,从而免去了使用两个反斜线的痛苦写法。例如:
def isEmail = email ==∼ /[\w.]+@[\w.]+/
它相当于如下的 Java 代码:
Pattern patt = Pattern.compile("[\\w.]+@[\\w.]+");
boolean isEmail = patt.matches(email);
还可以只用操作符创建一个新的 Matcher类:
def email = 'mailto:adam@email.com'
def mr = email =∼ /[\w.]+@[\w.]+/
if (mr.find()) println mr.group()
这允许你在字符串内部使用正则表达式,并且从一个表达式中得到一个子组。
4. 缺失的Java语法
由于Groovy的独特的语法以及多年来Java一直增加新的东西,所以看起来Groovy缺失了一些功能。然而,我们可以通过其他方式来做这些相同的功能。例如,对于数组,对于 Groovy 来说是一个很困难的问题,因为Java创建数组的语法,数组里的值不会被编译,例如,下面的代码在Groovy里是报错的:
String[] array = new String[] {"foo", "bar"};
而应该使用这样的语法:
String[] array = ['foo', 'bar'].toArray()
还有,在很长时间内 for (Type item : list) 这种循环是不支持的。但是你有两种替代方案,一是使用 “in” 关键字;二 是使用 each 方法。
// for (def item : list)
for (item in list) doStuff(item)
list.each { item -> doStuff(item) }
5. 语句末尾“;”可选
如果你以前用过 Java 的话,在 Groovy 中因为分号是可选的,可能会引起语句结束的疑惑问题。通常这不是问题,但是在一行中调用多个方法的话,可能会产生问题。这种情况下,你需要在每行代码结束后使用非结束的操作符,例如“.”, 看例子:
class Pie {
def bake() { this }
def make() { this }
def eat() { this }
}
def pie = new Pie().
make().
bake().
eat()
如果你使用典型的Java语法的话,在Groovy里会引起编译错误:
def pie = new Pie() //Groovy interprets end of line
.make() // huh? what is this?
6. 泛型去哪里了?
Groovy 默认支持泛型,但并不是强制的。出于此原因,你可能在
Groovy 中很少会看到泛型的使用,例如,下面的代码在 Groovy 中是没有问题的。
List<Integer> nums = [1, 2, 3.1415, 'pie']
但是,如果想在 Groovy 中强制使用泛型的话,需要在类或方法前加上对应的注解 @CompileStatic 或 @TypeChecked。例如:
import groovy.transform.*
@CompileStatic
class Foo {
List<Integer> nums = [1, 2, 3.1415] //error
}
这样,就会引起编译错误:Incompatible generic argument types. Cannot assign java.util.List <java.lang.Number> to: java.util.List 。因为3.1415中Groovy里是 BigDecimal 类型的,而 List 要求泛型的类型为 Number 类型。
7. Groovy 的数字
这里涉及的是十进制数字,在 Groovy 里默认为 BigDecimal 类型的。这样,你在做数学运算时省去了四舍五入的问题。
如果你想使用 float 和 double 类型,只需要在数字后面加上 f 或 d 就可以了。
def pie = 3.141592d
8. Boolean的解决方案
因为 Groovy 只是跟 Java 很相像,但并不是 Java,所有有时候会有些疑惑。其中一个就是 Boolean 的问题。
在 Boolean 的使用上,Groovy 更加自由。例如,下面的代码都可以表示 Boolean 类型为 true 的情况。
if ("foo") println("true")
if (!"") println("true")
if (42) println("true")
if (! 0) println("true")
9. Map的语法
Groovy 的语法糖可以直接在 Map 中使用字符串作为 key,这通常用起来非常方便。但是如果使用 Groovy 的属性访问语法糖时,但
Map中 元素的 key 是一个对象类型时,会导致迷惑不清。所以你需要直接使用 getClass() 方法。
除此而外,如果你使用变量作为 key 的话,也会出现类似的问题。这时你需要用括号把 key 括起来。例如:
1 def foo = 1
2 def bar = 2
3 def map = [(foo): bar]
如果变量 foo 不括起来的的话,就会变成了foo这个字符串,而不是数字1了。
Groovy 学习手册(2)的更多相关文章
- Groovy 学习手册(7)
10. Groovy GPars GPars 一开始在 Groovy 中作为一个单独的项目,同时带来了很多并发的机制.它包含了很多并行的map/redue,Actors,以及其他很多并发的模块. 1. ...
- Groovy 学习手册(6)
9. 不可变特性 不可变特性和函数式编程在一起就像是花生酱和果酱在一起一样.虽然没有必要非要在一起使用,但他们相处得很好. 在纯正的函数式语言中,每个函数对本身之外没有影响,即没有副作用.这意味着每次 ...
- Groovy 学习手册(5)
8. 函数式编程 函数式编程(FP)是一种编程风格,侧重于函数和最小化状态的变化(使用不可变的数据结构).它更接近于用数学来表达解决方案,而不是循序渐进的操作. 在函数式编程里,其功能应该是" ...
- Groovy 学习手册(4)
6. 领域特定语言 Groovy 有许多特性,使它非常适合写DSL(领域特定语言).这些特性包活: 具有委托机制的闭包: 点号(.)和语句末尾的分号(;)是可选的: 运算符的重载(例如,加号,减号等) ...
- Groovy 学习手册(3)
五. Groovy 的设计模式 设计模式是一种非常好的方式,可以使你的代码变得实用,可读又具有扩展性.跟 Java 相比,在 Groovy 里使用设计模式使代码更加简洁和容易. 1. 策略模式 设想一 ...
- Groovy 学习手册(1)
1. 需要安装的软件 Java / Groovy 对应 Java 和 Groovy,你需要安装以下软件: Java JDK,例如 JDK 8 IDE,例如 Eclipse,NetBeans 8 Gro ...
- Kotlin强化实战!这份学习手册让你的面试稳如泰山
一.引言 正如官网的slogan所描述:kotlin,是一门让程序员写代码时更有幸福的现代语言. 同时,也正如维基百科里介绍: JetBrains公司希望Kotlin能够推动IntelliJ IDEA ...
- Redis学习手册(目录)
为什么自己当初要选择Redis作为数据存储解决方案中的一员呢?现在能想到的原因主要有三.其一,Redis不仅性能高效,而且完全免费.其二,是基于C/C++开发的服务器,这里应该有一定的感情因素吧.最后 ...
- git学习手册
#git学习手册 git: Git是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常大的项目版本管理.[2] Git 是 Linus Torvalds 为了帮助管理 Linux内核开发而 ...
随机推荐
- android中RecyclerView控件实现点击事件
RecyclerView控件实现点击事件跟ListView控件不同,并没有提供类似setOnItemClickListener()这样的注册监听器方法,而是需要自己给子项具体的注册点击事件. 本文的例 ...
- SQL Server 之 附加数据库出现“ 拒绝访问 ”
错误信息如下图所示,附加数据库时出现“拒绝访问”: 解决方案: 修改拒绝访问的文件的安全权限,这里是修改数据库的.mdf文件的安全权限.
- 再谈IE的浏览器模式和文档模式[转]
http://www.cnblogs.com/liuzhendong/archive/2012/04/27/2474363.html 以前在 “IE8兼容视图(IE7 mode)与独立IE7的区别”一 ...
- 超具体Windows版本号编译执行React Native官方实例UIExplorer项目(多图慎入)
),React Native技术交流4群(458982758).请不要反复加群! 欢迎各位大牛,React Native技术爱好者加入交流!同一时候博客右側欢迎微信扫描关注订阅号,移动技术干货,精彩文 ...
- Atlas系列一:Atlas功能特点FAQ
1:Atlas是否支持多字符集? 支持,可以在test.cnf中指定. #默认字符集,设置该项后客户端不再需要执行SET NAMES语句charset = utf8 2:Atlas是否支持事物操作? ...
- 【基础练习】【拓扑排序】codevs3294 车站分级题解
题目来源:NOIP2013 普及第四题 题目描写叙述 Description 一条单向的铁路线上,依次有编号为1, 2, -, n的n个火车站.每一个火车站都有一个级别,最低为1级.现有若干趟车次在这 ...
- V-rep学习笔记:并联机构正逆运动学
Solving the FK problem of simple kinematic chains is trivial (just apply the desired joint values to ...
- 如何实现两台Domino之间的相互访问
一)交叉验证 1启动Administrator软件,连接到您的服务器,点击"配置"标签. 2点击右边屏幕"工具"--"验证字"--"交叉验证" 3选择您自己的cert.id,输入其口 ...
- 浅谈Spring的PropertyPlaceholderConfigurer
大型项目中,我们往往会对我们的系统的配置信息进行统一管理,一般做法是将配置信息配置与一个cfg.properties的文件中,然后在我们系统初始化的时候,系统自动读取cfg.properties配置文 ...
- GDALBuildVRT异构波段的支持
目录 简述 修改源码 1.修改DatasetProperty结构体 2.修改VRTBuilder::AnalyseRaster函数 3.修改VRTBuilder::CreateVRTNonSepara ...