Groovy的隐藏功能?

78 groovy

看起来Groovy在这个帖子中被遗忘了所以我只会问Groovy同样的问题.

  • 尝试限制Groovy核心的答案
  • 每个答案一个功能
  • 举一个示例和该功能的简短描述,而不仅仅是文档的链接
  • 使用粗体标题作为第一行标记要素

也可以看看:

  1. Python的隐藏功能
  2. Ruby的隐藏功能
  3. Perl的隐藏功能
  4. Java的隐藏功能

小智 56

使用spread-dot运算符

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

这是一个捷径animals.collect { it.size() }.

  • 从上下文中,它意味着在每个数组元素上调用size方法并返回结果数组.实际上非常酷:-) (7认同)

Rui*_*ira 39

方法允许把这样的:

 myObj1.setValue(10)
 otherObj.setTitle(myObj1.getName())
 myObj1.setMode(Obj1.MODE_NORMAL)
Run Code Online (Sandbox Code Playgroud)

进入这个

 myObj1.with {
    value = 10
    otherObj.title = name
    mode = MODE_NORMAL
 }
Run Code Online (Sandbox Code Playgroud)

  • 这带给我关于对象pascal的旧记忆:-) (3认同)
  • 请注意构造函数,http://stackoverflow.com/a/7345579/20774 (3认同)

Rob*_*her 37

使用散列作为伪对象.

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

结合鸭子打字,你可以用这种方法走很长的路.甚至不需要甩掉"as"操作符.

  • 对单元测试中的快速模拟非常有用. (5认同)
  • Groovy的新手 - 确实非常好. (2认同)

bil*_*dev 37

有人知道猫王吗?

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)
Run Code Online (Sandbox Code Playgroud)

  • 没有重要的理由,只要遵守OP提出的惯例.当时我没有考虑到我的动作会带来的清新效果. (2认同)

Ted*_*eid 35

找出对象上的方法就像询问metaClass一样简单:

"foo".metaClass.methods.name.sort().unique()
Run Code Online (Sandbox Code Playgroud)

打印:

["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"]
Run Code Online (Sandbox Code Playgroud)


ken*_*ken 28

要拦截缺少的静态方法,请使用以下方法

 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"
Run Code Online (Sandbox Code Playgroud)

-

  • Object Foo没有名为B的静态方法.然而,你可以通过添加一个名为"$ static_methodMissing(String,Object)"的方法来实现一个,并在那里实现你想要的任何东西.每当调用静态方法并且对象没有定义静态方法时,就会调用此魔术方法. (3认同)

小智 24

解构

它可能在Groovy中被称为其他东西; 它被称为clojure中的解构.你永远不会相信它会变得多么方便.

def list = [1, 'bla', false]
def (num, str, bool) = list
assert num == 1
assert str == 'bla'
assert !bool
Run Code Online (Sandbox Code Playgroud)


kro*_*old 21

为了使用groovy测试java代码,对象图构建器非常棒:

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' )
   }
}
Run Code Online (Sandbox Code Playgroud)

标准功能,但仍然非常好.

ObjectGraphBuilder

(您需要提供POJO的任何属性,这些属性List是空列表的默认值,而不是null构建器支持的工作.)


Joh*_*ugh 19

println 
"""
Groovy has "multi-line" strings.
Hooray!
"""
Run Code Online (Sandbox Code Playgroud)

  • 不知道为什么多行字符串需要""作为分隔符时"可以扩展为允许多行和单行字符串. (2认同)
  • @VorgvanGeir使用""表示你不必逃避". (2认同)

Rui*_*ira 15

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

switch(event.source) {
   case object1:
        // do something
        break
   case object2:
        // do something
        break
}
Run Code Online (Sandbox Code Playgroud)


Ted*_*eid 15

在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"]
Run Code Online (Sandbox Code Playgroud)


mmi*_*dol 15

使用宇宙飞船运营商

我喜欢Spaceship运算符,适用于各种自定义排序方案.这里有一些使用示例.其中一个特别有用的情况是使用多个字段在对象的动态创建比较器.例如

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 ]
Run Code Online (Sandbox Code Playgroud)


Joh*_*ugh 14

闭包可以使所有旧的尝试终极资源管理游戏消失.文件流在块结束时自动关闭:

