美文网首页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