Groovy的隐藏function?

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

  • 尝试限制对Groovy核心的回答
  • 每个答案一个function
  • 给出一个示例和function的简短描述,而不仅仅是文档的链接
  • 作为第一行使用粗体标题标记function

也可以看看:

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

使用散点算子

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

这是animals.collect { it.size() }的快捷方式。

with方法允许把这个变成:

  myObj1.setValue(10) otherObj.setTitle(myObj1.getName()) myObj1.setMode(Obj1.MODE_NORMAL) 

进入这个

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

使用散列作为伪对象。

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

结合鸭子打字,你可以用这种方法很长的路要走。 甚至不需要掏出“as”操作符。

任何人都知道猫王

 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) 

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

 "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"] 

拦截缺less的静态方法使用以下内容

  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" 

解构

Groovy可能被称为别的东西; 这叫clojure的解构。 你永远不会相信它会多么得心应手。

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

为了用groovytestingjava代码,对象图生成器是惊人的:

 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' ) } } 

标准function,但仍然非常好。

ObjectGraphBuilder

(你需要给你的POJO的任何属性List一个空列表的默认值,而不是null的build设者支持工作。)

 println """ Groovy has "multi-line" strings. Hooray! """ 

在groovy 1.6中,正则expression式和所有的闭包迭代器(比如each,collect,inject等等)一起工作,并且可以让你轻松的使用捕获组:

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

与Java不同,在Groovy中,任何东西都可以用在switch语句中,而不仅仅是基本types。 在一个典型的eventPerformed方法中

 switch(event.source) { case object1: // do something break case object2: // do something break } 

使用飞船操作员

我喜欢Spaceship操作符 ,对于各种自定义sorting场景很有用。 使用的一些例子在这里 。 其中特别有用的一种情况是使用多个字段在对象的基础上创build比较器。 例如

 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 ] 

closures可以使所有旧的尝试最后的资源pipe理游戏消失。 文件stream在块的末尾自动closures:

 new File("/etc/profile").withReader { r -> System.out << r } 

GDK的groovy.transform包中的转换提供的function,如:

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

其他:

  • @Slf4j这个本地转换使用LogBack日志logging为您的程序添加了一个日志loggingfunction。 调用一个名为log的未绑定variables的每个方法都将映射到对logging器的调用。
  • Groovy的XML Slurper :轻松parsingXML。 杀手function!

您可以使用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'] 

基于闭包的接口实现

如果您有一个types的参考,如:

 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 

从列表中删除null

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

我知道我有点晚,但我认为这里有一些不错的function:

集合加/减运算符

 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] 

切换语句

 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'] 

Unicodevariables名称

 def α = 123 def β = 456 def Ω = α * β assert Ω == 56088 

@代表

 class Foo { def footest() { return "footest"} } class Bar { @Delegate Foo foo = new Foo() } def bar = new Bar() assert "footest" == bar.footest() 

文字下划线

在编写长文字数字时,眼睛难以弄清楚某些数字是如何分组在一起的,例如几千个词组等等。通过允许您在数字文字中放置下划线,可以更容易地发现这些组:

 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 

使用隐式参数重新sorting的参数是另一个不错的参数。

此代码:

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

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

 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” – 为了清楚起见,我将它们留下。

我认为这是一个闭包作为参数和参数默认值的组合:

 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”

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

将代码转换为数据时,这非常有帮助:

 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('_')) 

记忆化

Memoization是一种优化技术,它存储昂贵的函数调用的结果,并在每次使用相同的参数再次调用函数时返回caching的结果。

有一个无限的版本,它会caching它永远会看到的一对(input参数,返回值); 和一个有限的版本,它将使用一个LRUcaching来caching看到的最后N个input参数及其结果。

方法的记忆:

 import groovy.transform.Memoized @Memoized Number factorial(Number n) { n == 0 ? 1 : factorial(n - 1) } @Memoized(maxCacheSize=1000) Map fooDetails(Foo foo) { // call expensive service here } 

loggingclosures:

 def factorial = {Number n -> n == 0 ? 1 : factorial(n - 1) }.memoize() fooDetails = {Foo foo -> // call expensive service here }.memoizeAtMost(1000) 

维基百科页面具有关于Memoization在计算机科学中使用的大量信息。 我只想指出一个简单的实际用法。

推迟一个常量的初始化到最后一刻

有时你有一个不能在类定义或创build时初始化的常量值。 例如,常量expression式可能会使用另一个常量或来自不同类的方法,在您的类的初始化之后,它将被别的东西(Spring或类似的东西)所插入。

在这种情况下,你可以把你的常量转换成一个getter并用@Memoized装饰它。 它只会被计算一次,第一次被访问,然后caching和重用值:

 import groovy.transform.Memoized @Memoized def getMY_CONSTANT() { // compute the constant value using any external services needed } 

Groovy可以像Javascript一样工作。 你可以通过closures私人variables和function。 您也可以通过closuresfunction来咖喱function。

 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) } } 

输出:

foo吧10

dynamic方法调用

您可以使用名称的string调用一个方法

 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的几行build立一个JSON树?

1)用withDefaultclosures来定义你的树

 def tree // declare first before using a self reference tree = { -> [:].withDefault{ tree() } } 

2)创build你自己的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"}}}

安全导航操作员

安全导航运算符用于避免NullPointerException。 通常当你有一个对象的引用时,你可能需要在访问对象的方法或属性之前validation它是否为空。 为了避免这种情况,安全导航操作符将简单地返回null而不是抛出exception,如下所示:

 def person = Person.find { it.id == 123 } // find will return a null instance def name = person?.name // use of the null-safe operator prevents from a NullPointerException, result is null 

多variables减速

1)单行中的多个variables声明

 def (a,b,c) = [1,2,3] 

2)使用不同的types声明。

 def (String a, int b) = ['Groovy', 1] 

强制操作符

强制操作符(as)是铸造的变体。 强制转换将对象从一种types转换为另一种types,而不能与赋值兼容。 举个例子:

整数x = 123
String s =(String)x
整数不能分配给一个string,所以它会在运行时产生一个ClassCastException这可以通过使用强制来解决:

整数x = 123 String s = x作为string
整数不能分配给一个string,但使用as将它强制为一个string