new File("/etc/profile").withReader { r ->
    System.out << r
}
Run Code Online (Sandbox Code Playgroud)


Han*_*eek 13

GDK groovy.transform包内的转换提供的功能,例如:

  • @Immutable:@Immutable注释指示编译器执行AST转换,该转换添加必要的getter,constructors,equals,hashCode和其他辅助方法,这些方法通常在创建具有已定义属性的不可变类时编写.
  • @CompileStatic:这将让Groovy编译器以Java的风格使用编译时检查,然后执行静态编译,从而绕过Groovy元对象协议.
  • @Canonical:@Canonical注释指示编译器执行AST转换,该转换将位置构造函数,equals,hashCode和一个漂亮的打印toString添加到您的类.

其他:

  • @Slf4j此本地转换使用LogBack日志记录为您的程序添加日志记录功能.对名为log的未绑定变量的每个方法调用都将映射到对记录器的调用.
  • Groovy的XML Slurper:轻松解析XML.杀手功能!


Dón*_*nal 12

基于闭包的接口实现

如果您有类型参考,例如:

MyInterface foo
Run Code Online (Sandbox Code Playgroud)

您可以使用以下方法实现整个界面:

foo = {Object[] args -> println "This closure will be called by ALL methods"} as MyInterface
Run Code Online (Sandbox Code Playgroud)

或者,如果要单独实现每个方法,可以使用:

foo = [bar: {-> println "bar invoked"}, 
    baz: {param1 -> println "baz invoked with param $param1"}] as MyInterface
Run Code Online (Sandbox Code Playgroud)


ken*_*ken 12

您可以使用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']
Run Code Online (Sandbox Code Playgroud)


小智 8

null从列表中删除值

def list = [obj1, obj2, null, obj4, null, obj6]
list -= null
assert list == [obj1, obj2, obj4, obj6]
Run Code Online (Sandbox Code Playgroud)


Omn*_*ent 7

@代表

class Foo {
    def footest() { return "footest"}   
}

class Bar {
    @Delegate Foo foo = new Foo()     
}

def bar = new Bar()

assert "footest" == bar.footest()
Run Code Online (Sandbox Code Playgroud)


mic*_*cha 7

我知道我有点晚了,但我认为这里有一些很好的功能:

集合加/减运算符

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]
Run Code Online (Sandbox Code Playgroud)

切换声明

switch (42) {
  case 0: .. break
  case 1..9: .. break
  case Float: .. break
  case { it % 4 == 0 }: .. break
  case ~/\d+/: .. break
}
Run Code Online (Sandbox Code Playgroud)

范围和索引

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']
Run Code Online (Sandbox Code Playgroud)

Unicode变量名称

def ? = 123
def ? = 456
def ? = ? * ?
assert ? == 56088
Run Code Online (Sandbox Code Playgroud)


Pan*_*nde 6

字面上的下划线

在编写长字面数字时,很难弄清楚某些数字是如何组合在一起的,例如成千上万的单词组等.通过允许您在数字文字中放置下划线,可以更容易地发现这些组:

long creditCardNumber = 1234_5678_9012_3456L
long socialSecurityNumbers = 999_99_9999L
double monetaryAmount = 12_345_132.12
long hexBytes = 0xFF_EC_DE_5E
long hexWords = 0xFFEC_DE5E
long maxLong = 0x7fff_ffff_ffff_ffffL
long alsoMaxLong = 9_223_372_036_854_775_807L
long bytes = 0b11010010_01101001_10010100_10010010
Run Code Online (Sandbox Code Playgroud)


Rob*_*her 5

使用隐式参数重新排序的参数是另一个很好的参数.

这段代码:

def foo(Map m=[:], String msg, int val, Closure c={}) {
  [...]
}
Run Code Online (Sandbox Code Playgroud)

创建所有这些不同的方法:

foo("msg", 2, x:1, y:2)
foo(x:1, y:2, "blah", 2)
foo("blah", x:1, 2, y:2) { [...] }
foo("blah", 2) { [...] }
Run Code Online (Sandbox Code Playgroud)

和更多.将命名和序数参数置于错误的顺序/位置是不可能搞砸的.

当然,在"foo"的定义中,你可以从"String msg"和"int val"中省略"String"和"int" - 为了清楚起见,我把它们留在了里面.