このスレッドではGroovyが忘れられたようですので、Groovyについても同じ質問をします。
参照:
スプレッドドット演算子を使用
_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 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)
疑似オブジェクトとしてハッシュを使用する。
def x = [foo:1, bar:{-> println "Hello, world!"}]
x.foo
x.bar()
ダックタイピングと組み合わせると、このアプローチで大いに役立つことができます。 「as」演算子を削除する必要はありません。
オブジェクトにあるメソッドを見つけるのは、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
Java groovyを使用したコードをテストする場合、オブジェクトグラフビルダーは素晴らしいです:
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
sのデフォルト値にする必要があります。)
println
"""
Groovy has "multi-line" strings.
Hooray!
"""
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"]
宇宙船オペレーターの使用
私は 宇宙船演算子 が好きで、あらゆる種類のカスタムソートシナリオに役立ちます。使用例のいくつかは ここ です。特に役立つ状況の1つは、複数のフィールドを使用してオブジェクトのオンザフライでコンパレータを作成することです。例えば.
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 ]
Javaとは異なり、Groovyでは、プリミティブ型だけでなく、switchステートメントで何でも使用できます。典型的なeventPerformedメソッド
switch(event.source) {
case object1:
// do something
break
case object2:
// do something
break
}
閉鎖により、リソース管理の古い試行錯誤のゲームがすべてなくなる可能性があります。ファイルストリームは、ブロックの最後で自動的に閉じられます。
new File("/etc/profile").withReader { r ->
System.out << r
}
GDK内の変換によって提供される機能groovy.transform
パッケージなど:
@Immutable
:@ Immutableアノテーションは、コンパイラにAST変換を実行するように指示します。これにより、必要なゲッター、コンストラクター、equals、hashCode、および不変クラスの作成時に通常記述されるその他のヘルパーメソッドが追加されます。定義されたプロパティを使用します。@CompileStatic
:これにより、GroovyコンパイラーはJavaのスタイルでコンパイル時チェックを使用し、静的コンパイルを実行して、Groovyメタオブジェクトプロトコルをバイパスします。@Canonical
:@ Canonicalアノテーションは、コンパイラーにAST変換を実行するように指示します。これにより、位置コンストラクター、equals、hashCode、およびプリティプリントtoStringがクラスに追加されます。その他:
@Slf4j
このローカル変換は、LogBackロギングを使用してプログラムにロギング機能を追加します。 logという名前のバインドされていない変数に対するすべてのメソッド呼び出しは、ロガーへの呼び出しにマップされます。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']
クロージャーベースのインターフェースの実装
次のような型指定された参照がある場合:
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]
class Foo {
def footest() { return "footest"}
}
class Bar {
@Delegate Foo foo = new Foo()
}
def bar = new Bar()
assert "footest" == bar.footest()
私は少し遅れていることを知っていますが、ここにはいくつかの素晴らしい機能が欠けていると思います:
コレクションのプラス/マイナス演算子
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ステートメント
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']
nicode変数名
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
暗黙の引数を使用した引数の並べ替えも、もう1つの優れた方法です。
このコード:
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」の定義では、「Stringmsg」と「intval」から「String」と「int」を省略できます。わかりやすくするために省略しました。
メソッドパラメータでspread演算子を使用
これは、コードをデータに変換するときに非常に役立ちます。
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('_'))
パラメータとしてのクロージャとparameter-default-valuesの組み合わせだと思います。
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」
メモ化
メモ化は、コストのかかる関数呼び出しの結果を保存し、同じ引数を使用して関数が再度呼び出されるたびにキャッシュされた結果を返すことで構成される最適化手法です。
無制限のバージョンがあり、これまでに表示される(入力引数、戻り値)のペアをキャッシュします。限定バージョン。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)
ウィキペディアのページ コンピュータサイエンスでのメモ化の使用に関する広範な情報があります。簡単な実用的な使い方を1つだけ指摘します。
定数の初期化を可能な限り最後の瞬間まで延期する
クラス定義時または作成時に初期化できない定数値がある場合があります。たとえば、定数式は、別の定数または別のクラスのメソッドを使用する場合があります。これらは、クラスの初期化後に他の何か(Springなど)によってプラグインされます。
この場合、定数をゲッターに変換し、@Memoized
で装飾することができます。最初にアクセスされたときに1回だけ計算され、次に値がキャッシュされて再利用されます。
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)1行での複数の変数宣言
def (a,b,c) = [1,2,3]
2)異なる型宣言を使用する。
def (String a, int b) = ['Groovy', 1]
"エルビス演算子"は三項演算子の短縮形です。これが便利な例の1つは、式がfalseに解決された場合に「適切なデフォルト」値を返す場合です(Groovyの真実のように)。簡単な例は次のようになります。
三項演算子を使用すると、割り当てたい値を繰り返す必要があります
displayCity = user.city ? user.city: 'UnKnown City'
エルビス演算子を使用すると、テストされた値がfalseでない場合に使用されます
displayCity = user.city ?: 'UnKnown City'
強制演算子(as)は、キャストの変形です。 Coercionは、オブジェクトをあるタイプから別のタイプに変換しますが、割り当てに互換性はありません。例を見てみましょう:
整数x = 123
String s =(String)x
整数は文字列に割り当てることができないため、実行時にClassCastExceptionが生成されますこれは、代わりに強制を使用して修正できます。
整数x = 123文字列s = x as String
整数を文字列に割り当てることはできませんが、asを使用すると文字列に強制変換されます