Groovy脚本基础全攻略

1 背景

Groovy脚本基于Java且拓展了Java,因此从某种程度来讲掌握Java是学习Groovy的前提,故本文适用于不熟悉Groovy却想快速获得Groovy核心基础干货的Java开发者(注意是Java),由于个人目的不是深刻学习Groovy语言,因此本文基本都是靠代码来解释,这样最直观,同时也够干货基础入门Groovy的特色和结构。javascript

开始介绍前先给一个大法,《官方权威指南》英文好的能够直接略过本文后续内容,我须要的只是Groovy皮毛;再次向Groovy的标志致敬,左手一个Java,右手一个Groovy,很差意思,我技术水平太Low了(T–T__《琅琊榜》看多了!!!)。html

Groovy是一种动态语言,它和Java相似(算是Java的升级版,可是又具有脚本语言的特色),都在Java虚拟机中运行。当运行Groovy脚本时它会先被编译成Java类字节码,而后经过JVM虚拟机执行这个Java字节码类。java

快速安装指南:git

安装Groovy在各类Bash下都是通用的,具体以下命令就可搞定:github

$ curl -s get.sdkman.io | bash $ source "$HOME/.sdkman/bin/sdkman-init.sh" $ sdk install groovy $ groovy -version //至此就能够享用了!

咱们在写Groovy代码时能够直接使用本身喜欢的文本编辑器编辑OK之后以.groovy后缀保存,而后在终端执行以下命令便可运行:正则表达式

$ groovy ./TestFile.groovy

或者咱们能够经过groovyConsole来进行groovy代码开发运行(因为不须要特别深刻学习使用Groovy,因此我的很是喜欢这种模式的开发运行),以下图:编程

这里写图片描述

再或者咱们还可使用Intellij IDEA等工具安装groovy插件进行groovy开发,这里再也不一一叙述了(配置环境点我),直接给出一个读取指定文件内容打印的例子,以下:数组

这里写图片描述

OK,有了上面这些简单粗暴的基础和环境以后那咱们快速开战吧。安全

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流ruby

2 语法基础

这里开始咱们就来快速简单粗暴的了解一下Groovy语法,其实和Java相似,但也有些区别,下面咱们一步一步来看吧,切记对比学习,这才是秘笈。

2-1 注释

Groovy的单行注释、多行注释、文档注释基本都和Java同样,没啥特殊的,再也不细说。只有一种特殊的单行注释须要留意一下便可。以下:

#!/usr/bin/env groovy println "Hello from the shebang line"

这种注释一般是用来给UNIX系统声明容许脚本运行的类型的,通常都是固定写法,没啥讲究的。

2-2 关键字

Groovy有以下一些关键字,咱们些代码命名时要注意:

as、assert、break、case、catch、class、const、continue、def、default、do、else、enum、extends、false、finally、for、goto、if、implements、import、in、instanceof、interface、new、null、package、return、super、switch、this、throw、throws、trait、true、try、while

这玩意和其余语言同样,没啥特殊的,自行脑补。

2-3 标识符

对于Groovy的标示符和Java仍是有些共同点和区别的,特别是引用标示符的区别,具体能够往下看。

2-3-1 普通标识符

普通标识符定义和C语言相似,只能以字母、美圆符、下划线开始,不能以数字开头。以下例子:

//正确 def name def $name def name_type def foo.assert //错误 def 5type def a+b

2-3-2 引用标识符

引用标识符出如今点后的表达式中,咱们能够以下同样使用:

def map = [:] //引用标示符中出现空格也是对的 map."an identifier with a space and double quotes" = "ALLOWED" //引用标示符中出现横线也是对的 map.'with-dash-signs-and-single-quotes' = "ALLOWED" assert map."an identifier with a space and double quotes" == "ALLOWED" assert map.'with-dash-signs-and-single-quotes' == "ALLOWED"

固然了,Groovy的全部字符串均可以看成引用标示符定义,以下:

//以下类型字符串做为引用标识符都是对的 map.'single quote' map."double quote" map.'''triple single quote''' map."""triple double quote""" map./slashy string/ map.$/dollar slashy string/$ //稍微特殊的GString,也是对的 def firstname = "Homer" map."Simson-${firstname}" = "Homer Simson" assert map.'Simson-Homer' == "Homer Simson"

2-4 字符及字符串

