Hidden features of Groovy?
似乎groovy在这个线程中被遗忘了,所以我将向groovy提出同样的问题。
- 尝试限制对groovy核心的回答
- 每个答案一个功能
- 给出功能的示例和简短描述,而不仅仅是指向文档的链接
- 用粗体标题作为第一行标记功能
参见:
使用扩散点运算符
1 2 3 |
这是
WITH方法允许转换:
1 2 3 | myObj1.setValue(10) otherObj.setTitle(myObj1.getName()) myObj1.setMode(Obj1.MODE_NORMAL) |
进入这个
1 2 3 4 5 | myObj1.with { value = 10 otherObj.title = name mode = MODE_NORMAL } |
有人知道埃尔维斯吗?
1 2 3 4 5 6 7 |
将哈希用作伪对象。
结合duck输入,您可以使用这种方法进行很长的路。甚至不需要删掉"as"操作符。
找到对象上的方法与询问元类一样简单:
1 |
印刷品:
1 2 3 4 5 6 7 | ["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"] |
To intercept missing static methods use the following
1 2 3 4 5 6 7 8 9 10 |
-肯
破坏
它可能在groovy中被称为其他东西;在clojure中被称为破坏。你永远不会相信它有多有用。
1 2 3 4 5 |
为了用Groovy测试Java代码,对象图形生成器是令人惊异的:
1 2 3 4 5 6 | 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的任何属性指定一个空列表的默认值,而不是
1 2 3 4 5 |
不像Java,在Groovy中,任何东西都可以用在转换语句中,而不仅仅是基元类型。在典型的EventPerformed方法中
1 2 3 4 5 6 7 8 |
在groovy 1.6中,正则表达式与所有闭包迭代器(如每个闭包迭代器、collect、inject等)一起工作,并允许您轻松地使用捕获组:
1 2 3 4 5 6 7 8 |
使用宇宙飞船操作员
我喜欢宇宙飞船操作员,对各种自定义排序场景都很有用。这里有一些用法示例。其中一个特别有用的情况是使用多个字段在对象的运行中创建一个比较器。例如
1 2 3 4 5 6 7 8 9 | 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 ] |
闭包可以使所有旧的资源管理的尝试最终消失。文件流在块末尾自动关闭:
1 2 3 |
由gdk的
@Immutable :@immutable注释指示编译器执行ast转换,该转换添加必要的getter、构造函数、equals、hashcode和其他助手方法,这些方法通常是在创建具有定义属性的不可变类时编写的。@CompileStatic :这将允许Groovy编译器使用Java风格的编译时间检查,然后执行静态编译,从而绕过Groovy元对象协议。@Canonical :@canonical注释指示编译器执行ast转换,该转换将位置构造函数、equals、hashcode和漂亮的print to字符串添加到类中。
其他:
@Slf4j 这个本地转换使用日志记录向程序添加了日志记录功能。对名为log的未绑定变量的每个方法调用都将映射到对记录器的调用。- groovy的xml slurper:易于解析XML。杀手锏!
基于闭包的接口实现
如果您有键入的引用,例如:
1 | MyInterface foo |
您可以使用以下方法实现整个接口:
或者,如果要单独实现每个方法,可以使用:
1 2 3 4 5 6 7 | foo = [bar: {-> println"bar invoked <div class="suo-content">[collapse title=""]<ul><li>缺少右大括号?</li><li>@Edstaub谢谢,修好了</li></ul>[/collapse]</div><hr><P>您可以使用tospreadmap()将列表转换为映射,这在列表中的顺序足以确定键及其关联值时非常方便。见下面的例子。</P>[cc lang="groovy"]def list = ['key', 'value', 'foo', 'bar'] as Object[] def map = list.toSpreadMap() assert 2 == map.size() assert 'value' == map.key assert 'bar' == map['foo'] |
从列表中删除
1 2 3 |
@代表
1 2 3 4 5 6 7 8 9 10 11 |
我知道我有点晚了,但我认为这里缺少一些好的功能:
集合加减运算符
1 2 3 4 5 |
switch语句
1 2 3 4 5 6 7 |
范围和索引
1 2 3 |
Unicode变量名
文字中的下划线
在编写长的文字数字时,很难弄清楚一些数字是如何组合在一起的,例如使用数千个组、单词等。通过允许在数字文字中放置下划线,更容易发现这些组:
1 2 3 4 5 6 7 8 | 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 |
用隐式参数重新排序的参数是另一个不错的参数。
此代码:
创建所有这些不同的方法:
1 2 3 4 | 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",我只是为了清晰起见而把它们放在里面。
在方法参数中使用扩散算子
在将代码转换为数据时,这是一个很好的帮助:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
这一用法也很有用:
1 2 3 4 |
我认为它是闭包作为参数和参数默认值的组合:
1 2 3 4 5 |
印刷品:"312"
记忆化
memoization是一种优化技术,它包括存储昂贵函数调用的结果,并在用相同参数再次调用函数时返回缓存的结果。
有一个不受限制的版本,它将缓存它将看到的任何一对(输入参数,返回值);以及一个有限的版本,它将使用一个LRU缓存缓存看到的最后n个输入参数及其结果。
方法的记忆化:
1 2 3 4 5 6 7 8 9 10 11 |
关闭的记忆:
1 2 3 4 5 6 7 |
维基百科的网页上有大量关于记忆在计算机科学中的应用的信息。我将指出一个简单的实际用途。
将常量的初始化推迟到最后可能的时刻
有时您有一个常量值,它在类定义或创建时无法初始化。例如,常量表达式可以使用另一个常量或来自不同类的方法,这些常量或方法在类初始化后将由其他东西(spring或类似的东西)插入。
在这种情况下,您可以将常量转换为getter,并用
1 2 3 4 5 6 |
groovy可以像javascript一样工作。您可以通过闭包来拥有私有变量和函数。您还可以使用闭包编写函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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) } } |
输出:
起泡棒十
如何在groovy中用几行代码构建JSON树?
1)用自引用
1 2 |
2)创建自己的JSON树
1 2 3 4 5 |
给出:
安全导航操作员
安全导航运算符用于避免NullPointerException。通常,当您引用一个对象时,您可能需要在访问该对象的方法或属性之前验证它不是空的。为了避免这种情况,安全导航操作员只返回空值,而不是抛出异常,如:
1 2 |
动态方法调用
可以使用带名称的字符串调用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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()' |
多变量死亡(P)(1)单线多种变量声明(p)字母名称(P)(2)采用不同类型的声明。(p)字母名称
埃尔维斯算子
"ELVIS运算符"是三元运算符的缩写。如果表达式解析为false(如在groovy truth中),则返回"合理的默认"值很方便。一个简单的例子如下:
使用三元运算符时,必须重复要分配的值
1 | displayCity = user.city ? user.city: 'UnKnown City' |
对于ELVIS运算符,如果不是假值,则使用测试值
1 | displayCity = user.city ?: 'UnKnown City' |
胁迫操作员(P)强迫经营者是一种不同的惩罚形式。Coercion converts object from one type to another without them being comparational for assignment.让我们做一个例子:(p)(P)Integer X=123STRING S=(STRING)xInteger is not assignable to a string,so it will produce a classscatexception at runtime8 This can be fixed by using胁迫:(p)(P)Integer X=123String S=x as stringInteger is not assignable to a string,but use of as will coerce it to a string(p)