Groovy的隐藏function?
Groovy似乎在这个线程中被遗忘了,所以我只会问Groovy同样的问题。
- 尝试限制对Groovy核心的回答
- 每个答案一个function
- 给出一个示例和function的简短描述,而不仅仅是文档的链接
- 作为第一行使用粗体标题标记function
也可以看看:
- Python的隐藏function
- Ruby的隐藏function
- Perl的隐藏function
- 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)用withDefault
closures来定义你的树
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