Groovy有java.lang.String和groovy.lang.GString两中字符串对象类型,具体以下细说。

2-4-1 单引号字符串

单引号字符串是java.lang.String类型的,不支持站位符插值操做,譬如:

def name = 'Test Groovy!' def body = 'Test $name' assert name == 'Test Groovy!' assert body == 'Test $name' //不会替换$name站位符

Groovy的字符串能够经过”+“直接拼接,譬如:

assert 'ab' == 'a' + 'b'

其中涉及转义字符规则同Java,只用特殊注意”’“的转义便可。

2-4-2 三重单引号字符串

三重单引号字符串是java.lang.String类型的,不支持站位符插值操做,能够标示多行字符串,譬如:

def aMultilineString = '''line one line two line three'''

三重单引号字符串容许字符串的内容在多行出现,新的行被转换为“\n”,其余全部的空白字符都被完整的按照文本原样保留;字符开头添加“/”表示字符内容不转义反斜杠“\”,只有在反斜杠接下来是一个字符u的时候才须要进行转义,由于\u表示一个unicode转义。以下:

def strippedFirstNewline = '''\ line one line two line three ''' assert !strippedFirstNewline.startsWith('\n')

2-4-3 双引号字符串

双引号字符串支持站位插值操做,若是双引号字符串中不包含站位符则是java.lang.String类型的,若是双引号字符串中包含站位符则是groovy.lang.GString类型的。

对于插值占位符咱们能够用${}或者$来标示,${}用于通常替代字串或者表达式,$主要用于A.B的形式中,具体以下例子:

def name = 'Guillaume' // a plain string def greeting = "Hello ${name}" assert greeting.toString() == 'Hello Guillaume' def sum = "The sum of 2 and 3 equals ${2 + 3}" assert sum.toString() == 'The sum of 2 and 3 equals 5' def person = [name: 'Guillaume', age: 36] assert "$person.name is $person.age years old" == 'Guillaume is 36 years old'

特别注意,$只对A.B等有效,若是表达式包含括号(像方法调用)、大括号、闭包等符号则是无效的。譬如:

def number = 3.14 shouldFail(MissingPropertyException) { println "$number.toString()" }  //该代码运行抛出groovy.lang.MissingPropertyException异常,由于Groovy认为去寻找number的名为toString的属性,因此异常

注意,在表达式中访问属性前必须保证属性已经定义好(值为空也能够),若是使用了未定义的属性会抛出groovy.lang.MissingPropertyException异常。 GString还支持延迟运算,譬如在GString中使用闭包,闭包在调用GString的toString()方法时被延迟执行;闭包中能够有0或1个参数,若指定一个参数,则参数会被传入一个Writer对象,咱们能够利用这个Writer对象来写入字符,若没有参数,闭包返回值的toString()方法被调用。譬如:

//无参数闭包 def sParameterLessClosure = "1 + 2 == ${-> 3}" assert sParameterLessClosure == '1 + 2 == 3' //一个参数闭包 def sOneParamClosure = "1 + 2 == ${ w -> w << 3}" assert sOneParamClosure == '1 + 2 == 3'

上面了解了GString的推迟运算特性,下面咱们再来看一个牛逼的特性,以下:

def number = 1 def eagerGString = "value == ${number}" def lazyGString = "value == ${ -> number }" assert eagerGString == "value == 1" assert lazyGString == "value == 1" number = 2 assert eagerGString == "value == 1" assert lazyGString == "value == 2" 

能够看见,eagerGString是普通的双引号插值站位替换,lazyGString是双引号闭包插值替换,咱们能够发如今number变为2之后他们的运算结果就有了差别。能够明显推理到结论,一个普通插值表达式值替换实际是在GString建立的时刻,一个包含闭包的表达式因为延迟运算调运toString()方法,因此会产生一个新的字符串值。

固然了,GString和String即便字符串同样他们的HashCode也不会同样,譬如:

assert "one: ${1}".hashCode() != "one: 1".hashCode()

因为相同字符串的String与GString的HashCode不一样,因此咱们必定要避免使用GString做为MAP的key,譬如:

def key = "a" def m = ["${key}": "letter ${key}"] assert m["a"] == null //因为key的HashCode不一样,因此取不到

其中涉及转义字符规则同Java,只用特殊注意””“的转义便可。

2-4-4 多重双引号字符串

