groovy 学习笔记

发表信息: by

GROOVY 特殊点

默认导入

  • java.lang
  • java.util
  • java.io
  • java.net
  • java.math.BigDecimal
  • java.math.BigInteger
  • groovy.lang
  • groovy.util

轻量级Java

  • Return 可选
  • 分号分隔符可选
  • 方法和类默认是public
  • ?. 只分派不为null的对象
  • 可以使用具名参数初始化javaBean
  • 不需要捕获自己不关心的异常
  • static方法也可以使用this来引用Class

GROOVY 语法

默认支持JAVA语法,所以所有.groovy文件中可以使用JAVA语法

循环

  • range
for (i in 0..10) {
    println i
}
  • upto
0.upto(10) {
    println it
}

it 是什么? upto方法接受一个闭包参数,如果闭包只需要一个参数,在groovy中可以使用默认的名字it来标示该参数, 切记用

  • times
10.times {
    print(it)
}

times 是默认从0开始,upto 是给定上限

  • step
0.step(10, 2) {
    print(it)
}

步长 0~10 步长2

安全导航操作

  • ?.
def foo(str) {
    str?.reverse()
}

println foo('hello')

str 不为null,则调用 str.reverse(), 这里包含了dolast未默认返回值的动作

异常处理

  • 可以不显式catch异常, 自动向上抛
def openFile(fileName) {
    new FileInputStream(fileName)
}
def openFile(fileName) {
    try {
        new FileInputStream(fileName)
    } catch (ex) {
        println(ex)
    }
}

变量ex前面没有任何类型, 代表可以捕获任何异常, 但是注意: 不能捕获除Exception之外的Error或者Throuwable, 要捕获的话需要显示声明 catch (Trowable th)

javaBean

class Two {
    def final name
    private def address

    Two(name) {
        this.name = name
    }

//    void setAddress(newAddress) {
//        throw new IllegalAccessException("error")
//    }
}

def two = new Two('gc')
// two.name = 'gc2' 会抛异常
two.address = '222' //不会抛异常,如果需要限制, 需要重写 setAddress方法
println("$two.name")
println("$two.address")

灵活的初始化和具名参数

class Two {
    def final name
    private def address
    def x, y, z

//    void setAddress(newAddress) {
//        throw new IllegalAccessException("error")
//    }
}

// def two = new Two(name: 'gc', address: 'add', x: 1, y: 2, z: 3) 会报错,因为这个操作并不是构造器,所以会在构造器之后执行
def two = new Two(address: 'add', x: 1, y: 2, z: 3)
// two.name = 'gc2' 会抛异常
two.address = '222' //不会抛异常,如果需要限制, 需要重写 setAddress方法
println("$two.name")
println("$two.address")
println("$two.z")
println("$two.x")
println("$two.y")
def access(x, y, z) {
    println "$x, $y, $z"
}

access(1, 2, 3)
access(x: 1, y: 2, z: 3, 50, true)
access(50, true, x: 1, y: 2, z: 3)

//1, 2, 3
////[x:1, y:2, z:3], 50, true
////[x:1, y:2, z:3], 50, true

如果groovy方法实参中存在map,则会自动将map传递给第一个形参, 如果要强制哪个参数为map, 可以 access(x, Map y, z) 这样写

可选形参

def access(x, y = 'y', z = 10) {
    println "$x, $y, $z"
}

access(1)

access(1, 2)

access(1, 2, 3)

这里可选形参必须放在参数列表末尾, 方便在固有接口中增加参数,便于接口演进设计

def access(x, y = 'y', z = 10, String[] args) {
    println "$x, $y, $z, $args"
}

access(1)

access(1, 2)

access(1, 2, 3)

access(1, 2, 3, '4', '5')

groovy 可以把参数最末尾的数组列表设置为可选的, 注意数组列表必须放在实参最末尾

多赋值

def access(str1, str2) {
    [str1, str2] // 最后一句未默认返回, 这里必须返回数组
}

def (str1, str2) = access("gc1", "gc2") // 接受返回值的外面可以把数组拆开
def args1 = access("gc1", "gc2") // 也可以不拆开

println("$str1, $str2")
println("$args1")

//gc1, gc2
//[gc1, gc2]

这样交换变量就变得很方便

def access(str1, str2) {
    [str2, str1]
}

def (str1, str2) = access("gc1", "gc2")

println("$str1, $str2")

//gc2 , gc1

如果左侧变量和右侧返回值数量一样,则一一映射,如果右面比左面多,则丢弃, 如果左面比右面多,则附null
如果左面的变量类型为基本类型,则附值为null的时候会抛异常 因为 int x = null 是非法的

实现接口

interface A {
    void aOne(str)

    void aTwo()

    void aThree(str1, str2, str3)
}

def useA(A a) {
    a.aOne("hello")
    a.aTwo()
//    a.aThree(1, 2, 3) // 将会异常, 因为在调用的时候无法区分it到底是哪个参数
}

useA({ println(it) } as A)

/**
 hello
 null
 **/

groovy 并不强制实现接口中的所有方法,只需要实现自己关心的方法就行, 如果确定为未实现的方法永远不会被调用,则没有问题, 否则会有异常

interface A {
    void aOne(str)

    void aTwo()
}

def useA(A a) {
    a.aOne("hello")
    a.aTwo()
}

useA({
    aOne:
    {
        println(it)
    }
    aTwo:
    {
        println("hello world")
    }

} as A)

/**
 hello
 hello world"
 **/

如果要实现的接口中由多个方法且实现姿势不一样,可以用 {methodName: {methodBody}, ....} 的姿势来实现

interface AI {
    void methodOne()
}

interface AII {
    void methodOne(str)
}

class B {
    def useA(AI a) {
        a.methodOne();
    }
}

B b = new B()
def methodName = "useA"
def interfaceName = "AI"

b."$methodName"({ print("hello world") }.asType(Class.forName("$interfaceName"))) // 注意,这里不能使用 '$interfaceName' 单引号

上面的方法使用了动态的实现接口的方法

Bool求值

def bool1 = 1
def bool2 = "hello"
def bool3 = []


if (bool1) {
    print(bool1)
}
if (bool2) {
    print(bool2)
}
if (bool3) {
    print(bool3)
}

groovy 不像java对bool值那么挑剔,以下表中列举了类型与布尔值的对应关系

类型 为真的条件
Boolean true
Collection 集合不为空
Character 值不为0
CharSequence 长度不为0
Iterator hasNext为true
Number double不为0
Map 不为空
Matcher 至少有一个匹配
Object[] 长度大于0
其他任何类型 引用不为null

操作符重载

在groovy中,每一个操作符都映射到一个标准方法,这些方法在java中可以直接使用,在groovy中即可以使用方法,也可以使用操作符