Groovy语法

注释

  • 单行注释//
//这是单行注释
  • 多行注释/**/
/*这是多行注释*/

// GroovyDoc注释/** */

/**
* 这是文档注释
*/


变量名

  • 普通变量名和Java规则一样
  • 引用变量,变量点后面可以跟引用值,可以使用java不允许的符号比如破折号等,比如
map = [:]
map."name" = "james"
map."a-b-c" = "dota"

map./slashy string/
map.$/dollar slashy string/$

def firstname = "Homer"
map."Simpson-${firstname}" = "Homer Simpson"


字符串

  • 单引号字符串
'hello world'
  • 三引号字符串表示多行
""" line 1
line 2
line 3
  • 双引号字符串,可以使用或者{}在字符串中进行插值,其中${}可以插入值或者表达式,但是表达式必须要以某种形式返回值否则值为null。
    其中$只对a.b有效,对其他语句无效如方法调用,大括号等,如果想输入$符号可以使用""
"2 + 3 is ${2+3}" // output 2+3 is 5
"2 + 3 is ${def i = 2; def j = 3; i+j}" // output 2 + 3 is 5

def person = [name: 'James', age: 36]
"$person.name is 36" // output James is 36
"person is $def age = 10" // 不合法
""
  • 当字符串中存在${->}形式,这表示一个闭包,闭包包含0个参数或者1个参数
    0个参数的闭包会调用toString()作为值,即->后面的值会toString,如果是表达式必须要有返回值,否则为null
    1个参数的闭包会传入的参数类型为StringWriter,用这个参数可以追加内容, 可以使用"<<"操作符追加内容
def person = "1 + 2 is ${->3}"

def person = "1 + 2 is ${w -> w.append("5")}"
def person = "1 + 2 is ${w -> w << "5"}"
  • 上述两种插值方法对比,采用闭包的好处可以动态更新数据,如果变量值更新了,闭包所用参数也对应更新。
    如下所示可以看出,当num值更新时,字符串闭包内的值也改变了, 普通传值没有改变是因为创建String的时候值就已经确定了。
def num = 3
def normal = "1 + 2 is ${-> num}"
def cls = "1 + 2 is ${num}"
println(normal) // output "1 + 2 is 3"
println(cls) // output "1 + 2 is 3"

num = 5
println(normal) // output "1 + 2 is 3"
println(cls) // output "1 + 2 is 5"
  • 字符串使用插值,类型则会被转换为GString,类型,值得注意的是GString类型的hashCode和String类型的hashCode是不一样的
def key = "a"
map = [${key}:"James"]
printfln map["a"] // output null
  • Char类型可以用以下三种来表示
def a = 'A'

def b = 'A' as char

def c = (char)'A'


Numbers

  • 整数数据类型基本和Java一样分别是byteshortcharintlongBigInteger
    如果类型修饰符为def,会根据范围,自动识别对应的数据类型
    def i = 10
    println i instance of Interger // Output ture
    
  • 小数数据类型分别是floatdoubleBigDecimal
    float a = 1.2
    double b = 1.21
    
  • 数字可以添加下划线,使某些大数看起来更加清楚
long i =  1223_123_1L
long i = 0x7fff_8fff_0000_ffff
  • 通过数字后缀来代表数据类型
Integer a = 42I或42i
Long b = 42L或42l
BigInteger c = 42G或42g
Double d = 42.2D或42.5d
Float e = 42.2F或42.1f
BigDecimal f = 42.24G或42.24g


List

  • Groovy使用逗号分隔值(用方括号括起来)来表示列表,默认类型为List, 一个List的值可以是不同类型
def listone = [1,2,3,4]
def listtwo = [1, 1.24, "hello"]s
  • List是ArrayList的实例,可以通过as进行转换成其他类型的List
def list = [1,2,3,4] as LinkedList
  • List索引可以使用以下几种形式, 可以用<<添加值
def list = [1,2,3,4]
list[-1]
list[2]
list[1..3]

list << 5
  • 多维List
list = [[0,1],[2,3]]
list[0][1]


Arrays

  • Arrays的形式上和List是一样的,但是如果需要Arrays类型数据,需要通过变量指定数据类型或者通过as强转
int[] list = [1,2,3,4,5]
def list = [1,2,3,4] as int[]
  • 索引,多维数组等定义和List一样

Maps

  • Groovy使用逗号分隔值(用方括号括起来),键值对冒号分隔来表示Map
def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']

colors['pink'] = '#FF00FF'
colors.yellow = '#FFFF00'
  • 如果想要引用变量作为key值,则需要加上括号
def key = 'pink'
def map = [(key) :123]


操作符

  • ** 表示次方, 下面表示2的3次方
def num = 2 ** 3
  • 双目运算符?:,是一个false 赋值
def a = 8
def b = a < 7 ?:10
// 等价于
if(a < 7) {
    b = ture
} else {
    b = 10
}
  • *.操作符,将cars中make元素全部收集到同一个列表
class Car {
    String make
    String model
}
def cars = [
       new Car(make: 'Peugeot', model: '508'),
       new Car(make: 'Renault', model: 'Clio')]       
def makes = cars*.make                                
assert makes == ['Peugeot', 'Renault'] 
  • Spread操作符可以将list列表中值传入符合list数量的方法中, 也可以直接插入到另外一个list中
def list = [1,2,3]
int f(int i, int j, int z) {
    return i * j + z
}

f(*list)

def other = [4,5, *list] // output [4,5,1,2,3]
def other = [4,5, list] // output [4,5,[1,2,3]]
  • map中也可以使用
def map = [red : 0x1]
def add = [green : 0x2, * : map]
// output [green:34, red:17]
  • Range操作符.., 生成一个有序列表
def i = 0..5 // output [0,1,2,3,4,5]
def i = 0..<5 // output [0,1,2,3,4]
def i = 'a'..'d' // output ['a','b','c','d']
  • 比较操作符<=>, 类似java中的compareTO方法,
(1<=>1) = 0
(2<=>1) = 1
(2<=>3) = -1
  • 下标操作符,类似getAt()或putAt()方法
def list = [0,1,2,3,4]
list[3] = 5 // output [0,1,2,5,4]
list[4] // output 4
  • 成员关系操作符in,判断一个数据成员是否在列表当中
def list = [1,2,3]
5 in list // output false
  • Identity操作符,==操作符在Groovy和Java中使用是不一样的, ==比较是值是否相等,equals比较的是内存地址是否一样
def list1 = [1,2,3]
def list2 = [1,2,3]
list1.is(list2) // output false
list1 == list2 // output true

Integer a = new Integer(5);
Integer b = new Integer(5);
println a.is(b) // output false
println a == b // output true
  • 转换操作符as,as操作符如果符合转换规则,就可以转换,否则会抛异常。如果转换为另外一个类型就会创建一个新的对象
Integer x = 123 as String  // output "123"
String a = "123" as Map // 抛异常
  • Groovy支持运算符重载

  • 包支持用别名
import java.util.Date as SQLDate

SQLDate date = new SQLDate() 
  • 脚本和类,Groovy会把脚本转换成一个类,这个类继承于Script,最终调用的还是main()方法,我们在写脚本中写的方法会被加入到类中,写的语句全部在run()方法中。
println 'Hello'                                 
int power(int n) { 2**n }                       
println "2^6==${power(6)}"

// 转换之后
import org.codehaus.groovy.runtime.InvokerHelper
class Main extends Script {
    int power(int n) { 2** n}                   
    def run() {
        println 'Hello'                         
        println "2^6==${power(6)}"              
    }
    static void main(String[] args) {
        InvokerHelper.runScript(Main, args)
    }
}
  • 脚本中变量作用域。
    变量如果声明类型,则无法被其他方法访问,因为这个变量相当于run方法中的局部变量
    变量如果没有声明类型,则会被脚本绑定,脚本会和其他方法共享这些数据
int declared  = 0
undeclared  = 10
void pow() {
    println declared
    println undeclared
}

pow()
  • 反编译之后的代码, 可以看到run方法中会把变量值传入,pow方法中把值取出来
public class Study extends Script
{
  public void pow()
  {
    CallSite[] arrayOfCallSite = $getCallSiteArray();
    arrayOfCallSite[2].callCurrent(this, arrayOfCallSite[3].callGroovyObjectGetProperty(this));
    arrayOfCallSite[4].callCurrent(this, arrayOfCallSite[5].callGroovyObjectGetProperty(this));
  }
  
  public Object run()
  {
    CallSite[] arrayOfCallSite = $getCallSiteArray();
    int declared = 0;
    int i = 10;
    ScriptBytecodeAdapter.setGroovyObjectProperty(Integer.valueOf(i), Study.class, this, (String)"undeclared");
    pow();
   }
  
  public static void main(String... args)
  {
    CallSite[] arrayOfCallSite = $getCallSiteArray();
    arrayOfCallSite[0].call(InvokerHelper.class, Study.class, args);
  }
  
}


方法和类

  • 如果没有可见修饰符修饰,默认是public的,并且会自动转换成属性,自然省去get和set方法
public class Study {
    public String name;

    class School {
        Study study = new Study();
        public void driver() {
        }
    }
}
  • 一个文件可以包含多个类,如果没有类默认是脚本(当然最后还是会转换为一个类)

  • 不论是构造函数还是普通函数参数都可以通过列表传入, 方法参数可以设置默认值

public class Study {
    public Study(String name, int age) {
        
    }
    
    public void pow(int a, int b = 9) {
    }
}


Study study = ["1",2] 
study.pow([5,6])
study.pow(5)
  • 方法可变参数列表
    可以传入任意个参数
    T[]和T..是等价的,也表示可见参数,意味方法参数列表为数组的,都表示可变参数。
    如果出现多个方法重载,比如一个方法参数列表是可见参数,另外一个方法参数列表是具体个数参数,以含具体个数参数方法为主
    void f(int[] a);
    void f(int a);
    
    f(1) // 调用的是f(int a)方法
    

Traits(特征)

  • 是Groovy独有的面向对象特性,有几点特性:由行为构成、可以实现接口、行为可以重载,兼容静态类型的检查和编译。可以看成具有方法实现和状态的接口,关键字trait
trait FlyingAbility {                           
    String fly() {
        println "I'm flying!" 
    }          
}

class Bird implements FlyingAbility {}          
def b = new Bird()                              
println b.fly()  
  • 可以含有抽象方法
trait Greetable {
    abstract String name()                              
    String greeting() { "Hello, ${name()}!" }           
}
  • 可以定义private方法
trait Greeter {
    private String greetingMessage() {                      
        'Hello from a private method!'
    }
    String greet() {
        def m = greetingMessage()                           
        println m
    }
}
  • 可以使用this操作符
public trait FlyingAbility {
    
    String fly() {
        return this
    }
}
  • 可以定义属性
trait Named {
    String name                             
}
  • 可以定义私有和共有字段
trait Counter {
    public int num = 1
    private int count = 0                   
    int count() { count += 1; count }       
}
  • 和接口一样支持多重继承
trait FlyingAbility {                           
        String fly() { "I'm flying!" }          
}
trait SpeakingAbility {
    String speak() { "I'm speaking!" }
}

class Duck implements FlyingAbility, SpeakingAbility {}
  • 方法可以被覆盖、相互继承
trait FlyingAbility {                           
        String fly() { 
            "I'm flying!" 
        }          
}
trait SpeakingAbility extends FlyingAbility {
    String fly() {
        "I can speaking!" 
    }
}


闭包

  • 闭包是一个匿名函数,拥有函数的特征,写法如下{ [closureParameters -> ] statements }, 有以下几种写法
{ item++ }                                          

{ -> item++ }                                       

{ println 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.Closur一个实例,可以赋值给该类的实例对象
def listener = { e ->  e } 
println listener //output `groovy.lang.Closure`对象
println listener("lis") // output  "lis"

Closure callback = { println 'Done!' }     

Closure<Boolean> isTextFile = {
    File it -> it.name.endsWith('.txt')                     
}
  • 闭包可以像其他方法一样被调用,可以像其他函数一样传参进入,也可以当成一个对象调用call方法
def isOdd = { 
    int i -> i%2 != 0 
}

isOdd(2)
isOdd.call(2)

  • 闭包跟函数一样,参数列表可以是对象,基本类型,可选列表,也可以给参数设置默认值,
    不过和函数不同的地方,如果闭包没有确切定义一个参数列表,闭包就会定义一个隐式参数it
def f = {-> printfln it}
def f = {it -> println it}


闭包中的this,owner,delegate

  • this:在一个类中定义闭包,闭包中的this指向该类,
    getThisObject()this是等价的。
    类中定义闭包使用this,则指向内部类,在该闭包中可以调用该类的成员变量和方法
    闭包中嵌套使用闭包,this也是指向类
    总之,无论闭包怎么嵌套,闭包中使用this就指向离他最近的类
class Enclosing {
    void run() {
        def whatIsThisObject = { getThisObject() }          
        assert whatIsThisObject() == this                   
        def whatIsThis = { this }                           
        assert whatIsThis() == this   //  等价                     
    }
}
class EnclosedInInnerClass {
    class Inner {
        Closure cl = { this }                               
    }
    void run() {
        def inner = new Inner()
        // 内部类定义闭包使用this,则指向内部类
        assert inner.cl() == inner                      
    }
}
class NestedClosures {
    void run() {
        def nestedClosures = {
            def cl = { this }                               
            cl()
        }
        // 闭包嵌套闭包,则this也指向类
        assert nestedClosures() == this                     
    }
}
  • owner: 指向一个封闭的对象,可以是一个类或者闭包
    ownergetOwner()是等价的
    如果闭包定义在内部类中,指向的也是这个内部类
    但是如果owner在嵌套闭包内,则指向的是outer闭包,并非和this一样是类
    总结:和this一样都是返回封闭对象,但是this值包含类,owner包含了闭包和类

  • delegate: 委托可以被赋值成定义的任何对象,默认情况下,delegateowner的指向范围一样
    但是区别是delegate可以被赋于其他对象,而owner则不行

    class Person {
      String name
    }
    class Thing {
      String name
    }
    def p = new Persong(name: "Normal")
    def t = new Thing(name : "Teapot")
    
    def a = { 
      delegate.name.toUpperCase() 
    }
    
    def b = {
      owner.name.toUpperCase()
    }
    
    a.delegate = p 
    a() // output NORMAL
    b.owner = t 
    b() //报错,因为不允许被转为t对象
    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容