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技術交流

相關文章
相關標籤/搜索