多重双引号字符串也支持站位插值操做,咱们要特别注意在多重双引号字符串中的单引号和双引号转换问题。譬如:

def name = 'Groovy' def template = """ Dear Mr ${name}, You're the winner of the lottery! Yours sincerly, Dave """ assert template.toString().contains('Groovy')

2-4-5 斜线字符串

斜线字符串其实和双引号字符串很相似,一般用在正则表达式中,下面咱们看几个例子,以下:

//普通使用
def fooPattern = /.*foo.*/
assert fooPattern == '.*foo.*' //含转义字符使用 def escapeSlash = /The character \/ is a forward slash/ assert escapeSlash == 'The character / is a forward slash' //多行支持 def multilineSlashy = /one two three/ assert multilineSlashy.contains('\n') //含站位符使用支持 def color = 'blue' def interpolatedSlashy = /a ${color} car/ assert interpolatedSlashy == 'a blue car'

特别注意,一个空的斜线字符串会被Groovy解析器解析为一注释。

2-4-6 字符Characters

不像Java,Groovy没有明确的Characters。可是咱们能够有以下三种不一样的方式来将字符串做为字符处理,譬如:

char c1 = 'A' assert c1 instanceof Character def c2 = 'B' as char assert c2 instanceof Character def c3 = (char)'C' assert c3 instanceof Character

2-5 数字Numbers

Groovy支持各类类型的整型和数值类型,一般支持Java支持的那些,下面咱们仔细来讲说。

2-5-1 整型

Groovy像Java同样支持以下一些整型,byte、char、short、int、long、java.lang.BigInteger。咱们在使用中能够像下面例子同样:

// primitive types byte b = 1 char c = 2 short s = 3 int i = 4 long l = 5 // infinite precision BigInteger bi = 6 int xInt = 077 assert xInt == 63 int xInt = 0x77 assert xInt == 119 int xInt = 0b10101111 assert xInt == 175

2-5-2 浮点型

Groovy像Java同样支持以下一些浮点型,float、double、java.lang.BigDecimal。咱们在使用中能够像下面例子同样:

// primitive types float f = 1.234 double d = 2.345 // infinite precision BigDecimal bd = 3.456 assert 1e3 == 1_000.0 assert 2E4 == 20_000.0 assert 3e+1 == 30.0 assert 4E-2 == 0.04

2-6 Booleans类型

Boolean类型没啥解释的,和其余语言同样,就两个值,以下:

def myBooleanVariable = true boolean untypedBooleanVar = false booleanField = true

比较简单,没啥特例,自行脑补。

2-7 Lists类型

Groovy一样支持java.util.List类型,在Groovy中一样容许向列表中增长或者删除对象,容许在运行时改变列表的大小,保存在列表中的对象不受类型的限制;此外还能够经过超出列表范围的数来索引列表。以下例子:

//使用动态List def numbers = [1, 2, 3] assert numbers instanceof List assert numbers.size() == 3 //List中存储任意类型 def heterogeneous = [1, "a", true] //判断List默认类型 def arrayList = [1, 2, 3] assert arrayList instanceof java.util.ArrayList //使用as强转类型 def linkedList = [2, 3, 4] as LinkedList assert linkedList instanceof java.util.LinkedList //定义指定类型List LinkedList otherLinked = [3, 4, 5] assert otherLinked instanceof java.util.LinkedList //定义List使用 def letters = ['a', 'b', 'c', 'd'] //判断item值 assert letters[0] == 'a' assert letters[1] == 'b' //负数下标则从右向左index assert letters[-1] == 'd' assert letters[-2] == 'c' //指定item赋值判断 letters[2] = 'C' assert letters[2] == 'C' //给List追加item letters << 'e' assert letters[ 4] == 'e' assert letters[-1] == 'e' //获取一段List子集 assert letters[1, 3] == ['b', 'd'] assert letters[2..4] == ['C', 'd', 'e'] //多维List支持 def multi = [[0, 1], [2, 3]] assert multi[1][0] == 2 

2-8 Arrays类型

Groovy中数组和Java相似,具体以下:

