Groovy的隐藏特性?

Groovy的隐藏特性?,groovy,Groovy,似乎Groovy在这个线程中被遗忘了,所以我只想问Groovy同样的问题 尝试将答案限制在Groovy core上 每个答案一个功能 给出该功能的示例和简短描述,而不仅仅是文档链接 使用粗体标题作为第一行标记要素 另见: 使用散列作为伪对象 def x = [foo:1, bar:{-> println "Hello, world!"}] x.foo x.bar() 与duck类型相结合,您可以使用这种方法走很长的路。甚至不需要使用“as”操作符。使用扩展点操作符 def a

似乎Groovy在这个线程中被遗忘了,所以我只想问Groovy同样的问题

  • 尝试将答案限制在Groovy core上
  • 每个答案一个功能
  • 给出该功能的示例和简短描述,而不仅仅是文档链接
  • 使用粗体标题作为第一行标记要素
另见:


  • 使用散列作为伪对象

    def x = [foo:1, bar:{-> println "Hello, world!"}]
    x.foo
    x.bar()
    

    与duck类型相结合,您可以使用这种方法走很长的路。甚至不需要使用“as”操作符。

    使用扩展点操作符

    def animals = ['ant', 'buffalo', 'canary', 'dog']
    assert animals.size() == 4
    assert animals*.size() == [3, 7, 6, 3]
    

    这是
    animals.collect{it.size()

    此代码:

    def foo(Map m=[:], String msg, int val, Closure c={}) {
      [...]
    }
    
    创建所有这些不同的方法:

    foo("msg", 2, x:1, y:2)
    foo(x:1, y:2, "blah", 2)
    foo("blah", x:1, 2, y:2) { [...] }
    foo("blah", 2) { [...] }
    
    还有更多。把命名参数和顺序参数放在错误的顺序/位置是不可能搞砸的


    当然,在“foo”的定义中,你可以从“String msg”和“int val”中去掉“String”和“int”——我把它们放在这里只是为了清楚起见。

    有人知道猫王吗

    def d = "hello";
    def obj = null;
    
    def obj2 = obj ?: d;   // sets obj2 to default
    obj = "world"
    
    def obj3 = obj ?: d;  // sets obj3 to obj (since it's non-null)
    

    对于使用groovy测试java代码,object graph builder非常出色:

    def company = builder.company( name: 'ACME' ) {
       address( id: 'a1', line1: '123 Groovy Rd', zip: 12345, state: 'JV' )
       employee(  name: 'Duke', employeeId: 1 ){
          address( refId: 'a1' )
       }
    }
    
    标准功能,但仍然非常好


    (您确实需要为POJO的
    List
    s属性指定一个空列表的默认值,而不是
    null
    ,以便构建器支持工作。)

    与Java不同,在Groovy中,任何东西都可以在switch语句中使用,而不仅仅是原语类型。 在典型的eventPerformed方法中


    with方法允许将此设置为:

     myObj1.setValue(10)
     otherObj.setTitle(myObj1.getName())
     myObj1.setMode(Obj1.MODE_NORMAL)
    
    进入这个

     myObj1.with {
        value = 10
        otherObj.title = name
        mode = MODE_NORMAL
     }
    

    闭包可以让所有旧的资源管理游戏消失。文件流在块结束时自动关闭:

    new File("/etc/profile").withReader { r ->
        System.out << r
    }
    
    新文件(“/etc/profile”)。带读卡器{r->
    
    System.out在groovy 1.6中,正则表达式与所有闭包迭代器(如每个、收集、注入等)一起工作,并允许您轻松地使用捕获组:

    def filePaths = """
    /tmp/file.txt
    /usr/bin/dummy.txt
    """
    
    assert (filePaths =~ /(.*)\/(.*)/).collect { full, path, file -> 
            "$file -> $path"
        } ==  ["file.txt -> /tmp", "dummy.txt -> /usr/bin"]
    

    找出对象上的方法与询问元类一样简单:

    "foo".metaClass.methods.name.sort().unique()
    
    印刷品:

    ["charAt", "codePointAt", "codePointBefore", "codePointCount", "compareTo",
     "compareToIgnoreCase", "concat", "contains", "contentEquals", "copyValueOf", 
     "endsWith", "equals", "equalsIgnoreCase", "format", "getBytes", "getChars", 
     "getClass", "hashCode", "indexOf", "intern", "lastIndexOf", "length", "matches", 
     "notify", "notifyAll", "offsetByCodePoints", "regionMatches", "replace", 
     "replaceAll", "replaceFirst", "split", "startsWith", "subSequence", "substring", 
     "toCharArray", "toLowerCase", "toString", "toUpperCase", "trim", "valueOf", "wait"]
    

    基于闭包的接口实现

    如果您有键入的引用,例如:

    MyInterface foo
    
    您可以使用以下方法实现整个接口:

    foo = {Object[] args -> println "This closure will be called by ALL methods"} as MyInterface
    
    或者,如果要单独实现每个方法,可以使用:

    foo = [bar: {-> println "bar invoked"}, 
        baz: {param1 -> println "baz invoked with param $param1"}] as MyInterface
    

    要截取缺少的静态方法,请使用以下命令

     Foo {
        static A() { println "I'm A"}
    
         static $static_methodMissing(String name, args) {
            println "Missing static $name"
         }
     }
    
    Foo.A()  //prints "I'm A"
    Foo.B()  //prints "Missing static B"
    

    -Ken

    您可以使用toSpreadMap()将列表转换为地图,在列表中的顺序足以确定键和与键相关的值时非常方便。请参见下面的示例

    def list = ['key', 'value', 'foo', 'bar'] as Object[]
    def map = list.toSpreadMap()
    
    assert 2 == map.size()
    assert 'value' == map.key
    assert 'bar' == map['foo']
    

    使用太空船操作员

    def animals = ['ant', 'buffalo', 'canary', 'dog']
    assert animals.size() == 4
    assert animals*.size() == [3, 7, 6, 3]
    
    我喜欢,对各种自定义排序场景都很有用。一些使用示例如下。其中一种特别有用的情况是使用多个字段动态创建对象的比较器

    def list = [
        [ id:0, first: 'Michael', last: 'Smith', age: 23 ],
        [ id:1, first: 'John', last: 'Smith', age: 30 ],
        [ id:2, first: 'Michael', last: 'Smith', age: 15 ],    
        [ id:3, first: 'Michael', last: 'Jones', age: 15 ],   
    ]
    
    // sort list by last name, then first name, then by descending age
    assert (list.sort { a,b -> a.last <=> b.last ?: a.first <=> b.first ?: b.age <=> a.age })*.id == [ 3,1,0,2 ]
    
    def列表=[
    [id:0,第一个:“迈克尔”,最后一个:“史密斯”,年龄:23],
    [id:1,第一个是约翰,最后一个是史密斯,年龄:30],
    [id:2,第一个是迈克尔,最后一个是史密斯,年龄:15],
    [id:3,第一个是迈克尔,最后一个是琼斯,年龄:15],
    ]
    //按姓氏,然后按名字,然后按年龄递减对列表进行排序
    断言(list.sort{a,b->a.last b.last?:a.first b.first?:b.age a.age})*.id=[3,1,0,2]
    
    我认为它是闭包作为参数和参数默认值的组合:

    public void buyItems(Collection list, Closure except={it > 0}){
      list.findAll(){except(it)}.each(){print it}
    }
    buyItems([1,2,3]){it > 2}
    buyItems([0,1,2])
    

    打印:“312”

    解构

    assert (1..10).step(2) == [1, 3, 5, 7, 9]
    assert (1..10)[1, 4..8] == [2, 5, 6, 7, 8, 9]
    assert ('a'..'g')[-4..-2] == ['d', 'e', 'f']
    
    在Groovy中它可能被称为其他东西;在clojure中它被称为解构。你永远不会相信它有多方便

    def list = [1, 'bla', false]
    def (num, str, bool) = list
    assert num == 1
    assert str == 'bla'
    assert !bool
    

    Groovy的工作原理很像Javascript,可以通过闭包拥有私有变量和函数。 您还可以使用闭包来实现函数

    class FunctionTests {
    
    def privateAccessWithClosure = {
    
        def privVar = 'foo'
    
        def privateFunc = { x -> println "${privVar} ${x}"}
    
        return {x -> privateFunc(x) } 
    }
    
    
    def addTogether = { x, y ->
        return x + y
    }
    
    def curryAdd = { x ->
        return { y-> addTogether(x,y)}
    }
    
    public static void main(String[] args) {
        def test = new FunctionTests()
    
        test.privateAccessWithClosure()('bar')
    
        def curried = test.curryAdd(5)
    
        println curried(5)
    }
    }
    
    输出:

    富吧
    10

    在方法参数中使用扩展运算符

    def l = [1, 2, 3] + [4, 5, 6] - [2, 5] - 3 + (7..9)
    assert l == [1, 4, 6, 7, 8, 9]
    
    def m = [a: 1, b: 2] + [c: 3] - [a: 1]
    assert m == [b: 2, c: 3]
    
    def α = 123
    def β = 456
    def Ω = α * β
    assert Ω == 56088
    
    这对将代码转换为数据有很大帮助:

    def exec(operand1,operand2,Closure op) {
        op.call(operand1,operand2)
    }
    
    def addition = {a,b->a+b}
    def multiplication = {a,b->a*b}
    
    def instructions = [
         [1,2,addition],
         [2,2,multiplication]
    ]
    
    instructions.each{instr->
        println exec(*instr)
    }
    
    这种用法也很有用:

    String locale="en_GB"
    
    //this invokes new Locale('en','GB')
    def enGB=new Locale(*locale.split('_'))
    

    GDK的
    groovy.transform
    包中的转换提供的特性,例如:

    • :@Immutable注释指示编译器执行AST转换,该转换添加必要的getter、constructor、equals、hashCode和其他助手方法,这些方法通常在创建具有定义属性的不可变类时编写
    • :这将允许Groovy编译器使用Java风格的编译时检查,然后执行静态编译,从而绕过Groovy元对象协议
    • :@Canonical注释指示编译器执行AST转换,该转换向类中添加位置构造函数、equals、hashCode和漂亮的print-to字符串
    其他:

    • 此本地转换使用LogBack logging为程序添加日志功能。对名为log的未绑定变量的每个方法调用都将映射到对logger的调用
    • :轻松解析XML。杀手级功能


    我知道我有点晚了,但我认为这里缺少一些不错的功能:

    集合加减运算符

    def l = [1, 2, 3] + [4, 5, 6] - [2, 5] - 3 + (7..9)
    assert l == [1, 4, 6, 7, 8, 9]
    
    def m = [a: 1, b: 2] + [c: 3] - [a: 1]
    assert m == [b: 2, c: 3]
    
    def α = 123
    def β = 456
    def Ω = α * β
    assert Ω == 56088
    
    开关语句

    switch (42) {
      case 0: .. break
      case 1..9: .. break
      case Float: .. break
      case { it % 4 == 0 }: .. break
      case ~/\d+/: .. break
    }
    
    范围和索引

    assert (1..10).step(2) == [1, 3, 5, 7, 9]
    assert (1..10)[1, 4..8] == [2, 5, 6, 7, 8, 9]
    assert ('a'..'g')[-4..-2] == ['d', 'e', 'f']
    
    Unicode变量名

    def l = [1, 2, 3] + [4, 5, 6] - [2, 5] - 3 + (7..9)
    assert l == [1, 4, 6, 7, 8, 9]
    
    def m = [a: 1, b: 2] + [c: 3] - [a: 1]
    assert m == [b: 2, c: 3]
    
    def α = 123
    def β = 456
    def Ω = α * β
    assert Ω == 56088
    

    从列表中删除
    null

    def list = [obj1, obj2, null, obj4, null, obj6]
    list -= null
    assert list == [obj1, obj2, obj4, obj6]
    

    动态方法调用

    可以使用名称为的字符串调用方法

    class Dynamic {
        def one() { println "method one()" }
        def two() { println "method two()" }
    }
    
    def callMethod( obj, methodName ) {
        obj."$methodName"()
    }
    
    def dyn = new Dynamic()
    
    callMethod( dyn, "one" )               //prints 'method one()'
    callMethod( dyn, "two" )               //prints 'method two()'
    dyn."one"()                            //prints 'method one()'
    

    如何在groovy中用几行代码构建JSON树

    1) 使用默认值的自引用
    定义树

    def tree // declare  first before using a self reference
    tree = { ->  [:].withDefault{ tree() } }
    
    2) 创建自己的JSON树

    frameworks = tree()
    frameworks.grails.language.name = 'groovy'
    frameworks.node.language.name = 'js'
    
    def result =  new groovy.json.JsonBuilder(frameworks)
    

    它给出:
    {“grails”:{“language”:{“name”:“groovy”},node:{“language”:{“name”:“js”}}}
    文本下划线

    def l = [1, 2, 3] + [4, 5, 6] - [2, 5] - 3 + (7..9)
    assert l == [1, 4, 6, 7, 8, 9]
    
    def m = [a: 1, b: 2] + [c: 3] - [a: 1]
    assert m == [b: 2, c: 3]
    
    def α = 123
    def β = 456
    def Ω = α * β
    assert Ω == 56088
    
    当写长文字数字时,眼睛很难弄清楚一些数字是如何组合在一起的,例如,用数千个单词组成的组,e
    def (a,b,c) = [1,2,3]
    
    def (String a, int b) = ['Groovy', 1]