美文网首页Java 杂谈
Groovy不了解一下吗?

Groovy不了解一下吗?

作者: 梦中睡觉的巴子 | 来源:发表于2019-08-25 11:15 被阅读1次

最近听说用Groovy写单元测试很爽,来凑个热闹,尽可能短,尽可能少,没明说的就当Java来写就好。

国际惯例Hello World

关于Groovy的东西就不鬼扯了,反正就是一个基于JVM的没火起来的语言,进入正题

class GroovyTut {
    static void main(String[] args)
        println("Hello Groovy!") // 可以没有分号!
    }    
}

其实,还可以这样:

print("Hello Groovy!")

但由于Groovy本质是基于JVM的,所以最终这行代码还是会被包裹在一个自动生成的类里面。

一些有必要知道的特性

  1. 默认访问修饰符是public
  2. groovy根据实参类型选择方法(动态分派),Java则根据声明类型,两者恰恰相反
  3. groovy的==可以看作是Java的equals

变量

def a = "test" //自动推导变量类型
int b = 32 // 也可以像Java一样定义变量

跟很多动态语言很类似,至于其确切类型的种类,嗯,就是你想的那样,和Java类型基本一样。

字符串

def a = 'test' // String类型

def b = "插值字符串:${a}"

def c = "还可以插入表达式:${1+3+4}"

def d = "甚至还可以插入语句:${def a = 1; def b = 2; a + b}" // 一般不建议玩这么花

println(b) // 插值字符串:test

char d = 'd' // 至于真正的字符类型要显式声明或者强转

不得不说,这个特性贼有模板语言既视感。
单引号表示普通字符串,插值字符串要用双引号。

方法

String func(){
    return "test"
}

assert func() == "test"

def func2(){
    "test"  // 返回最后一条语句结果
}

assert func2() == "test"

返回类型可以用 def 代替(可以把def看作类型的占位符),返回值 return 可以省略。

def add(a, b){
    a + b
}

参数类型也可以被省略,默认为 Object 类型
在Java里,两个Object类型相加也是不容许的,但在Groovy里可以,因为如果传入字符串类型或者算术类型,这个操作显然合理,但是Java则会自始自终把参数当成Object来看,多得不说了,懂得都懂。
这也是Groovy一种动态性的体现,简单来说也就是程序不跑起来都不知道你是对是错。

闭包

我也不知道为什么叫闭包,在我的理解里闭包是一种机制也是一种操作,但Groovy里所谓的闭包(closure)其实更像是一个函数对象,而事实上它也确实是groovy.lang.Closure类的实例
闭包语法如下,与Java8的lambda非常类似:

//闭包的参数为可选项
def closure = { [closureParameters -> ] statements }
def closure = { println("test") } //没参数可以省略 ->

def closure1 = { int a, int b -> a + b} //多个参数

def closure2 = { println(it) } //只有一个参数可省略,Groovy提供隐式参数it

调用闭包:

def closure = {
    param -> println param
}
 
closure('hello') //直接把闭包变量当方法
closure.call('hello') //把闭包变量当实例对象
closure 'hello' // 当成关键字

这个机制(语法糖)还是很给力的。

List

def numbers = [1, 2, 3]

其实就是ArrayList,不过这么定义真让我找到一丝Python的爽感。

Array

语法和List类似,不过要指定数组类型

String[] arrStr = ['Ananas', 'Banana', 'Kiwi'] //直接声明类型为数组类型  String[]

assert arrStr instanceof String[]    
assert !(arrStr instanceof List)

def numArr = [1, 2, 3] as int[]     //痛过as关键字指定类型为数组类型 int[] 

assert numArr instanceof int[]       
assert numArr.size() == 3

Map

/ key虽然没有加引号,不过Groovy会默认将其转换为字符串
def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']

assert colors['red'] == '#FF0000' // 使用中括号访问
assert colors.green == '#00FF00' // 使用点表达式访问

colors['pink'] = '#FF00FF' // 使用中括号添加元素,相当于Java Map 的 put(key,value)方法
colors.yellow = '#FFFF00'// 使用点表达式添加元素
assert colors.pink == '#FF00FF'
assert colors['yellow'] == '#FFFF00'
assert colors instanceof java.util.LinkedHashMap // 默认使用LinkedHashMap类型

// Groovy Map的key默认语法不支持变量,这里的key实际上是字符串'keyVal'而不是keyVal变量的值'name'
def keyVal = 'name'
def persons = [keyVal: 'Guillaume'] 
assert !persons.containsKey('name')
assert persons.containsKey('keyVal')

//要使用变量作为key,需要使用括号
def keyVal = 'name'
def persons = [(keyVal): 'Guillaume'] 
assert persons.containsKey('name')
assert !persons.containsKey('keyVal')

Groovy中的Map其实就是java.util.LinkedHashMap

Range

在 Groovy 中可以使用..操作符来定义一个区间对象,简化范围操作的代码。

def range = 0..5
assert (0..5).collect() == [0, 1, 2, 3, 4, 5]
assert (0..<5).collect() == [0, 1, 2, 3, 4] // 相当于左闭右开区间
assert (0..5) instanceof List // Range实际上是List接口的实现
assert (0..5).size() == 6
assert ('a'..'d').collect() == ['a','b','c','d']//也可以是字符类型

//常见使用场景
for (x in 1..10) {
    println x
}

('a'..'z').each {
    println it
}

def age = 25;
switch (age) {
    case 0..17:
        println '未成年'
        break
    case 18..30:
        println '青年'
        break
    case 31..50:
        println '中年'
        break
    default:
        println '老年'
}

说实话,switch这么玩我看傻了

命名参数

class PersonWOConstructor {                                  
    String name
    Integer age
}

def person4 = new PersonWOConstructor()                      
def person5 = new PersonWOConstructor(name: 'Marie')         
def person6 = new PersonWOConstructor(age: 1)                
def person7 = new PersonWOConstructor(name: 'Marie', age: 2)

可以不定义构造器,如果要使用位置参数则要定义对应构造器。

Spread运算符*

可用于集合对象,相当于对每一个元素操作并将结果收集为一个List。


class Person{
    String name;
    Integer age;
}

def persons = [
        new Person(name : "Kevin", age : 20),
        new Person(name : "bob", age : 30),
]

def names= persons*.name

println(names) //[Kevin, bob]

这玩意还能用在任何实现了Iterable接口的类对象上:

class Component {
    Long id
    String name
}
class CompositeObject implements Iterable<Component> {
    def components = [
        new Component(id: 1, name: 'Foo'),
        new Component(id: 2, name: 'Bar')]

    @Override
    Iterator<Component> iterator() {
        components.iterator()
    }
}
def composite = new CompositeObject()
assert composite*.id == [1,2]
assert composite*.name == ['Foo','Bar']

还能用来传参:

def func(a, b, c){
    a + b + c
}

def params = [1, 2, 3]

println(func(*params)) // 6

还能扩充List和Map

def items = [4,5]                      
def list = [1,2,3,*items,6]            
assert list == [1,2,3,4,5,6]  

def m1 = [c:3, d:4]                   
def map = [a:1, b:2, *:m1]            
assert map == [a:1, b:2, c:3, d:4] 

重载运算符!

class Person{
    String name;

    Person plus(obj){
        return new Person(name:this.name + obj.name)
    }

}
Person person=new Person(name : "kevin")
Person person1 =new Person(name :  "test")

println((person + person1).name)

绝大多数的运算符都能重载,对应的函数名就不多费口舌了。

相关文章

网友评论

    本文标题:Groovy不了解一下吗?

    本文链接:https://www.haomeiwen.com/subject/mpkcectx.html