//定义初始化String数组 String[] arrStr = ['Ananas', 'Banana', 'Kiwi'] assert arrStr instanceof String[] assert !(arrStr instanceof List) //使用def定义初始化int数组 def numArr = [1, 2, 3] as int[] assert numArr instanceof int[] assert numArr.size() == 3 //声明定义多维数组指明宽度 def matrix3 = new Integer[3][3] assert matrix3.size() == 3 //声明多维数组不指定宽度 Integer[][] matrix2 matrix2 = [[1, 2], [3, 4]] assert matrix2 instanceof Integer[][] //数组的元素使用及赋值操做 String[] names = ['Cédric', 'Guillaume', 'Jochen', 'Paul'] assert names[0] == 'Cédric' names[2] = 'Blackdrag' assert names[2] == 'Blackdrag'

2-9 Maps类型

Map是“键-值”对的集合,在Groovy中键key不必定是String,能够是任何对象(实际上Groovy中的Map就是java.util.Linke dHashMap)。以下:

//定义一个Map def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF'] //获取一些指定key的value进行判断操做 assert colors['red'] == '#FF0000' assert colors.green == '#00FF00' //给指定key的对赋值value操做与判断 colors['pink'] = '#FF00FF' colors.yellow = '#FFFF00' assert colors.pink == '#FF00FF' assert colors['yellow'] == '#FFFF00' //判断Map的类型 assert colors instanceof java.util.LinkedHashMap //访问Map中不存在的key为null assert colors.unknown == null //定义key类型为数字的Map def numbers = [1: 'one', 2: 'two'] assert numbers[1] == 'one'

对于Map须要特别注意一种状况,以下:

//把一个定义的变量做为Map的key,访问Map的该key是失败的 def key = 'name' def person = [key: 'Guillaume'] assert !person.containsKey('name') assert person.containsKey('key') //把一个定义的变量做为Map的key的正确写法---添加括弧,访问Map的该key是成功的 person = [(key): 'Guillaume'] assert person.containsKey('name') assert !person.containsKey('key') 

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

3 运算符

关于Groovy的运算符介绍相似于上面同样,咱们重点突出与Java的不一样点,相同点自行脑补。

Groovy支持**次方运算符,以下:

assert 2 ** 3 == 8 def f = 3 f **= 2 assert f == 9

Groovy非运算符以下:

assert (!true) == false assert (!'foo') == false assert (!'') == true

Groovy支持?.安全占位符,这个运算符主要用于避免空指针异常,譬如:

def person = Person.find { it.id == 123 } def name = person?.name assert name == null 

Groovy支持.@直接域访问操做符,由于Groovy自动支持属性getter方法,但有时候咱们有一个本身写的特殊getter方法,当不想调用这个特殊的getter方法则能够用直接域访问操做符。以下:

class User {
    public final String name User(String name) { this.name = name} String getName() { "Name: $name" } } def user = new User('Bob') assert user.name == 'Name: Bob' assert user.@name == 'Bob' 

Groovy支持.&方法指针操做符,由于闭包能够被做为一个方法的参数,若是想让一个方法做为另外一个方法的参数则能够将一个方法当成一个闭包做为另外一个方法的参数。以下:

def list = ['a','b','c'] //常规写法 list.each{ println it } String printName(name){ println name } //方法指针操做符写法 list.each(this.&printName) 

Groovy支持将?:三目运算符简化为二目,以下:

displayName = user.name ? user.name : 'Anonymous' displayName = user.name ?: 'Anonymous' 
  • 1
  • 2
  • 1
  • 2

Groovy支持*.展开运算符,一个集合使用展开运算符能够获得一个元素为原集合各个元素执行后面指定方法所得值的集合,以下:

cars = [
   new Car(make: 'Peugeot', model: '508'), null, new Car(make: 'Renault', model: 'Clio')] assert cars*.make == ['Peugeot', null, 'Renault'] assert null*.make == null 

关于Groovy的其余运算符就很少说,类比Java吧。

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

4 程序结构

这里主要讨论Groovy的代码组成结构,具体以下细则。

4-1 包名

包名的定义和做用及含义彻底和Java同样,再也不介绍,以下:

// defining a package named com.yoursite package com.yoursite

4-2 Imports引入

常规的imports导包操做和Java同样,以下:

//例1: import groovy.xml.MarkupBuilder // using the imported class to create an object def xml = new MarkupBuilder() assert xml != null //例2: import groovy.xml.* def markupBuilder = new MarkupBuilder() assert markupBuilder != null assert new StreamingMarkupBuilder() != null //例3: import static Boolean.FALSE assert !FALSE //例4:特殊的,至关于用as取别名 import static Calendar.getInstance as now assert now().class == Calendar.getInstance().class

