本文參考自The Groovy Development Kit,一些代碼直接引用了源文檔。
Groovy開發工具包(The Groovy Development Kit)的名字一開始迷惑了我,我以為是一些IDE的插件之類的。在實際看了原文檔之后,我才明白這是Groovy提供的一組類庫和方法,讓我們開發更加方便。
在java中讀寫文件非常麻煩。由于JDK類庫設計問題,以及Java本身的局限性,導致Java自帶的功能很不好用。比如說Java的讀寫流,使用了裝飾器設計模式,原意是讓我們能夠自行組合各種流,實現功能。但是實際情況是這讓類庫變得很復雜,我們哪怕是簡單讀寫文件也需要聲明一個很長的嵌套流。
Groovy為JDK的很多類提供了很多助手方法,讓文件讀寫變得異常簡單。列舉如下。如果需要查看完整的GDK文檔,可以查看GDK API文檔。
thejava.io.File class : http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/File.htmlthe java.io.InputStream class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/InputStream.htmlthe java.io.OutputStream class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/OutputStream.htmlthe java.io.Reader class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/Reader.htmlthe java.io.Writer class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/Writer.htmlthe java.nio.file.Path class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/nio/file/Path.htmlGroovy提供了非常方便的文件讀寫方式。而且在使用withXXX方法或者閉包中拋出異常時,Groovy會自動關閉文件資源。所以我們可以放心的使用這些API。首先來看看文件讀取。
Groovy為我們提供了豐富的功能。如果只需要簡單讀一個文件,簡單的幾行代碼就可以做到。這些方法很簡單,看代碼就能知道怎么用。
static void readingFiles() { def baseDir = /C:/Windows/System32/drivers/etc/ def filename = 'hosts' //讀取文件 def file = new File(baseDir, filename) file.eachLine { PRintln(it) } //同時獲取行號 file.eachLine { line, num -> println("line $num:$line") } //獲取字節流 byte[] contents = file.bytes println(contents.join('')) //獲取行列表 String[] lines = file.collect { it } println(lines.join('/n')) //將文件用作輸入流 file.withInputStream { //在這里執行操作 } }寫文件和讀文件一樣簡單。我們可以使用Writer來寫文件。文件編碼可以不指定,默認是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') << '這是一段文字'還可以直接寫入文件的字節流。
file.bytes = [66,22,11]同樣的,可以直接操作輸出流,使用withXXX方法可以在閉包結束之后就自動關閉資源。
new File(baseDir,'data.bin').withOutputStream { stream -> // do something ...}遍歷文件樹也很簡單。首先來看看遍歷目錄。
def dir = new File('C://Windows')//列出所有文件dir.eachFile { if (it.isFile()) { println(it) }}//列出所有可執行文件dir.eachFileMatch(~/.*/.exe$/){ println(it)}遞歸遍歷也很簡單,使用eachFileRecurse方法即可,還可以像方法傳遞枚舉變量指定要遞歸的類型。
dir.eachFileRecurse { file -> println file.name}dir.eachFileRecurse(FileType.FILES) { file -> println file.name}traverse方法提供了更強大的功能,該方法還可以接受一個Map作為遍歷參數,詳細參數作用參見這里。
dir.traverse { file -> if (file.directory && file.name=='bin') { FileVisitResult.TERMINATE } else { println file.name FileVisitResult.CONTINUE }}在Groovy中序列化和反序列化對象同樣簡單,直接看代碼。
static void serializeObjects() { def person = new Person(id: 1, name: 'yitian', birthday: LocalDate.now()) def file = new File(getCurrentDir(), 'obj.txt') file.withObjectOutputStream { it.writeObject(person) } def obj file.withObjectInputStream { obj = it.readObject() } println(obj) }class Person implements Serializable{ int id String name LocalDate birthday @Override String toString() { "Person(id=$id,name=$name,birthday=$birthday" }}在Grooy中調用外部進程也很簡單。在字符串上面調用execute方法,然后就會返回一個java.lang.Process對象。
要連接到進程的輸入輸出流也很簡單,直接引用進程的in、out、err屬性即可。需要注意in是輸出流,out、err是輸入流。
def process = "ls -l".execute() process.in.eachLine { line -> println line }進程也支持各種高級操作,例如管道。我們只要調用進程的pipeTo方法,或者使用管道操作符,都可以使用管道。其他進程的使用方法請參見Groovy文檔。
Groovy開發工具包提供了方便的集合操作,這些操作類似Java 8的流類庫,C#的LINQ,Kotlin的集合庫,提供了各種方便的功能。
列表上定義了豐富的操作,求和、排序、取值、集合運算等等。直接看代碼吧。
static void lists() { println('列表') //定義列表 def list = [1, 3, 25, 77, 5, 8, 97, 34, 100, 230] //訪問列表 println(list[2]) list[1] = 100 println(list[2..-1]) //添加元素 list << 77 list << 45 list.add(12) list.addAll([1, 2, 3, 4, 5]) list += 5 println(list) //刪除元素 list - 77 //刪除下標為6的元素 list.remove(6) list.removeAll([1, 2, 3, 4, 5]) list -= 5 println(list) //列表排序 list.sort().reverse() println(list) //斷言 assert ![] assert list //迭代 list.each { print("$it ") } println() //帶序號迭代 list.eachWithIndex { int e, int index -> print("$index->$e ") } println() //轉換列表 def multi2 = list.collect { it * 2 } println(multi2) //和上面等價 def times2 = list*.multiply(2) println(times2) //過濾列表 def greaterThan17 = list.findAll { it > 7 } println(greaterThan17) //只查找第一個 def firstGreaterThan7 = list.find { it > 7 } println(firstGreaterThan7) //判斷列表 assert !list.every { it > 100 } assert list.any { it > 100 } //求和和最值 def sum = list.sum() println("sum=$sum") println("max=${list.max()}") println("min=${list.min()}") //連接操作 println([1, 2, 3, 4].join('<->')) //累積操作,累加、累乘還有更復雜的操作 println("累計求和:${[1, 2, 3, 4].inject { s, i -> s + i }}") println("累計求積:${[1, 2, 3, 4].inject { s, i -> s * i }}") //集合操作 def list1 = [1, 2, 3, 4] def list2 = [2, 3, 5, 4, 23, 2] println("求交:${list1.intersect(list2)}") println("2出現了幾次:${list2.count(2)}") println("有幾個奇數:${list2.count { it % 2 != 0 }}") //無相交元素 assert [1, 2, 3].disjoint([4, 5, 6]) //重復元素 println("[1,2]重復兩遍是什么:${[1, 2] * 2}") println("[1,2]重復4遍是什么:${[1, 2].multiply(4)}") }Map同樣支持很多操作。直接看代碼吧。
static void maps() { println("Map") def map = [:] //添加元素 map[7] = 7 map.put(8, 8) (1..6).each { map[it] = it } //遍歷元素 println(map) map.each { entry -> println("key:$entry.key,value:$entry.value") } map.eachWithIndex { Map.Entry<Object, Object> entry, int index -> println("index:$index,key:$entry.key,value:$entry.value") } map.each { key, value -> println("key:$key,value:$value") } //集合 println("keys:${map.keySet()}") println("entries:${map.entrySet()}") println("values:${map.values()}") //分組 def list = [1, 2, 3, 4, 5, 6] def group = list.groupBy { it % 2 == 0 } println("分組后的結果:$group") //獲取字符串鍵值 def couples = [amy: 'leo', king: 'lily', smith: 'lisa'] println(couples['king']) println(couples.smith) //字符串鍵要特別注意 def name = 'yitian' def people = [name: 24] println(people) //使用括號才能正確將變量的值用作鍵 people = [(name): 24] println(people) //不要用GString作為鍵,它和String的哈希值不同 def s = '1234' def gs = "${s}" println("GString hash:${gs.hashCode()},String hash:${s.hashCode()}") //放進去再用String取是讀不出來的 def m = [(gs): 123] assert m[s] == null }范圍操作是另一類方便的操作。我們可以定義閉區間和開閉區間,然后方便的迭代和判斷范圍。
static void ranges() { def range = 1..10 println(range) //開閉區間 def range2 = 1..<10 range2.each { print "$it " } println() //范圍的起止 println("起:${range.from},止:${range.to}") //范圍繼承了List接口 assert range instanceof List println("第二個和最后第二個元素:${range[1, -2]}") println("第二個到倒數第二個:${range[1..-2]}") println("3是否在范圍內:${3 in range}") //范圍可用于switch def marriedYears = 15 switch (marriedYears) { case 1..5: println("小夫妻") break case 6..10: println("老夫妻") break case 11..30: println("老夫老妻") break default: println("成仙了") } }Groovy還提供了切片操作符、展開操作符和星點操作符,對集合執行不同的操作。
static void Operators() { //切片運算符 def list = 1..100 println("倒數十個元素:${list[-10..-1]}") //展開運算符,也就是將兩個集合展開合并為一個 def list2 = [1, 2, 3, *(4..10)] println(list2) //星點操作符,用于選定一個集合中的某個屬性 def people = [[name: 'yitian'], [name: 'zhang3'], [name: 'li4']] println("所有名字是:${people*.name}") }Groovy還為提供了擴展的方法,詳細情況請參見相應文檔。
添加到Iterable的方法可以在后面的鏈接中找到here添加到Iterator的方法可以在后面的鏈接中找到here添加到Collection的方法可以在后面的鏈接中找到here添加到List的方法可以在后面的鏈接中找到here添加到Map的方法可以在后面的鏈接中找到here新聞熱點
疑難解答