Groovy 使用完全解析
轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/70313790
本文出自【趙彥軍的博客】
文章目錄
- 概念
- Groovy 配置環境變量
- 開發工具 IntelliJ IDEA
- Groovy 語法
- 基本語法
- 定義變量
- 定義函數
- 斷言 assert
- 循環 for
- 循環 time
- 三目運算符
- 捕獲異常
- switch
- 判斷是否為真
- asType
- Groovy 數據類型
- **Java 基本類型**
- **Groovy 容器**
- 閉包
- Java 屬性
- 再識 Groovy
- Script 類
- 腳本變量的作用域
- JSON 操作
- 對象轉json 、 json 轉對象
- 集合對象轉json 、json 轉集合對象
- I/O 操作
- 文本文件讀
- 文本文件寫
- 文件夾操作
- 深度遍歷文件
- InputStream
- xml 解析
- 實例1 解析簡單xml
- 實例2 解析復雜 xml
概念
Groovy是一種動態語言,它和Java類似(算是Java的升級版,但是又具備腳本語言的特點),都在Java虛擬機中運行。當運行Groovy腳本時它會先被編譯成Java類字節碼,然后通過JVM虛擬機執行這個Java字節碼類。
Groovy 配置環境變量
-
在 Groovy 官網下載壓縮包 http://www.groovy-lang.org/download.html
-
然后解壓到本地,如圖所示:
- 在 Path 環境變量中添加 Groovy 的bin 目錄路徑,比如:
D:\soft\apache-groovy-sdk-2.4.10\groovy-2.4.10\bin
如圖所示:
- 用 CMD 打開命令行,執行:groovy -version , 如果看到如下提示,就代表配置成功了。
Groovy Version: 2.4.10 JVM: 1.8.0_112 Vendor: Oracle Corporation OS: Windows 10
如圖所示:
開發工具 IntelliJ IDEA
groovy 的開發工具是 IntelliJ IDEA
下載地址: https://www.jetbrains.com/idea/
安裝完成后,新建項目 ,項目類型選擇 Groovy ,然后填寫 JDK 、Groovy 的安裝目錄
新建的項目 Groovy 如下圖所示:
在 src 目錄下,新建包名 groovy , 并且創建 groovy 源文件 Test.groovy,如下圖所示:
現在我們在 Test.groovy 中輸出一句 helloword ,代碼如下:
package groovyprintln( "hello world")運行 Test.groovy 文件 ,如下圖所示:
Groovy 語法
基本語法
1、Groovy注釋標記和Java一樣,支持 //或者/**/
2、Groovy語句可以不用分號結尾。Groovy為了盡量減少代碼的輸入,確實煞費苦心
3、單引號
單引號’’ 中的內容嚴格對應Java中的String,不對 $ 符號進行轉義
def s1 = 'i am 100 $ dolloar' println( s1 )運行結果:
i am 100 $ dolloar4、雙引號
雙引號""的內容則和腳本語言的處理有點像,如果字符中有號的話,則它會號的話,則它會號的話,則它會表達式先求值。
def x = 100 def s1 = "i am $x dolloar"println( s1 )運行結果:
i am 100 dolloar5、三引號
三個引號’’‘xxx’’'中的字符串支持隨意換行 比如
def s1 = ''' x y z f '''println(s1)運行結果:
x y z f定義變量
Groovy中支持動態類型,即定義變量的時候可以不指定其類型。Groovy中,變量定義可以使用關鍵字def。注意,雖然def不是必須的,但是為了代碼清晰,建議還是使用def關鍵字
- 定義一個變量
定義函數
無返回類型的函數定義,必須使用def關鍵字 ,最后一行代碼的執行結果就是本函數的返回值
//無參函數 def fun1(){}//有參函數 , 無需指定參數類型 def fun2( def1 , def2 ){}如果指定了函數返回類型,則可不必加def關鍵字來定義函數
String fun3(){return "返回值" }其實,所謂的無返回類型的函數,我估計內部都是按返回Object類型來處理的。畢竟,Groovy 是基于Java 的,而且最終會轉成 Java Code 運行在 JVM 上 .
Groovy的函數里,可以不使用return xxx 來設置 xxx 為函數返回值。如果不使用 return 語句的話,則函數里最后一句代碼的執行結果被設置成返回值。
def getSomething(){ "getSomething return value" //如果這是最后一行代碼,則返回類型為String 1000 //如果這是最后一行代碼,則返回類型為Integer }除了每行代碼不用加分號外,Groovy中函數調用的時候還可以不加括號
例子1:
def s1 = "123"println(s1)//或者println s1例子2:
println(fun1())println fun1()def fun1(){"你好" }效果:
你好 你好斷言 assert
- 斷言變量為空
效果如下:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-YixwoPo6-1609157395410)(https://img-blog.csdn.net/20170915162248368?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemhhb3lhbmp1bjY=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)]
- 斷言變量的長度
效果如下:
如果斷言發生,斷言后面的代碼無法執行
循環 for
- 方式一
1、運行結果: 輸出5個測試
2、groovy 語法中,注意 i 前面不用指定 int 類型。
- 方式二
這種方式也是一種循環,只不過他輸出的是 6 個 hello world , 如果想要輸出5個,有3中方式。
第一種方法
for (i in 0..<5){println("hello world") }第二種方法
for (i in 0..4){println("hello world") }第三種方法
for (i in 1..5){println("hello world") }循環 time
times表示從0開始循環到4結束
4.times {println it }結果:
0 1 2 3三目運算符
Java 語法
def name def result = name != null ? name : "abc" println(result)groovy 語法
def name = 'd' def result = name?: "abc"捕獲異常
捕獲所有的 Exception ,有兩種寫法
//第一種寫法,Java 寫法 try {println 5 / 0 } catch (Exception e) {}//第二種寫法,Groovy 寫法 try {println 5 / 0 } catch (anything) {}這里的any并不包括Throwable,如果你真想捕獲everything,你必須明確的標明你想捕獲Throwable
switch
age = 36 def rateswitch (age) {case 10..26:rate = 0.05breakcase 27..36:rate = 0.06breakcase 37..46:rate = 0.07breakdefault:throw new IllegalArgumentException() }println( rate)判斷是否為真
Person person//Java 寫法 if (person!= null){if (person.Data!=null){println person.Data.name} }//Groovy println person?.Data?.nameasType
asType 就是數據類型轉換
//String 轉成 int def s2 = s1 as int//String 轉成 int def s3 = s1.asType(Integer)Groovy 數據類型
Groovy中的數據類型主要分2種
-
一個是Java中的基本數據類型。
-
另外一個是Groovy中的容器類。
-
最后一個非常重要的是閉包。
Java 基本類型
def boolean s1 = truedef int s2 = 100def String s3 = "hello world"if (s1) {println("hello world") }Groovy 容器
List:鏈表,其底層對應Java中的List接口,一般用ArrayList作為真正的實現類。
Map:鍵-值表,其底層對應Java中的LinkedHashMap。
Range:范圍,它其實是List的一種拓展。
- List
效果如下:
[5, string, false] 5 string false null 集合長度:3 [5, string, false, null, null, null, null, null, null, null, 100] 集合長度:11- map
- range
Range 是 Groovy 對 List 的一種拓展
def range = 1..5println(range) //[1, 2, 3, 4, 5]range.size() //長度range.iterator() //迭代器def s1 = range.get(1) //獲取標號為1的元素range.contains( 5) //是否包含元素5range.last() //最后一個元素range.remove(1) //移除標號為1的元素range.clear() //清空列表例子2:
def range = 1..5println(range) //[1, 2, 3, 4, 5]println("第一個數據: "+range.from) //第一個數據 //第一個數據: 1println("最后一個數據: "+range.to) //最后一個數據 //最后一個數據: 5閉包
閉包,英文叫Closure,是Groovy中非常重要的一個數據類型或者說一種概念了。閉包,是一種數據類型,它代表了一段可執行的代碼。
def aClosure = {//閉包是一段代碼,所以需要用花括號括起來.. String param1, int param2 -> //這個箭頭很關鍵。箭頭前面是參數定義,箭頭后面是代碼 println"this is code" //這是代碼,最后一句是返回值, //也可以使用return,和Groovy中普通函數一樣 }簡而言之,Closure的定義格式是:
def xxx = {paramters -> code} //或者 def xxx = {無參數,純code}說實話,從C/C++語言的角度看,閉包和函數指針很像。閉包定義好后,要調用它的方法就是:
閉包對象.call(參數)
或者更像函數指針調用的方法:
閉包對象(參數)
比如:
實例演練,源碼如下
def fun1 = {p1 ->def s = "我是一個閉包," + p1 }println(fun1.call()) //閉包 調用方式1println(fun1.call("我是一個參數")) //閉包 調用方式2println(fun1("我是一個參數2"))運行結果如下:
我是一個閉包,null 我是一個閉包,我是一個參數 我是一個閉包,我是一個參數2閉包沒定義參數的話,則隱含有一個參數,這個參數名字叫it,和this的作用類似。it代表閉包的參數。
def fun2 = {it-> "dsdsd" }println( fun2.call())如果在閉包定義時,采用下面這種寫法,則表示閉包沒有參數!
def fun3 = {-> "dsdsd" }println( fun3.call())如果調用 fun3 的時候傳遞參數就會報錯,比如
fun3.call("d") //執行這個方法的時候就會報錯省略圓括號
def list = [1,2,3] //定義一個List//調用它的each,這段代碼的格式看不懂了吧?each是個函數,圓括號去哪了?list.each {println(it) }//結果/*** 1* 2* 3*/each函數調用的圓括號不見了!原來,Groovy中,當函數的最后一個參數是閉包的話,可以省略圓括號。比如
def fun(int a1,String b1, Closure closure){ //dosomething closure() //調用閉包 }那么調用的時候,就可以免括號!
fun (4, "test", { println"i am in closure" })注意,這個特點非常關鍵,因為以后在Gradle中經常會出現這樣的代碼:
task hello{doLast{println("hello world")} }省略圓括號雖然使得代碼簡潔,看起來更像腳本語言
Java 屬性
Groovy中可以像Java那樣寫package,然后寫類。比如我們在 Person.groovy 文件中編寫Java 代碼,如下所示:
然后我們新建 Test.groovy 類,寫測試工程,如下所:
運行結果如下所示:
Person{name='zhaoyanjun', age=20}當然,如果不聲明public/private等訪問權限的話,Groovy中類及其變量默認都是public的.
再識 Groovy
Java中,我們最熟悉的是類。但是我們在Java的一個源碼文件中,不能不寫class(interface或者其他…),而Groovy可以像寫腳本一樣,把要做的事情都寫在xxx.groovy中,而且可以通過groovy xxx.groovy直接執行這個腳本。這到底是怎么搞的?
既然是基于Java的,Groovy會先把xxx.groovy中的內容轉換成一個Java類。
在運行完 Test.groovy 后,發現會產生一個 out 目錄,在這個目錄里面可以看到 Person.groovy 、Test.groovy 被轉換成了 .class 文件,如下圖所示:
-
編譯完成后,.groovy 文件都被轉換成了 .class 文件,每個 .class 文件都默認有靜態 main 方法。每一個腳本都會生成一個static main函數。這樣,當我們groovytest.groovy的時候,其實就是用java去執行這個main 函數。
-
腳本中的所有代碼都會放到run函數中。比如,println ‘Groovy world’,這句代碼實際上是包含在run函數里的。
-
Test 繼承 Script 類。
Script 類
在 groovy 的庫文件中,可以看到 Script 類是一個抽象類,繼承 GroovyObjectSupport 類,如下所示
腳本變量的作用域
在 Test.groovy 里面定義變量 s1 , 方法 fun1 , 同時在 fun1 方法中輸出 s1 , 代碼如下:
一運行就報錯,錯誤如下
通過 out 目錄,查看 Test.class 類如下:
可以看到在 s1 變量定義在 run 方法中,相當于局部變量,fun1 方法自然無法訪問 s1 .
解決方法也很簡單 ,就是把 s1 的 def 去掉,代碼如下:
通過 out 目錄,查看 Test.class 類如下:
上圖中 s1 也沒有被定義成 Test 的成員函數,而是在 run 的執行過程中,將 s1 作為一個屬性添加到 Test 實例對象中了。然后在print s1 中,先獲取這個屬性。但是從反編譯的實際上看,s1 并沒有成為 Test.class 的成員變量,其他腳本卻無法訪問 s1 變量 。
怎樣使 s1 徹徹底底變成 Test 的成員變量?
答案也很簡單在 s1 前面加上 @Field 字段
@Field s1 = "123" //s1 徹徹底底變成 Test 的成員變量反編譯效果如下:
JSON 操作
JsonOutput 類把對象轉換成 json字符串。
JsonSlurper 類把 json 字符串轉換成對象
定義 Person 實體類
public class Person {String name;int age; }對象轉json 、 json 轉對象
Person person = new Person(); person.name = "zhaoyanjun" person.age = 27//把對象轉換為 json 字符串 def json =JsonOutput.toJson(person)println(json)JsonSlurper jsonSlurper = new JsonSlurper()//把字符串轉換為對象 Person person1 = jsonSlurper.parseText(json)println( person1.name )運行效果如下圖:
{"age":27,"name":"zhaoyanjun"} zhaoyanjun集合對象轉json 、json 轉集合對象
Person person = new Person(); person.name = "zhaoyanjun" person.age = 27Person person1 = new Person(); person1.name = "zhaoyanjun2" person1.age = 28def list = [person,person1]//把集合對象轉換為 json 字符串 def jsonArray =JsonOutput.toJson(list)println(jsonArray)JsonSlurper jsonSlurper = new JsonSlurper()//把字符串轉換為集合對象 List<Person> list2 = jsonSlurper.parseText(jsonArray)println( list2.get(1).name )運行結果為:
[{"age":27,"name":"zhaoyanjun"},{"age":28,"name":"zhaoyanjun2"}] zhaoyanjun2I/O 操作
Groovy的 I/O 操作是在原有Java I/O操作上進行了更為簡單方便的封裝,并且使用Closure來簡化代碼編寫。雖然比Java看起來簡單,但要理解起來其實比較難。
文本文件讀
在電腦上新建一個文本文件 test.txt , 內容如下:
今天是星期五 天氣很好 明天就要放假了下面用 groovy 讀取里面的文本
def filePath = "C:/Users/T/Desktop/test.txt" def file = new File(filePath) ;file.eachLine {println it }你沒有看錯,就是這么簡單,groovy 的文件讀取操作簡單到令人發指。但是這不夠,還有跟令人發指的操作,比如:
def filePath = "C:/Users/T/Desktop/test.txt" def file = new File(filePath) ;println file.text //輸出文本看到這里,發現 Groovy 操作文件比 Java 簡單了 100 倍,蒼天啊!
更多用法
- 指定編碼格式
- 把小寫轉成大寫
文本文件寫
- 方式1
- 方式2
效果如下:
文件夾操作
- 遍歷文件夾中的文件、文件
效果如下:
文件夾:1 文件夾:2 文件夾:3 文件:1 文件:2 文件:3 文件:4.txt深度遍歷文件
def filePath = "e:/" def file = new File(filePath);//深度遍歷目錄,也就是遍歷目錄中的目錄 file.eachDirRecurse {println it.name }//深度遍歷文件,包括目錄和文件 file.eachFileRecurse {println it.path }InputStream
def filePath = "C:/Users/T/Desktop/test.txt" def file = new File(filePath) ;def ism = file.newInputStream() //操作ism,最后記得關掉ism.close使用閉包操作 inputStream,以后在Gradle里會常看到這種搞法
def filePath = "C:/Users/T/Desktop/test.txt" def file = new File(filePath) ;file.withInputStream {ism->// 操作ism. 不用close。Groovy會自動替你close ism.eachLine {println it //讀取文本} }確實夠簡單,令人發指。我當年死活也沒找到withInputStream是個啥意思。所以,請各位開發者牢記Groovy I/O操作相關類的SDK地址:
- java.io.File: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/File.html
- java.io.InputStream: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/InputStream.html
- java.io.OutputStream: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/OutputStream.html
- java.io.Reader: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/Reader.html
- java.io.Writer: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/Writer.html
- java.nio.file.Path: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/nio/file/Path.html
xml 解析
在java中解析xml是非常繁瑣的,通常需要用10行代碼去解析5行的xml文件,非常不經濟。在groovy 中解析xml 就很方便了。
實例1 解析簡單xml
比如下面一段xml
<?xml version="1.0"?><langs type="current"> <language>Java</language> <language>Groovy</language> <language>JavaScript</language> </langs>groovy 解析如下:
//獲取 xml 文件的 langs 節點 def langs = new XmlParser().parse("C:/Users/T/Desktop/test.xml")//獲取type 字段的值 def type = langs.attribute("type")println typelangs.language.each{println it.text() }結果如下:
current Java Groovy JavaScript實例2 解析復雜 xml
xml 如下圖所示:
<?xml version="1.0" encoding="UTF-8"?> <metadata><groupId>com.yiba.sdk</groupId> <artifactId>weshareWiFiSDk</artifactId> <version>2.3.3</version><versioning> <latest>2.3.3</latest><versions><version>2.2.7</version><version>2.3.0</version><version>2.3.1</version><version>2.3.2</version><version>2.3.3</version></versions> </versioning></metadata>解析代碼如下:
//獲取metadata節點 def metadata = new XmlParser().parse("C:/Users/T/Desktop/test1.xml")//獲取metadata下面的 groupId 屬性值 def groupId = metadata.groupId.text()//獲取metadata下面的 artifactId 屬性值 def artifactId = metadata.artifactId.text()//獲取metadata下面的 version 屬性值 def version = metadata.version.text()println groupId + " " + artifactId + " " + version//獲取metadata下面的 versioning 節點 def versioning = metadata.versioning//獲取versioning 下面的 latest 屬性值 println versioning.latest.text()//獲取versioning 下面的 versions 節點 def versions = versioning.versions versions.version.each{//遍歷 versions 下面的version 值println "version" + it.text() }結果如下:
com.yiba.sdk weshareWiFiSDk 2.3.3 2.3.3 version2.2.7 version2.3.0 version2.3.1 version2.3.2 version2.3.3個人微信號:zhaoyanjun125 , 歡迎關注
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-DbdhcgIu-1609157395419)(http://o7rvuansr.bkt.clouddn.com/weixin200.jpg)]
總結
以上是生活随笔為你收集整理的Groovy 使用完全解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android Loader 异步加载详
- 下一篇: Android Git 常用命令和规范