不过要特别注意,Groovy与Java相似,已经帮咱们默认导入了一些经常使用的包,因此在咱们使用这些包的类时就不用再像上面那样导入了,以下是自动导入的包列表:

import java.lang.* import java.util.* import java.io.* import java.net.* import groovy.lang.* import groovy.util.* import java.math.BigInteger import java.math.BigDecimal

4-3 脚本与类(脚本的实质)

相对于传统的Java类,一个包含main方法的Groovy类能够以下书写:

class Main { static void main(String... args) { println 'Groovy world!' } }

和Java同样,程序会从这个类的main方法开始执行,这是Groovy代码的一种写法,实际上执行Groovy代码彻底能够不须要类或main方法,因此更简单的写法以下:

println 'Groovy world!'

上面这两中写法实际上是同样的,具体咱们能够经过以下命令进行编译为class文件:

groovyc demo.groovy //编译Groovy源码为class

咱们使用反编译工具能够查看到这个demo.groovy类源码以下:

import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script { def run() { println 'Groovy world!' } static void main(String[] args) { InvokerHelper.runScript(Main, args) } }

能够看见,上面咱们写的groovy文件编译后的class实际上是Java类,该类从Script类派生而来(查阅API);能够发现,每一个脚本都会生成一个static main方法,咱们执行groovy脚本的实质实际上是执行的这个Java类的main方法,脚本源码里全部代码都被放到了run方法中,脚本中定义的方法(该例暂无)都会被定义在Main类中。

经过上面能够发现,Groovy的实质就是Java的class,也就是说他必定会和Java同样存在变量做用域!对哦,前面咱们解释变量时居然没说到这个东东,这里说下吧。看下面例子:

//单个Groovy源码文件,运行会报错找不到num变量 def num = 1 def printNum(){ println num }  //单个Groovy源码文件,运行会报错找不到num变量 int num = 1 def printNum(){ println num }  //单个Groovy源码文件,运行OK成功 num = 1 def printNum(){ println num } 

上面的例子能够发现,咱们若是想要在Groovy的方法中使用Groovy的变量则不能有修饰符。然而,若是咱们想在B.groovy文件访问A.groovy文件的num变量咋办呢,咱们可使用Field注解,具体操做以下:

import groovy.transform.Field; @Field num = 1
  • 1
  • 2
  • 1
  • 2

哈哈,这就是Groovy的变量做用域了,若是你想知道上面这些写法为啥出错,很简单,本身动手整成Java源码相信你必定能够看懂为啥鸟。

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

5 闭包

Groovy的闭包(closure)是一个很是重要的概念,闭包是能够用做方法参数的代码块,Groovy的闭包更象是一个代码块或者方法指针,代码在某处被定义而后在其后的调用处执行。

5-1 语法

定义一个闭包:

{ [closureParameters -> ] statements }

//[closureparameters -> ]是可选的逗号分隔的参数列表,参数相似于方法的参数列表,这些参数能够是类型化或非类型化的。

以下给出几个有效的闭包定义例子:

//最基本的闭包
{ item++ }  //使用->将参数与代码分离 { -> item++ }  //使用隐含参数it(后面有介绍) { println it }  //使用明确的参数it替代 { it -> println it }  //使用显示的名为参数 { name -> println name }  //接受两个参数的闭包 { String x, int y -> println "hey ${x} the value is ${y}" } //包含一个参数多个语句的闭包 { reader -> def line = reader.readLine() line.trim() }

闭包对象:

一个闭包其实就是一个groovy.lang.Closure类型的实例,以下:

//定义一个Closure类型的闭包 def listener = { e -> println "Clicked on $e.source" } assert listener instanceof Closure //定义直接指定为Closure类型的闭包 Closure callback = { println 'Done!' } Closure<Boolean> isTextFile = { File it -> it.name.endsWith('.txt') }

调运闭包:

其实闭包和C语言的函数指针很是像,咱们定义好闭包后调用的方法有以下两种形式:

  • 闭包对象.call(参数)

  • 闭包对象(参数)

以下给出例子:

def code = { 123 } assert code() == 123 assert code.call() == 123 def isOdd = { int i-> i%2 == 1 } assert isOdd(3) == true assert isOdd.call(2) == false

特别注意,若是闭包没定义参数则默认隐含一个名为it的参数,以下例子:

