似乎Groovy在该线程中被遗忘了,所以我只想向Groovy询问相同的问题。
- 尝试将答案限制在Groovy核心上
- 每个答案一个功能
- 提供功能的示例和简短描述,而不仅仅是文档的链接
- 使用粗体标题作为第一行标记功能
也可以看看:
Answers:
有人知道猫王吗?
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"]
要拦截缺少的静态方法,请使用以下命令
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
对于使用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' )
}
}
标准功能,但仍然非常不错。
(您确实需要提供POJO的任何属性,这些属性List
是空列表的默认值,而不是null
为了使构建器支持正常工作。)
println
"""
Groovy has "multi-line" strings.
Hooray!
"""
与Java不同,在Groovy中,任何东西都可以在switch语句中使用,而不仅仅是原始类型。在典型事件中执行的方法
switch(event.source) {
case object1:
// do something
break
case object2:
// do something
break
}
使用太空飞船操作员
我喜欢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 ]
GDKgroovy.transform
软件包内的转换所提供的功能,例如:
@Immutable
:@Immutable批注指示编译器执行AST转换,该转换添加了必要的getter,构造函数,equals,hashCode和其他在创建具有已定义属性的不可变类时通常编写的辅助方法。@CompileStatic
:这将使Groovy编译器使用Java风格的编译时检查,然后执行静态编译,从而绕过Groovy元对象协议。@Canonical
:@Canonical批注指示编译器执行AST转换,该转换将位置构造函数,equals,hashCode和漂亮的toString添加到类中。其他:
@Slf4j
此本地转换使用LogBack日志记录为您的程序添加了日志记录功能。对名为log的未绑定变量的每个方法调用都将映射到对记录器的调用。我知道我来晚了,但我认为这里缺少一些不错的功能:
集合正负运算符
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']
Unicode变量名称
def α = 123
def β = 456
def Ω = α * β
assert Ω == 56088
在文字下划线
在编写长文字数字时,很难确定一些数字是如何组合在一起的,例如,成千上万的单词,单词等的组合。通过允许在数字文字中加下划线,可以更容易地发现这些组:
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
使用隐式参数对参数进行重新排序是另一个不错的选择。
这段代码:
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 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('_'))
记忆化
记忆化是一种优化技术,其中包括存储昂贵的函数调用的结果,并在每次使用相同参数再次调用该函数时返回缓存的结果。
有一个无限的版本,它将缓存它将看到的每对(输入参数,返回值);以及有限版本,它将使用LRU缓存来缓存最后看到的N个输入参数及其结果。
记忆方法:
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
}
闭包的记忆:
def factorial = {Number n ->
n == 0 ? 1 : factorial(n - 1)
}.memoize()
fooDetails = {Foo foo ->
// call expensive service here
}.memoizeAtMost(1000)
维基百科页面上有关于计算机科学中记忆化用法的广泛信息。我只是指出一种简单的实际用途。
将常量的初始化推迟到最后一个可能的时刻
有时,您有一个常量值,无法在类定义或创建时初始化。例如,常量表达式可以使用另一个常量或来自不同类的方法,该类将在初始化类后由其他东西(例如Spring等)插入。
在这种情况下,您可以将常量转换为吸气剂并用修饰它@Memoized
。它只会被计算一次,第一次被访问,然后值被缓存和重用:
import groovy.transform.Memoized
@Memoized
def getMY_CONSTANT() {
// compute the constant value using any external services needed
}
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)
}
}
输出:
foo bar 10
动态方法调用
您可以使用名称为字符串的方法来调用方法
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)使用自引用withDefault
闭包定义树
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"}}}
安全导航员
安全导航运算符用于避免NullPointerException。通常,当您具有对对象的引用时,可能需要在访问对象的方法或属性之前验证其是否为null。为了避免这种情况,安全的导航运算符将只返回null而不是引发异常,例如:
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
1)单行中有多个变量声明
def (a,b,c) = [1,2,3]
2)使用不同的类型声明。
def (String a, int b) = ['Groovy', 1]