上一篇 Gradle の入門知識を学びました。Gradle は Groovy に基づいています。今日は Groovy の基礎知識を学びましょう。Groovy は JVM 仮想マシンに基づく動的言語で、文法は Java の文法に似ています。Groovy は Java と完全に互換性があり、すべての Gradle ファイルは Groovy スクリプトファイルです。Gradle ファイルは Groovy 文法に基づいており、Groovy は Java と互換性があるため、Gradle ファイル内に Java コードを書くことができます。この基盤の上に、クロージャや DSL などの多くの新機能が追加されており、Groovy は非常に柔軟な動的スクリプト言語と言えます。Gradle に関連して、Groovy のいくつかの基礎知識を学びましょう。
- 文字列
- コレクション
- メソッド
- JavaBean
- クロージャ
文字列#
Groovy の特徴の一つは、Groovy ではセミコロンが必須ではなく、シングルクォートとダブルクォートの両方が文字列定数を定義します。違いは、シングルクォートは純粋な文字列定数であり、その文字列内の式を計算しませんが、ダブルクォートで定義された文字列定数は合法的な式を使用して関連する計算を行うことができます。テストコードは以下の通りです:
task stringTest{
//defキーワードを使用して変数を定義
def str1 = "ダブルクォート"
def str2 = 'シングルクォート'
println "ダブルクォートで定義された文字列:"+str1
println "ダブルクォートで定義された文字列:"+str1.class
println "シングルクォートで定義された文字列:"+str2
//変数の動的変化
str1 = true;
println "ダブルクォートで定義された文字列:"+str1.class
//$演算子を使用
println "ダブルクォートで定義された文字列:${str1}"
//変数が一つのときは中括弧を省略できる
println "ダブルクォートで定義された文字列:$str1"
//シングルクォートで定義された文字列は式を使用して計算できない
println 'シングルクォートで定義された文字列:$str2'
}
以下は実行結果の参考です:
PS E:\Gradle\study\Groovy> gradle stringTest
> Configure project :
ダブルクォートで定義された文字列:ダブルクォート
ダブルクォートで定義された文字列:class java.lang.String
シングルクォートで定義された文字列:シングルクォート
ダブルクォートで定義された文字列:class java.lang.Boolean
ダブルクォートで定義された文字列:true
ダブルクォートで定義された文字列:true
シングルクォートで定義された文字列:$str2
BUILD SUCCESSFUL in 1s
コレクション#
Groovy にもコレクションの概念があり、主に一般的な List と Map を見ていきます。以下では List と Map の一般的な操作について紹介します。
では、Groovy でListをどのように定義するのでしょうか。Groovy の List の定義方法は Java の配列に似ており、具体的な操作は以下のコードを参照してください:
task list{
//Listを定義
def list = [1,2,3,4,5,6];
def weekList = ['月曜日','火曜日','水曜日','木曜日','金曜日','土曜日','日曜日'];
println "listの型:"+list.class
println "weekListの型:"+weekList.class
//コレクション内の要素にアクセス
println '最初の要素:'+list[0]//最初の要素にアクセス
println '二番目の要素:'+list[1]//二番目の要素にアクセス、以下同様
println '最後の要素:'+list[-1]//最後の要素にアクセス
println '二番目から最後の要素:'+list[-2]//二番目から最後の要素にアクセス、以下同様
println '特定の範囲内の要素:'+list[2..4]//特定の範囲内の要素にアクセス、以下同様
//eachを使用してコレクション内の要素を繰り返し処理
weekList.each{
//itを反復の要素変数として使用、間違えないでください
println it
}
}
以下は上記コードの実行結果の参考です:
PS E:\Gradle\study\Groovy\ListMap> gradle list
> Configure project :
listの型:class java.util.ArrayList
weekListの型:class java.util.ArrayList
最初の要素:1
二番目の要素:2
最後の要素:6
二番目から最後の要素:5
特定の範囲内の要素:[3, 4, 5]
月曜日
火曜日
水曜日
木曜日
金曜日
土曜日
日曜日
BUILD SUCCESSFUL in 2s
では、Groovy でMapをどのように定義するのでしょうか。Groovy の Map はもちろんキーと値のペアです。具体的な定義と操作は以下のコードを参照してください:
task map{
//Mapを定義
def map = ['name':'Groovy', 'age':10];
println "mapの型:"+map.getClass().name;
//Map内の要素にアクセス
println map.name;
println map['name'];
//Map内の要素を繰り返し処理
map.each{
println "Key:${it.key},value:${it.value}"
}
}
以下は上記コードの実行結果の参考です:
PS E:\Gradle\study\Groovy\ListMap> gradle map
> Configure project :
mapの型:java.util.LinkedHashMap
Groovy
Groovy
Key:name,value:Groovy
Key:age,value:10
BUILD SUCCESSFUL in 2s
Groovy のコレクションについてはこれで十分です。
メソッド#
Groovy のメソッドは Java のメソッドに似ていますが、書き方がより柔軟です。Groovy では return は必須ではなく、return を書かない場合、Groovy は最後の文をそのメソッドの戻り値として扱います。コードブロックとは、波括弧で囲まれたコードの一部を指し、Groovy ではコードブロックを引数として渡すことができます。コレクションの繰り返し部分を参照してください。以下のコードを参照してください:
task method{
//メソッド呼び出し
methodA(1, 2)
methodA 1, 2
//メソッドの戻り値を取得
def a = methodA 10, 20
println 'メソッドの戻り値を取得:'+a
//コードブロックを引数として渡す
def list = [1,2,3,4,5];
list.each(
//クロージャ引数
{
// println it
}
)
//Groovyでは、メソッドの最後の引数がクロージャの場合、メソッドの外に直接置くことができます
list.each(){
// println it
}
//省略形
list.each{
println it
}
}
//メソッドの定義
def methodA(int a, int b){
println a + b
//Groovyではreturn文は必須ではなく、デフォルトで最後の文の結果を戻り値として扱います
a + b
}
以下は上記コードの実行結果の参考です:
PS E:\Gradle\study\Groovy\Method> gradle method
> Configure project :
3
3
30
メソッドの戻り値を取得:30
1
2
3
4
5
BUILD SUCCESSFUL in 2s
JavaBean#
Groovy の JavaBean は Java のものよりも柔軟で、javaBean. 属性の形式で JavaBean の属性値を取得および変更できます。対応する Getter、Setter メソッドを使用する必要はありません。コードを直接見てみましょう:
task javaBean{
//GroovyでJavaBeanを定義
Student student = new Student()
student.name = "Groovy"
student.age = 10
student.setName("Gradle")
println "名前は:"+student.name
//Getterメソッドを呼び出して値を取得することはできません
// println "名前は:"+student.getName
println "年齢は:${student.age}"
println "点数は:"+student.score
}
class Student{
private String name
private int age
//定義されたGetterメソッドに対応する属性は直接呼び出すことができます
public String getScore(){
100
}
//属性のGetter、Setterメソッド
public String setName(String name){
this.name = name
}
public void getName(){
name
}
}
以下は上記コードの実行結果の参考です:
PS E:\Gradle\study\Groovy\JavaBean> gradle javaBean
> Configure project :
名前は:Gradle
年齢は:10
点数は:100
BUILD SUCCESSFUL in 2s
クロージャ#
クロージャは多くのスクリプト言語に共通する特徴であり、JavaScript や Groovy などに見られます。クロージャは波括弧で囲まれたコードブロックです。以下では Groovy のクロージャについて学びます。主に二つの部分:クロージャとクロージャ引数の渡し方、クロージャの委任について説明します。
クロージャとその引数の渡し方#
以下にクロージャを定義する方法と関連する引数の渡し方を示します。コードを直接見てみましょう:
task closure{
//カスタムクロージャの実行
mEach{
println it
}
//クロージャに引数を渡す
mEachWithParams{m,n -> //m,n ->クロージャの引数と本体を区別します
println "${m} is ${n}"
}
}
//1.メソッドを定義し、引数closureはクロージャを受け取ります
//2.クロージャの実行は波括弧内のコードの実行です
//3.クロージャが受け取る引数はクロージャ引数closureのiであり、引数が一つの場合はデフォルトでit変数です
def mEach(closure){
for(int i in 1..5){
closure(i)
}
}
//クロージャに引数を渡す
def mEachWithParams(closure){
def map = ["name":"Groovy","age":10]
map.each{
closure(it.key, it.value)
}
}
上記のコードでは、クロージャを定義し、引数の渡し方を示しています。クロージャに引数が一つだけある場合、デフォルトで it になりますが、複数の引数がある場合は引数を定義する必要があります。具体的には上記のコードを参照してください。以下は実行結果の参考です:
PS E:\Gradle\study\Groovy\Closure> gradle delegate
> Configure project :
1
2
3
4
5
name is Groovy
age is 10
BUILD SUCCESSFUL in 2s
クロージャの委任#
Groovy のクロージャの強力な点は、クロージャメソッドの委任をサポートしていることです。Groovy のクロージャには三つの属性があります:thisObject、owner、delegate。クロージャ内で定義されたメソッドを呼び出すとき、これら三つの属性によってどのオブジェクトがそのメソッドを実行するかが決まります。デフォルトでは owner と delegate は等しいですが、delegate は変更可能です。Gradle の多くのクロージャ機能は delegate を変更することで実現されています。以下にクロージャとメソッドを定義し、これら三つの属性の違いを印刷して説明します:
//クロージャの委任
task delegate{
new Delegate().test{
//Groovyクロージャの三つの属性:thisObject、owner、delegate
println "thisObject:${thisObject.getClass()}"
println "owner:${owner.getClass()}"
println "delegate:${delegate.getClass()}"
//クロージャのデフォルトit
println "クロージャのデフォルトit:"+it.getClass()
//定義されたメソッドは優先的にthisObjectを使用して処理します
method()
//クロージャ内のメソッド
it.method()
}
}
def method(){
println "root内のメソッド:${this.getClass()}"
}
class Delegate{
def method(){
println "Delegate内のメソッド:${this.getClass()}"
}
//クロージャ
def test(Closure<Delegate> closure){
closure(this);
}
}
以下は上記コードの実行結果の参考です:
PS E:\Gradle\study\Groovy\Closure> gradle delegate
> Configure project :
thisObject:class build_3ajca04o1rprxygcsq0ajvt7i
owner:class build_3ajca04o1rprxygcsq0ajvt7i$_run_closure2
delegate:class build_3ajca04o1rprxygcsq0ajvt7i$_run_closure2
クロージャのデフォルトit:class Delegate
root内のメソッド:class build_3ajca04o1rprxygcsq0ajvt7i
Delegate内のメソッド:class Delegate
BUILD SUCCESSFUL in 2s
クロージャ内で method () メソッドを呼び出すと、thisObject が method () メソッドを呼び出したことがわかります。owner や delegate ではなく、クロージャ内では thisObject がメソッドの実行を優先的に処理します。また、owner と delegate は一致していますが、owner の優先度が delegate よりも高いことがわかります。したがって、クロージャ内のメソッドの処理順序は:thisObject > owner > delegate です。
Gradle では一般的に delegate を現在の it に指定します。これにより、delegate で指定されたオブジェクトを使用して it を操作できるようになります。以下にクロージャの delegate を指定し、委任の優先度を設定して、委任された具体的なオブジェクトがそのメソッドを実行するようにします。以下はテストコードです:
task student{
configStudent{
println "現在のit:${it}"
name = "Groovy"
age = 10
getInfo()
}
}
class Student{
String name
int age
def getInfo(){
println "name is ${name}, age is ${age}"
}
}
def configStudent(Closure<Student> closure){
Student student = new Student()
//現在作成されたStudentインスタンスを委任オブジェクトとして設定
closure.delegate = student
//委任モードを優先的に設定します。設定しない場合、クロージャ内のメソッドの処理者はthisObjectになります
closure.setResolveStrategy(Closure.DELEGATE_FIRST)
//it変数を設定
closure(student)
}
以下は上記コードの実行結果の参考です:
PS E:\Gradle\study\Groovy\Closure> gradle student
> Configure project :
現在のit:Student@18f6d755
name is Groovy, age is 10
BUILD SUCCESSFUL in 2s
まとめ#
Groovy を学ぶ目的は、Gradle ビルドツールの理解を深めることです。上記の五つの側面を通じて、Groovy についての初歩的な理解を得ました。今後、Groovy の高度な使い方を学ぶ必要があれば、再度 Groovy を見ていきます。