def isEven = { it%2 == 0 } assert isEven(3) == false assert isEven.call(2) == true

5-2 参数

普通参数:

一个闭包的普通参数定义必须遵循以下一些原则:

  • 参数类型可选
  • 参数名字
  • 可选的参数默认值
  • 参数必须用逗号分隔

以下是一些例子:

def closureWithOneArg = { str -> str.toUpperCase() } assert closureWithOneArg('groovy') == 'GROOVY' def closureWithOneArgAndExplicitType = { String str -> str.toUpperCase() } assert closureWithOneArgAndExplicitType('groovy') == 'GROOVY' def closureWithTwoArgs = { a,b -> a+b } assert closureWithTwoArgs(1,2) == 3 def closureWithTwoArgsAndExplicitTypes = { int a, int b -> a+b } assert closureWithTwoArgsAndExplicitTypes(1,2) == 3 def closureWithTwoArgsAndOptionalTypes = { a, int b -> a+b } assert closureWithTwoArgsAndOptionalTypes(1,2) == 3 def closureWithTwoArgAndDefaultValue = { int a, int b=2 -> a+b } assert closureWithTwoArgAndDefaultValue(1) == 3

隐含参数:

当一个闭包没有显式定义一个参数列表时,闭包老是有一个隐式的it参数。以下:

def greeting = { "Hello, $it!" } assert greeting('Patrick') == 'Hello, Patrick!'

上面的相似下面这个例子:

def greeting = { it -> "Hello, $it!" } assert greeting('Patrick') == 'Hello, Patrick!'

固然啦,若是你想声明一个不接受任何参数的闭包,且必须限定为没有参数的调用,那么你必须将它声明为一个空的参数列表,以下:

def magicNumber = { -> 42 } // this call will fail because the closure doesn't accept any argument magicNumber(11)

可变长参数:

Groovy的闭包支持最后一个参数为不定长可变长度的参数,具体用法以下:

def concat1 = { String... args -> args.join('') } assert concat1('abc','def') == 'abcdef' def concat2 = { String[] args -> args.join('') } assert concat2('abc', 'def') == 'abcdef' def multiConcat = { int n, String... args -> args.join('')*n } assert multiConcat(2, 'abc','def') == 'abcdefabcdef'

5-3 闭包省略调运

不少方法的最后一个参数都是一个闭包,咱们能够在这样的方法调运时进行略写括弧。好比:

def debugClosure(int num, String str, Closure closure){ //dosomething } debugClosure(1, "groovy", { println"hello groovy!" })

能够看见,当闭包做为闭包或方法的最后一个参数时咱们能够将闭包从参数圆括号中提取出来接在最后,若是闭包是惟一的一个参数,则闭包或方法参数所在的圆括号也能够省略;对于有多个闭包参数的,只要是在参数声明最后的,都可以按上述方式省略。

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

6 GDK(Groovy Development Kit)

Groovy除了能够直接使用Java的JDK之外还有本身的一套GDK,其实也就是对JDK的一些类的二次封装罢了;同样,这是GDK官方API文档,写代码中请自行查阅。

6-1 I/O操做

Groovy提供了不少IO操做的方法,你可使用Java的那写IO方法,可是没有Groovy的GDK提供的简单牛逼。

读文件操做:

咱们先来看一个例子:

 //读文件打印脚本 new File('/home/temp', 'haiku.txt').eachLine { line -> println line }  //读文件打印及打印行号脚本 new File(baseDir, 'haiku.txt').eachLine { line, nb -> println "Line $nb: $line" }

能够看见,这是一个读文件打印每行的脚本,eachLine方法是GDK中File的方法,eachLine的参数是一个闭包,这里采用了简写省略括弧。

固然了,有时候你可能更加喜欢用Reader来操做,使用Reader时即便抛出异常也会自动关闭IO。以下:

def count = 0, MAXSIZE = 3 new File(baseDir,"haiku.txt").withReader { reader -> while (reader.readLine()) { if (++count > MAXSIZE) { throw new RuntimeException('Haiku should only have 3 verses') } } }

接着咱们再看几个关于读文件的操做使用,以下:

//把读到的文件行内容所有存入List列表中
def list = new File(baseDir, 'haiku.txt').collect {it} //把读到的文件行内容所有存入String数组列表中 def array = new File(baseDir, 'haiku.txt') as String[] //把读到的文件内容所有转存为byte数组 byte[] contents = file.bytes //把读到的文件转为InputStream,切记此方式须要手动关闭流 def is = new File(baseDir,'haiku.txt').newInputStream() // do something ... is.close() //把读到的文件以InputStream闭包操做,此方式不须要手动关闭流 new File(baseDir,'haiku.txt').withInputStream { stream -> // do something ... }

上面介绍了一些经常使用的文件读操做,其它的具体参见API和GDK吧。

写文件操做:

有了上面的读操做,接下来直接看几个写操做的例子得了,以下:

//向一个文件以utf-8编码写三行文字 new File(baseDir,'haiku.txt').withWriter('utf-8') { writer -> writer.writeLine 'Into the ancient pond' writer.writeLine 'A frog jumps' writer.writeLine 'Water’s sound!' } //上面的写法能够直接替换为此写法 new File(baseDir,'haiku.txt') << '''Into the ancient pond A frog jumps Water’s sound!''' //直接以byte数组形式写入文件 file.bytes = [66,22,11] //相似上面读操做,可使用OutputStream进行输出流操做,记得手动关闭 def os = new File(baseDir,'data.bin').newOutputStream() // do something ... os.close() //相似上面读操做,可使用OutputStream闭包进行输出流操做,不用手动关闭 new File(baseDir,'data.bin').withOutputStream { stream -> // do something ... }

上面介绍了一些经常使用的文件写操做,其它的具体参见API和GDK吧。

文件树操做:

在脚本环境中,遍历一个文件树是很常见的需求,Groovy提供了多种方法来知足这个需求。以下:

//遍历全部指定路径下文件名打印
dir.eachFile { file -> println file.name } //遍历全部指定路径下符合正则匹配的文件名打印 dir.eachFileMatch(~/.*\.txt/) { file -> println file.name } //深度遍历打印名字 dir.eachFileRecurse { file -> println file.name } //深度遍历打印名字,只包含文件类型 dir.eachFileRecurse(FileType.FILES) { file -> println file.name } //容许设置特殊标记规则的遍历操做 dir.traverse { file -> if (file.directory && file.name=='bin') { FileVisitResult.TERMINATE } else { println file.name FileVisitResult.CONTINUE } }

执行外部程序:

Groovy提供一种简单方式来处理执行外部命令行后的输出流操做。以下:

def process = "ls -l".execute() println "Found text ${process.text}"

execute方法返回一个java.lang.Process对象,支持in、out、err的信息反馈。在看一个例子,以下:

def process = "ls -l".execute() process.in.eachLine { line -> println line }

上面使用闭包操做打印出执行命令行的输入流信息。

6-2 有用的工具类操做

ConfigSlurper配置:

ConfigSlurper是一个配置管理文件读取工具类,相似于Java的*.properties文件,以下:

def config = new ConfigSlurper().parse(''' app.date = new Date() app.age = 42 app { name = "Test${42}" } ''') assert config.app.date instanceof Date assert config.app.age == 42 assert config.app.name == 'Test42'

上面介绍了一些经常使用的属性配置操做,其它的具体参见API和GDK吧。

Expando扩展:

def expando = new Expando() expando.toString = { -> 'John' } expando.say = { String s -> "John says: ${s}" } assert expando as String == 'John' assert expando.say('Hi') == 'John says: Hi'

上面介绍了一些经常使用的拓展操做,其它的具体参见API和GDK吧。

6-2 其余操做

还有不少其余操做,这里就不一一列举,详情参考官方文档便可,譬如JSON处理、XML解析啥玩意的,自行需求摸索吧。

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

7 DSL(Domain Specific Languages)领域相关语言

这个就不特殊说明了,只在这里提一下,由于咱们前边不少地方已经用过它了,加上咱们只是干货基础掌握,因此不作深刻探讨。

DSL是一种特定领域的语言(功能领域、业务领域),Groovy是通用的编程语言,因此不是DSL,可是Groovy却对编写全新的DSL提供了很好的支持,这些支持来自于Groovy自身语法的特性,以下:

  • Groovy不需用定义CLASS类就能够直接执行脚本;

  • Groovy语法省略括弧和语句结尾分号等操做;

因此说这个基础入门不必特别深刻理解,简单的前面都用过了,理解DSL做用便可,点到为止,详情参考官方文档。

【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

相关文章
相关标签/搜索