Groovy

出典: フリー教科書『ウィキブックス(Wikibooks)』

Apache Groovyは、Javaプラットフォーム上で動作するオブジェクト指向のスクリプト言語です。 Javaとのシームレスな統合を提供し、動的型付けやクロージャなどの機能を備えています。 Rubyに似たシンタックスを持ち、Javaのライブラリやフレームワークを利用できるため、Webアプリケーション、ビルドスクリプト、テスト、データ処理など、幅広い用途で活用されています。

Groovyの基礎[編集]

Groovyとは何か[編集]

Apache Groovy(グルーヴィー)は、Javaプラットフォーム上で動作する動的なスクリプト言語で、Java言語と密接に関連しています。この言語は、Javaの機能にアクセスできるだけでなく、簡単で直感的な構文、ダイナミックな型付け、クロージャなど、他の多くのプログラミング言語の特徴も組み合わせています。

Groovyは、Javaコードを簡素化し、可読性を高めるために設計されており、Javaの機能を活用しながら、開発者がより効率的にコードを記述できるようにすることを目的としています。また、Javaとのシームレスな統合性を備えており、Javaクラスを拡張し、Javaコードに対してGroovyコードを使用できます。

Apache Groovyは、Apacheソフトウェア財団によって管理されており、オープンソースで公開されています。この言語は、Java開発者やシステム管理者、ビッグデータ分析者など、さまざまなユーザーにとって人気のある選択肢です。

Groovyの特徴
変数
Groovyでは、変数の宣言にはいくつかの方法があります。以下にそのいくつかの例を示します。
def x = 10  // 動的型付けされた変数
String name = "John"  // 静的型付けされた変数
final int MAX_VALUE = 100  // 不変の変数
文字列
文字列は、シングルクォートまたはダブルクォートで囲まれたテキストです。ダブルクォートの場合、式を展開することができます。
def name = "John"
def message = "Hello ${name}"
リスト
リストは、要素のコレクションです。Groovyのリストは、括弧で囲まれたカンマ区切りの要素のリストとして表されます。
def numbers = [1, 2, 3, 4, 5]
マップ
マップは、キーと値のペアのコレクションです。Groovyのマップは、括弧で囲まれたキーと値のペアのリストとして表されます。
def person = [ name: "John", age: 30 ]
制御構文
Groovyは、Javaと同様の制御構文をサポートしています。これには、if、for、whileなどが含まれます。
def age = 30
if (age >= 18) {
    println "You are an adult"
} else {
    println "You are a minor"
}
メソッド
メソッドは、Groovyスクリプト内で再利用可能なコードブロックです。メソッドは、defキーワードで宣言されます。
def sayHello(name) {
    println "Hello ${name}"
}

sayHello("John")
クロージャ
クロージャは、関数を値として扱うことができます。Groovyのクロージャは、波括弧で囲まれた引数と本文で定義されます。
def closure = { name ->
    println "Hello ${name}"
}

closure("John")
クラス
Groovyは、Javaと同様にオブジェクト指向言語であるため、クラスをサポートしています。
クラスを用いたコード例
class Person {
    String name
    int age

    Person(String name, int age) {
        this.name = name
        this.age = age
    }

    void sayHello() {
        println "Hello, my name is ${name} and I am ${age} years old."
    }
}

def person = new Person("John", 30)
person.sayHello()
RubyとGroovyの比較
RubyとGroovyの主な違いをいくつか示します。
  1. 文法:Rubyは、Groovyよりも更に簡潔な文法を持ち、コードの書き方が自由度が高いです。また、Rubyは、動的な型付けの言語であり、Groovyと同様にランタイム時に型エラーが検出されます。
  2. 関数型プログラミング:Rubyは、関数型プログラミングの特徴も持ち、簡潔なコードで高度な処理が可能です。一方、Groovyは、オブジェクト指向プログラミングが中心となっています。
  3. メタプログラミング:Rubyは、Groovyと同様に強力なメタプログラミング機能を提供しています。Rubyのメタプログラミング機能は、非常に強力であり、DSL(Domain-Specific Language)の開発にも向いています。
  4. 実行速度:Rubyは、Groovyよりも実行速度が遅く、大規模なアプリケーションには向かない場合があります。一方、Rubyは、高い生産性を持ち、短い時間でコードを書くことができます。
  5. コーディングスタイル:Rubyは、Groovyと同様に柔軟なスタイルでコーディングできます。ただし、Rubyには独自のスタイルがあり、初心者には学習コストがかかる場合があります。

総じて、Rubyは簡潔で柔軟な文法が特徴的であり、メタプログラミングに強いといった特徴があります。一方、Groovyはオブジェクト指向プログラミングが中心となっており、DSLの開発には向いています。どちらの言語を選択するかは、プロジェクトの性質や目的によって異なります。


Groovyのインストールと設定[編集]

Groovyの開発にはJREまたはJDKが必要です。まず、JREまたはJDKをインストールしてください。

GroovyはApacheのWebサイトからダウンロードできます。以下の手順に従って、Groovyをインストールしてください。

  1. GroovyのWebサイトにアクセスし、Groovyダウンロードページに移動します。
  2. ダウンロードページで、最新のバージョンを選択します。zipファイル形式を使用することをお勧めします。
  3. ダウンロードを開始する前に、Apacheアカウントにサインアップする必要がある場合があります。アカウントを持っていない場合は、新規登録してください。
  4. zipファイルをダウンロードし、適当なディレクトリに展開します。
  5. 環境変数を設定します。PATH環境変数にGroovyのbinフォルダへのパスを追加します。
JavaとGroovyの比較
JavaとGroovyは、両方ともJava仮想マシン(JVM)上で実行されるオブジェクト指向プログラミング言語です。以下に、JavaとGroovyの主な違いをいくつか示します。
  1. 文法:Javaは、静的な型付けの言語であり、コンパイル時に型エラーを検出できます。一方、Groovyは動的な型付けの言語であり、ランタイム時に型エラーが検出されます。Groovyは、Javaよりも簡潔な文法を持ち、コードの書き方が自由度が高いです。
  2. コードの量:Groovyは、Javaよりも短く、コードの書き方が自由度が高いため、同じ機能を実現するためのコードの量が少なくて済む場合があります。
  3. メタプログラミング:Groovyは、Javaよりも強力なメタプログラミング機能を提供しています。メタプログラミングとは、プログラムが自己修正することができる機能のことで、GroovyはJavaに比べてメタプログラミングが簡単に実現できます。
  4. 実行速度:Javaは、コンパイル時に最適化されるため、実行速度が速く、大規模なアプリケーションに適しています。一方、Groovyは、動的型付けのため、実行速度が遅い場合があります。
  5. コーディングスタイル:Javaは、コードのスタイルを統一するための多くの規則がありますが、Groovyは、柔軟なスタイルでコーディングできます。

総じて、Javaは大規模なアプリケーションに適しており、Groovyは簡潔で自由な文法が特徴的で、メタプログラミングに強いといった特徴があります。どちらの言語を選択するかは、プロジェクトの性質や目的によって異なります。


変数とデータ型[編集]

Groovyでは、変数とデータ型について以下のように説明できます:

  1. 動的型付けな変数: Groovyは動的型付け言語です。変数を宣言する際に、その型を明示的に指定する必要はありません。変数に代入される値によって、その型が自動的に決定されます。例えば:
    def x = 10  // 動的型付けされた変数
    x = "ABC"   // 可能
    
  2. 静的型付けな変数: 静的型付けもサポートされており、変数宣言時に型を明示的に指定することができます。この場合、変数はその型の値しか受け付けません。例えば:
    String name = "John"  // 静的型付けされた変数
    // name = 42 // コンパイルエラー
    
  3. データ型: GroovyはJavaと同じく、プリミティブ型やオブジェクト型をサポートしています。例えば、整数型intや文字列型String、リスト型List、マップ型Mapなどがあります。Groovyはこれらのデータ型を柔軟に使用することができます。

データ型[編集]

Groovyは動的型付け言語であり、変数の型を事前に宣言する必要はありません。変数の値に基づいて、自動的に適切なデータ型が割り当てられます。

主なデータ型には以下のようなものがあります:

  • 整数型(Integer):整数値を格納するためのデータ型です。
  • 浮動小数点型(Double):浮動小数点数を格納するためのデータ型です。
  • 文字列型(String):テキストデータを格納するためのデータ型です。
  • ブール型(Boolean):真偽値(trueまたはfalse)を格納するためのデータ型です。

以下は、それぞれのデータ型の例です:

以下は、Groovyで使用される主要な型とそのリテラルの例、および解説を表形式で示したものです:

Groovyの主要な型
リテラル例 解説
int 10, 0b1010, 012 整数型。基数10(10進数)、基数2(2進数)、基数8(8進数)
Integer 10, 0b1010, 012 整数オブジェクト型。int型のラッパークラス
long 100L, 0x64L 長整数型。基数10(10進数)、基数16(16進数)
Long 100L, 0x64L 長整数オブジェクト型。long型のラッパークラス
double 3.14, 6.02e23 浮動小数点数型。通常の小数、指数表記
Double 3.14, 6.02e23 浮動小数点数オブジェクト型。double型のラッパークラス
float 3.14f, 6.02e23f 単精度浮動小数点数型。末尾に"f"を付けた場合はfloat型
Float 3.14f, 6.02e23f 単精度浮動小数点数オブジェクト型。float型のラッパークラス
boolean true, false 真偽値型。
Boolean true, false 真偽値オブジェクト型。boolean型のラッパークラス
char 'A', '\u0041' 文字型。シングルクォートで囲んで文字を表現。Unicode表現も可
Character 'A', '\u0041' 文字オブジェクト型。char型のラッパークラス
String "Hello, World!" 文字列型。
List [1, 2, 3] リスト。可変長配列。
Map [name: "John"] マップ。キーと値のペアのコレクション。
Set [1, 2, 3] as Set 集合。重複を許さない値のコレクション。
Date new Date(), new Date(2022, 1, 1) 日付型。現在日時や指定した日時を表現。
LocalDate LocalDate.now(), LocalDate.of(2022, 2, 5) 日付型。JDKのLocalDateクラスと同様。
LocalDateTime LocalDateTime.now(), LocalDateTime.of(2022, 2, 5, 12, 30) 日時型。JDKのLocalDateTimeクラスと同様。
これらの型は、Groovyで広く使用され、Javaの標準ライブラリとの互換性があります。Groovyはこれらの型のリテラルを使って柔軟にデータを操作できるのが特徴です。

型の変換[編集]

Groovyでは、異なるデータ型の間で値を変換することができます。これを型キャストと呼びます。以下は、いくつかの基本的な型キャストの例です。

整数から文字列への変換:

// toString()メソッドを使う方法:
// 整数オブジェクトに対してtoString()メソッドを呼び出すことで、文字列に変換できます。
def num = 123
def str = num.toString()
println str // 出力: "123"

// asキーワードを使う方法:
// asキーワードを使って整数を文字列にキャストする方法もあります。
num = 456
str = num as String
println str // 出力: "456"

// GString (Groovy文字列)を使う方法:
// GStringを使って、整数を文字列に変換することもできます。この方法では、整数を文字列の中に埋め込むことができます。
num = 789
str = "$num"
println str // 出力: "789"

文字列から整数への変換:

// toInteger()メソッドを使う方法:
// 文字列オブジェクトに対してtoInteger()メソッドを呼び出すことで、整数に変換できます。
def str = "123"
def num = str.toInteger()
println num // 出力: 123

// asキーワードを使う方法:
// asキーワードを使って文字列を整数にキャストする方法もあります。
str = "456"
num = str as Integer
println num // 出力: 456

// Integer.parseInt()メソッドを使う方法:
// Integer.parseInt()メソッドを使って文字列を整数に変換する方法もあります。
str = "789"
num = Integer.parseInt(str)
println num // 出力: 789

文字列から浮動小数点数への変換:

// toDouble()メソッドを使う方法:
// 文字列オブジェクトに対してtoDouble()メソッドを呼び出すことで、浮動小数点数に変換できます。
def str = "3.14"
def num = str.toDouble()
println num // 出力: 3.14

// asキーワードを使う方法:
// asキーワードを使って文字列を浮動小数点数にキャストする方法もあります。
str = "6.02e23"
num = str as Double
println num // 出力: 6.02E23

// Double.parseDouble()メソッドを使う方法:
// Double.parseDouble()メソッドを使って文字列を浮動小数点数に変換する方法もあります。
str = "2.71828"
num = Double.parseDouble(str)
println num // 出力: 2.71828

変数の再代入[編集]

Groovyでは、変数には新しい値を再代入することができます。変数の値を変更するには、変数名を指定して新しい値を代入します。

def x = 10 // 変数xに初期値10を代入する
println x // 出力: 10

x = 20 // 変数xに新しい値20を代入して再代入する
println x // 出力: 20

この例では、最初に変数xに値10が代入され、次に同じ変数xに新しい値20が代入されています。再代入により、変数xが参照する値が変更され、結果として20が出力されます。

Groovyの柔軟な代入および再代入の機能により、変数の値を簡単に変更できます。

定数[編集]

Groovyでは、値を変更できない定数を宣言することもできます。定数はfinalキーワードを使用して宣言され、初期化された後に値を変更することはできません。

final int MAX_NUMBER = 100

まとめ[編集]

Integer i = 42                // 整数型
Double f = 3.14               // 浮動小数点型
String s = "Hello, World!"    // 文字列型
Boolean b = true              // ブール型

def q                         // 未初期化 org.codehaus.groovy.runtime.NullObject
def number = 10               // java.lang.Integerと推論
def pi = 3.14                 // java.math.BigDecimalと推論
def message = "Hello, World!" // java.lang.Stringと推論
final int MAX_NUMBER = 100    // 整数定数

[i, f, s, b, q, number, pi, message, MAX_NUMBER].each{
  println it.inspect() + ': ' + it.getClass()
}
実行結果
42: class java.lang.Integer
3.14: class java.lang.Double
'Hello, World!': class java.lang.String
true: class java.lang.Boolean
null: class org.codehaus.groovy.runtime.NullObject
10: class java.lang.Integer
3.14: class java.math.BigDecimal
'Hello, World!': class java.lang.String
100: class java.lang.Integer

1行目から4行目までは、さまざまな型の変数の宣言と初期化が行われています。

  • Integer i = 42は、整数型の変数iを宣言し、値42で初期化しています。
  • Double f = 3.14は、浮動小数点型の変数fを宣言し、値3.14で初期化しています。
  • String s = "Hello, World!"は、文字列型の変数sを宣言し、値"Hello, World!"で初期化しています。
  • Boolean b = trueは、ブール型の変数bを宣言し、値trueで初期化しています。

6行目から10行目では、変数の型推論が示されています。Groovyではdefキーワードを使用して型推論を行うことができます。

  • def qは未初期化の変数qを宣言しています。Groovyでは初期化されていない変数はorg.codehaus.groovy.runtime.NullObjectとして扱われます。
  • def number = 10は、変数numberを宣言し、値10で初期化しています。Groovyは推論によりjava.lang.Integerの型と判断します。
  • def pi = 3.14は、変数piを宣言し、値3.14で初期化しています。Groovyは推論によりjava.math.BigDecimalの型と判断します。
  • def message = "Hello, World!"は、変数messageを宣言し、値"Hello, World!"で初期化しています。Groovyは推論によりjava.lang.Stringの型と判断します。

最後の行では、配列にそれらの要素をまとめ、eachメソッドを使用して各要素に対して処理を行っています。 各要素をinspect()メソッドで文字列表現に変換し、それにクラス情報を追加して出力しています。この部分は各要素の型を確認するためのデバッグ目的のコードです。

上記のコードを実行すると、各変数の値と型が出力されます。例えば、iの出力は42: class java.lang.Integerとなります。

演算子と式[編集]

// 数値演算
def a = 10
def b = 3
def sum = a + b
def difference = a - b
def product = a * b
def quotient = a / b
def modulus = a % b

println "Sum: " + sum
println "Difference: " + difference
println "Product: " + product
println "Quotient: " + quotient
println "Modulus: " + modulus

// 文字列連結
def message1 = "Hello"
def message2 = "World"
def greeting = message1 + ", " + message2

println "Greeting: " + greeting

// 論理演算
def x = true
def y = false
def andResult = x && y
def orResult = x || y
def notResult = !x

println "AND Result: " + andResult
println "OR Result: " + orResult
println "NOT Result: " + notResult

// 比較演算
def num1 = 5
def num2 = 8

def isEqual = num1 == num2
def isNotEqual = num1 != num2
def isGreater = num1 > num2
def isLess = num1 < num2

println "Is Equal: " + isEqual
println "Is Not Equal: " + isNotEqual
println "Is Greater: " + isGreater
println "Is Less: " + isLess

このコードでは、Groovyで使用される一般的な演算子を紹介しています。

数値演算では、加算(+)、減算(-)、乗算(*)、除算(/)、剰余(%)の演算子が使用されています。

文字列連結では、文字列同士を+演算子で結合しています。

論理演算では、論理積(&&)、論理和(||)、否定(!)の演算子が使用されています。

比較演算では、等しいかどうか(==)、等しくないかどうか(!=)、大きいかどうか(>)、小さいかどうか(<)の演算子が使用されています。

各演算の結果は変数に格納され、println文を使用して結果が出力されます。

// 代入演算子
def x = 5
x += 3  // x = x + 3
println "x: " + x  // 結果: 8

def y = 10
y -= 4  // y = y - 4
println "y: " + y  // 結果: 6

def z = 2
z *= 5  // z = z * 5
println "z: " + z  // 結果: 10

def a = 15
a /= 3  // a = a / 3
println "a: " + a  // 結果: 5

def b = 7
b %= 4  // b = b % 4
println "b: " + b  // 結果: 3

// インクリメントとデクリメント
def count = 5
count++  // インクリメント
println "Count after increment: " + count  // 結果: 6

count--  // デクリメント
println "Count after decrement: " + count  // 結果: 5

// 三項演算子
def score = 80
def result = (score >= 70) ? "Pass" : "Fail"
println "Result: " + result  // 結果: Pass

このコードでは、さまざまな演算子と演算子の組み合わせが示されています。

代入演算子では、加算代入(+=)、減算代入(-=)、乗算代入(*=)、除算代入(/=)、剰余代入(%=)の演算子が使用されています。

インクリメント(++)とデクリメント(--)は、変数の値を1つ増やすまたは減らすために使用されます。

三項演算子(?:)は、条件式の結果に基づいて異なる値を返すために使用されます。条件が真の場合は最初の値が、偽の場合は2番目の値が代入されます。

各演算の結果は変数に格納され、println文を使用して結果が出力されます。

// 文字列比較
def str1 = "apple"
def str2 = "banana"

def isEqualStr = str1 == str2
def isNotEqualStr = str1 != str2

println "Is Equal (Strings): " + isEqualStr  // 結果: false
println "Is Not Equal (Strings): " + isNotEqualStr  // 結果: true

// 論理演算子のショートサーキット
def p = true
def q = false

def logicalAnd = p && q
def logicalOr = p || q

println "Logical AND: " + logicalAnd  // 結果: false
println "Logical OR: " + logicalOr  // 結果: true

// 演算子の優先順位
def x = 5
def y = 3
def z = 2

def result1 = x + y * z
def result2 = (x + y) * z

println "Result 1: " + result1  // 結果: 11
println "Result 2: " + result2  // 結果: 16

このコードでは、さまざまな演算子とその使用法が示されています。

文字列比較では、==演算子と!=演算子を使用して、2つの文字列が等しいかどうかを比較しています。

論理演算子のショートサーキットでは、&&演算子と||演算子を使用して、論理積と論理和を評価しています。

演算子の優先順位では、乗算(*)が加算(+)よりも優先されることを示しています。result1の計算では、乗算が先に評価され、result2の計算では括弧が優先されます。

各演算の結果は変数に格納され、println文を使用して結果が出力されます。

// 三項演算子のネスト
def age = 25
def isAdult = (age >= 18) ? "Adult" : ((age >= 13) ? "Teenager" : "Child")
println "Age Group: " + isAdult  // 結果: Adult

// null安全演算子
def text = "Hello"
def length = text?.length()
println "Length: " + length  // 結果: 5

def nullText = null
def nullLength = nullText?.length()
println "Null Length: " + nullLength  // 結果: null

// Elvis 演算子
def name = null
def displayName = name ?: "John Doe"
println "Display Name: " + displayName  // 結果: John Doe

このコードでは、Groovyの特殊な演算子である三項演算子のネスト、null安全演算子、およびElvis演算子の使用例が示されています。

三項演算子のネストでは、年齢に基づいて異なる結果を返す複雑な条件分岐が行われています。

null安全演算子(?.)は、null安全な呼び出しを行います。もし変数がnullであれば、メソッド呼び出しやプロパティアクセスは無視され、結果はnullになります。

Elvis演算子(?:)は、変数がnullである場合に代替の値を返すために使用されます。変数がnullでなければ、その値が使用されます。

各演算の結果は変数に格納され、println文を使用して結果が出力されます。

// 配列演算子
def numbers = [1, 2, 3, 4, 5]
def names = ["Alice", "Bob", "Charlie"]

def firstNumber = numbers[0]
def lastNumber = numbers[-1]
def nameLength = names[1].length()

println "First Number: " + firstNumber  // 結果: 1
println "Last Number: " + lastNumber  // 結果: 5
println "Name Length: " + nameLength  // 結果: 3

// リスト結合演算子
def list1 = [1, 2, 3]
def list2 = [4, 5, 6]
def mergedList = list1 + list2

println "Merged List: " + mergedList  // 結果: [1, 2, 3, 4, 5, 6]

// 文字列演算子
def greeting = "Hello, " + "World!"
println "Greeting: " + greeting  // 結果: Hello, World!

// instanceof演算子
def obj1 = "Hello"
def obj2 = 42

def isString = obj1 instanceof String
def isNumber = obj2 instanceof Number

println "Is String: " + isString  // 結果: true
println "Is Number: " + isNumber  // 結果: true

このコードでは、配列演算子、リスト結合演算子、文字列演算子、およびinstanceof演算子の使用例が示されています。

配列演算子([])を使用すると、配列内の特定の要素にアクセスできます。numbers[0]は最初の要素を、numbers[-1]は最後の要素を取得します。

リスト結合演算子(+)は、2つのリストを結合して新しいリストを作成します。

文字列演算子(+)は、文字列の連結に使用されます。

instanceof演算子は、オブジェクトの型をチェックします。指定した型に属していればtrueを返し、そうでなければfalseを返します。

各演算の結果は変数に格納され、println文を使用して結果が出力されます。

// レンジ演算子
def range1 = 1..5
def range2 = 10..1

println "Range 1: " + range1  // 結果: [1, 2, 3, 4, 5]
println "Range 2: " + range2  // 結果: []

// 正規表現演算子
def text = "Hello, World!"
def pattern = /Hello, (\w+)!/
def match = text =~ pattern

println "Matched Text: " + match[0][0]  // 結果: Hello, World!
println "Matched Group: " + match[0][1]  // 結果: World

// メソッド呼び出し演算子
def list = [1, 2, 3, 4, 5]
def size = list.size()

println "List Size: " + size  // 結果: 5

// クロージャ演算子
def numbers = [1, 2, 3, 4, 5]
def squares = numbers.collect { it * it }

println "Squares: " + squares  // 結果: [1, 4, 9, 16, 25]

このコードでは、レンジ演算子(..)、正規表現演算子(=~)、メソッド呼び出し演算子(.)、およびクロージャ演算子({})の使用例が示されています。

レンジ演算子は、指定した範囲の値を表すリストを作成します。1..5は1から5までの整数のリストを、10..1は空のリストを作成します。

正規表現演算子(=~)を使用すると、テキスト内で正規表現パターンに一致する部分を検索できます。match[0][0]は一致した全体のテキストを、match[0][1]はキャプチャグループの一致した部分を取得します。

メソッド呼び出し演算子(.)を使用すると、オブジェクトのメソッドを呼び出すことができます。list.size()はリストの要素数を取得します。

クロージャ演算子({})は、匿名の関数を作成します。numbers.collect { it * it }numbersリストの各要素に対してクロージャを適用し、要素の2乗のリストを作成します。

各演算の結果は変数に格納され、println文を使用して結果が出力されます。

// グループ化演算子
def result1 = 2 + 3 * 4
def result2 = (2 + 3) * 4

println "Result 1: " + result1  // 結果: 14
println "Result 2: " + result2  // 結果: 20

// 三項演算子のショートサーキット
def x = 5
def y = 10
def z = (x > y) ? "x > y" : (x < y) ? "x < y" : "x == y"

println "Comparison: " + z  // 結果: x < y

// ビット演算子
def a = 5
def b = 3

def bitwiseAnd = a & b
def bitwiseOr = a | b
def bitwiseXor = a ^ b

println "Bitwise AND: " + bitwiseAnd  // 結果: 1
println "Bitwise OR: " + bitwiseOr  // 結果: 7
println "Bitwise XOR: " + bitwiseXor  // 結果: 6

// シフト演算子
def num = 10

def leftShift = num << 2
def rightShift = num >> 1

println "Left Shift: " + leftShift  // 結果: 40
println "Right Shift: " + rightShift  // 結果: 5

このコードでは、演算子のグループ化(())、三項演算子のショートサーキット、ビット演算子、およびシフト演算子の使用例が示されています。

グループ化演算子(())は、演算子の評価順序を明示的に指定します。result1では乗算が先に評価されますが、result2では加算が先に評価されます。

三項演算子のショートサーキットでは、条件が順番に評価され、最初に真となる条件の結果が返されます。

ビット演算子(&|^)は、ビットごとの論理演算を行います。各演算の結果は整数として計算されます。

シフト演算子(<<>>)は、二進数表現のビットを左右にシフトします。左シフトではビットが左に移動し、右シフトではビットが右に移動します。

各演算の結果は変数に格納され、println文を使用して結果が出力されます。

// 論理演算子
def bool1 = true
def bool2 = false

def andResult = bool1 && bool2
def orResult = bool1 || bool2
def notResult = !bool1

println "AND Result: " + andResult  // 結果: false
println "OR Result: " + orResult  // 結果: true
println "NOT Result: " + notResult  // 結果: false

// 比較演算子
def num1 = 5
def num2 = 10

def isEqual = num1 == num2
def isNotEqual = num1 != num2
def isGreaterThan = num1 > num2
def isLessThan = num1 < num2
def isGreaterOrEqual = num1 >= num2
def isLessOrEqual = num1 <= num2

println "Is Equal: " + isEqual  // 結果: false
println "Is Not Equal: " + isNotEqual  // 結果: true
println "Is Greater Than: " + isGreaterThan  // 結果: false
println "Is Less Than: " + isLessThan  // 結果: true
println "Is Greater Or Equal: " + isGreaterOrEqual  // 結果: false
println "Is Less Or Equal: " + isLessOrEqual  // 結果: true

このコードでは、論理演算子(&&||!)と比較演算子(==!=><>=<=)の使用例が示されています。

論理演算子は、真偽値を操作するために使用されます。&&は論理積(AND)を計算し、両方のオペランドがtrueの場合に結果がtrueとなります。||は論理和(OR)を計算し、どちらかのオペランドがtrueの場合に結果がtrueとなります。!は論理否定(NOT)を計算し、オペランドの真偽値を反転させます。

比較演算子は、値の比較を行います。==は等しいかどうかを判定し、!=は等しくないかどうかを判定します。><>=<=はそれぞれ大なり、小なり、以上、以下を判定します。

各演算の結果は変数に格納され、println文を使用して結果が出力されます。

// null安全演算子
def text = "Hello, World!"
def length = text?.length()

println "Length: " + length  // 結果: 13

def nullValue = null
def result = nullValue?.toUpperCase()

println "Result: " + result  // 結果: null

// エルビス演算子
def name = null
def displayName = name ?: "Unknown"

println "Display Name: " + displayName  // 結果: Unknown

name = "Alice"
displayName = name ?: "Unknown"

println "Display Name: " + displayName  // 結果: Alice

このコードでは、null安全演算子(?.)とエルビス演算子(?:)の使用例が示されています。

null安全演算子(?.)は、オブジェクトがnullでない場合にのみプロパティやメソッドにアクセスします。もしオブジェクトがnullであれば、結果はnullとなります。text?.length()では、textオブジェクトがnullでない場合にのみlength()メソッドが呼び出されます。

エルビス演算子(?:)は、オブジェクトがnullである場合にデフォルトの値を使用します。オブジェクトがnullでない場合はその値を使用します。name ?: "Unknown"では、namenullであれば"Unknown"が、そうでなければnameの値が代入されます。

各演算の結果は変数に格納され、println文を使用して結果が出力されます。

// 安全ナビゲーション演算子
class Person {
  String name
}

def person = new Person()
def personName = person?.name

println "Person Name: " + personName  // 結果: null

person.name = "Alice"
personName = person?.name

println "Person Name: " + personName  // 結果: Alice

// 配列アクセス演算子
def array = [1, 2, 3, 4, 5]
def element = array[2]

println "Element: " + element  // 結果: 3

// スプレッド演算子
def numbers = [1, 2, 3]
def combined = [0, *numbers, 4, 5]

println "Combined: " + combined  // 結果: [0, 1, 2, 3, 4, 5]

このコードでは、安全ナビゲーション演算子(?.)、配列アクセス演算子([])、およびスプレッド演算子(*)の使用例が示されています。

安全ナビゲーション演算子(?.)は、オブジェクトがnullでない場合にのみプロパティにアクセスします。もしオブジェクトがnullであれば、結果はnullとなります。person?.nameでは、personオブジェクトがnullでない場合にのみnameプロパティにアクセスします。

配列アクセス演算子([])は、配列内の要素にアクセスします。array[2]では、array配列の3番目の要素にアクセスし、その値を取得します。

スプレッド演算子(*)は、配列内の要素を展開します。[0, *numbers, 4, 5]では、numbers配列の要素を展開して新しい配列を作成します。

各演算の結果は変数に格納され、println文を使用して結果が出力されます。

制御構造[編集]

// if文
def num = 10

if (num > 0) {
  println "Positive"
} else if (num < 0) {
  println "Negative"
} else {
  println "Zero"
}

// forループ
def numbers = [1, 2, 3, 4, 5]

for (def i = 0; i < numbers.size(); i++) {
  println numbers[i]
}

// whileループ
def count = 0

while (count < 5) {
  println "Count: " + count
  count++
}

// switch文
def fruit = "apple"

switch (fruit) {
  case "apple":
    println "It's an apple."
    break
  case "banana":
    println "It's a banana."
    break
  case "orange":
    println "It's an orange."
    break
  default:
    println "Unknown fruit."
    break
}

このコードでは、Groovyの制御構造の例が示されています。

if文は条件に基づいて分岐します。numが0より大きい場合は"Positive"、0より小さい場合は"Negative"、それ以外の場合は"Zero"が出力されます。

forループは指定された回数の繰り返しを行います。numbersリストの要素を順番に表示します。

whileループは条件が真の間、繰り返し処理を行います。countが5未満の間、Count: [countの値]と表示し、countをインクリメントします。

switch文は複数の条件に基づいて分岐します。fruitの値に応じて異なるメッセージが表示されます。

各制御構造の例では、条件やループの制御に応じてコードブロックが実行されます。

// ループの制御
def numbers = [1, 2, 3, 4, 5]

for (def number in numbers) {
  if (number == 3) {
    continue  // 次の繰り返しに進む
  }

  println number

  if (number == 4) {
    break  // ループを終了する
  }
}

// 強制的な例外のスロー
def num = -1

try {
  if (num < 0) {
    throw new IllegalArgumentException("Invalid number.")
  }
  println "Valid number."
} catch (IllegalArgumentException e) {
  println "Caught exception: " + e.message
}

このコードでは、ループの制御と例外のスローに関連する制御構造の例が示されています。

forループでは、numbersリストの要素を順番に処理します。ただし、要素の値が3の場合はcontinue文が実行され、次の繰り返しに進みます。要素の値が4の場合はbreak文が実行され、ループが終了します。

try-catch構文は例外の捕捉と処理を行います。tryブロック内のコードが実行され、もし例外がスローされた場合は該当するcatchブロックが実行されます。この例では、numが負の場合にIllegalArgumentExceptionがスローされ、その例外がキャッチされてメッセージが表示されます。

各制御構造はプログラムのフローを制御し、条件や繰り返しに基づいてコードの実行を調整します。また、例外のスローとキャッチを使用することで、エラー処理や異常状態の処理を行うことができます。

// ラベル付きループとラベル付きブロック
outerLoop: for (def i = 1; i <= 3; i++) {
  innerLoop: for (def j = 1; j <= 3; j++) {
    if (i == 2 && j == 2) {
      break outerLoop  // 外側のループを終了する
    }
    println "i: " + i + ", j: " + j
  }
}

// assert文によるアサーション
def x = 5
def y = 3

assert x > y  // xがyより大きいことを検証

// 三項演算子とnull安全演算子の組み合わせ
def name = "Alice"
def message = name?.length() > 0 ? "Hello, " + name : "Hello, Guest"

println message  // 結果: Hello, Alice

このコードでは、ラベル付きループとラベル付きブロック、assert文によるアサーション、および三項演算子とnull安全演算子の組み合わせの例が示されています。

ラベル付きループとラベル付きブロックを使用することで、内側のループから外側のループを終了することができます。break outerLoopは外側のループを終了し、ループから抜けます。

assert文は、条件式が真であることをアサーション(検証)します。もし条件式が偽の場合、アサーションエラーが発生し、プログラムの実行が停止します。この例では、xyよりも大きいことを検証しています。

三項演算子とnull安全演算子を組み合わせることで、nullチェックと条件付きの値の代入を行うことができます。name?.length() > 0は、namenullでない場合にのみlength()メソッドの結果が利用されます。

各制御構造の例では、プログラムのフローの制御や条件の検証を行っています。また、アサーションを使用することでプログラムの正しさを検証できます。

// 例外処理とfinallyブロック
def divideNumbers(int a, int b) {
  try {
    def result = a / b
    return result
  } catch (ArithmeticException e) {
    println "Divide by zero error: " + e.message
  } finally {
    println "Finally block executed"
  }
}

println divideNumbers(10, 2)  // 結果: 5
println divideNumbers(10, 0)  // 結果: Divide by zero error: / by zero

// クロージャ
def closureExample = { int x, int y ->
  x + y
}

println closureExample(3, 4)  // 結果: 7

// 例外のスローとキャッチ
def calculateSquareRoot(int number) {
  if (number < 0) {
    throw new IllegalArgumentException("Invalid number")
  }

  return Math.sqrt(number)
}

try {
  println calculateSquareRoot(9)  // 結果: 3.0
  println calculateSquareRoot(-9)  // 例外がスローされる
} catch (IllegalArgumentException e) {
  println "Caught exception: " + e.message
}

このコードでは、Groovyの「制御構造」に関連するさまざまな要素の例が示されています。

try-catch-finallyブロックは、例外処理を実行するために使用されます。tryブロック内のコードが実行され、もし例外がスローされた場合は該当するcatchブロックが実行されます。また、finallyブロックは例外の有無にかかわらず必ず実行されます。この例では、ゼロで割り算を試みた場合にArithmeticExceptionがキャッチされ、適切なメッセージが表示されます。

クロージャは無名関数のことで、関数のように扱うことができます。closureExampleは2つの引数を受け取り、それらを足した結果を返すクロージャです。closureExample(3, 4)は7を返します。

例外のスローとキャッチは、プログラムの実行中に異常状態を処理するために使用されます。calculateSquareRootメソッドでは、引数が負の場合にIllegalArgumentExceptionをスローします。呼び出し側では、このメソッドをtry-catch構文で囲み、例外をキャッチして適切なメッセージを表示します。

これらの制御構造は、プログラムの制御フローやエラー処理を柔軟に制御するために使用されます。

// リスト操作とコレクション演算子
def numbers = [1, 2, 3, 4, 5]

// eachメソッドによるリストの要素の繰り返し処理
numbers.each { num ->
  println num
}

// collectメソッドによるリストの要素の変換
def squaredNumbers = numbers.collect { num ->
  num * num
}

println squaredNumbers  // 結果: [1, 4, 9, 16, 25]

// findAllメソッドによる条件に合致する要素の抽出
def evenNumbers = numbers.findAll { num ->
  num % 2 == 0
}

println evenNumbers  // 結果: [2, 4]

// injectメソッドによるリストの要素の累積演算
def sum = numbers.inject { result, num ->
  result + num
}

println sum  // 結果: 15

// グルーピング
def names = ["Alice", "Bob", "Charlie", "Amy", "David"]

def groupedNames = names.groupBy { name ->
  name.length()
}

println groupedNames  // 結果: [3:[Bob, Amy], 5:[Alice], 7:[Charlie, David]]

このコードは、Groovyのリスト操作とコレクション演算子に関する例です。以下に各部分の解説をします。

  1. def numbers = [1, 2, 3, 4, 5]:整数のリストを作成します。
  2. numbers.each { num -> println num }eachメソッドを使用してリストの要素を繰り返し処理し、各要素を表示します。結果として、リストの要素1から5が順番に表示されます。
  3. def squaredNumbers = numbers.collect { num -> num * num }collectメソッドを使用してリストの要素を変換します。各要素を2乗した結果を含む新しいリストを生成します。squaredNumbersには[1, 4, 9, 16, 25]というリストが代入されます。
  4. println squaredNumbers:変換されたリストsquaredNumbersを表示します。結果として、[1, 4, 9, 16, 25]が表示されます。
  5. def evenNumbers = numbers.findAll { num -> num % 2 == 0 }findAllメソッドを使用して条件に合致する要素を抽出します。この場合、リストの中から偶数の要素を抽出し、新しいリストを生成します。evenNumbersには[2, 4]というリストが代入されます。
  6. println evenNumbers:抽出された偶数のリストevenNumbersを表示します。結果として、[2, 4]が表示されます。
  7. def sum = numbers.inject { result, num -> result + num }injectメソッドを使用してリストの要素を累積的に演算します。各要素を順番に足し合わせて合計値を計算します。sumには15が代入されます。
  8. println sum:合計値sumを表示します。結果として、15が表示されます。
  9. def names = ["Alice", "Bob", "Charlie", "Amy", "David"]:文字列のリストを作成します。
  10. def groupedNames = names.groupBy { name -> name.length() }groupByメソッドを使用してリストの要素を指定されたクロージャの戻り値に基づいてグループ化します。ここでは、名前の長さをキーとしてグループ化します。groupedNamesにはグループ化された結果がマップとして代入されます。
  11. println groupedNames:グループ化された結果を表示します。結果として、名前の長さに基づいたグループ化が表示されます。

関数とメソッド[編集]

関数の定義と呼び出し[編集]

// 関数の定義
def sayHello() {
  println "Hello, World!"
}

// 関数の呼び出し
sayHello()  // 結果: Hello, World!

// 引数を受け取る関数の定義
def greet(name) {
  println "Hello, $name!"
}

// 引数を指定して関数を呼び出す
greet("Alice")  // 結果: Hello, Alice!
greet("Bob")    // 結果: Hello, Bob!

// デフォルト引数を持つ関数の定義
def calculateArea(width, height = 1) {
  width * height
}

println calculateArea(5)       // 結果: 5
println calculateArea(5, 3)    // 結果: 15

// 可変長引数を受け取る関数の定義
def sumNumbers(...numbers) {
  numbers.sum()
}

println sumNumbers(1, 2, 3)    // 結果: 6
println sumNumbers(4, 5, 6, 7) // 結果: 22

// メソッドの定義(クラス内で定義される)
class Calculator {
  static int add(int a, int b) {
    a + b
  }
}

println Calculator.add(3, 4)   // 結果: 7

このコードでは、Groovyの関数とメソッドに関する例が示されています。

  1. def sayHello():関数sayHelloを定義します。この関数は引数を受け取らずに「Hello, World!」と表示します。
  2. sayHello():関数sayHelloを呼び出して、「Hello, World!」と表示します。
  3. def greet(name):引数を受け取る関数greetを定義します。この関数は引数nameを使用して挨拶を表示します。
  4. greet("Alice"):引数を指定して関数greetを呼び出し、「Hello, Alice!」と表示します。
  5. greet("Bob"):別の引数を指定して関数greetを呼び出し、「Hello, Bob!」と表示します。
  6. def calculateArea(width, height = 1):デフォルト引数を持つ関数calculateAreaを定義します。widthheightの引数を使用して、面積を計算します。
  7. calculateArea(5):引数widthのみを指定して関数calculateAreaを呼び出し、結果として5が表示されます。
  8. calculateArea(5, 3):引数widthheightを指定して関数calculateAreaを呼び出し、結果として15が表示されます。
  9. def sumNumbers(...numbers):可変長引数を持つ関数sumNumbersを定義します。numbersの可変長引数を使用して、総和を計算します。
  10. sumNumbers(1, 2, 3):引数リスト1, 2, 3を指定して関数sumNumbersを呼び出し、結果として6が表示されます。
  11. sumNumbers(4, 5, 6, 7):引数リスト4, 5, 6, 7を指定して関数sumNumbersを呼び出し、結果として22が表示されます。
  12. class Calculator:クラスCalculatorを定義します。
  13. static int add(int a, int b):クラス内の静的メソッドaddを定義します。このメソッドは2つの整数引数abを受け取り、それらの合計を計算します。
  14. println Calculator.add(3, 4):クラスCalculatorの静的メソッドaddを呼び出し、引数3と4を渡して合計を計算し、結果として7が表示されます。

クロージャーとメソッド[編集]

// クロージャを使用した関数の定義と呼び出し
def multiplier = { x, y -> x * y }
println multiplier(3, 4)  // 結果: 12

// クラス内でのメソッドの定義と呼び出し
class Person {
  String name

  void sayHello() {
    println "Hello, I'm $name!"
  }
}

def person = new Person(name: "Alice")
person.sayHello()  // 結果: Hello, I'm Alice!
  1. def multiplier = { x, y -> x * y }:クロージャを使用して関数multiplierを定義します。このクロージャは2つの引数xyを受け取り、それらの積を返します。
  2. println multiplier(3, 4):クロージャmultiplierを呼び出し、引数3と4を渡して積を計算し、結果として12が表示されます。
  3. class Person:クラスPersonを定義します。
  4. String namePersonクラス内にnameという文字列型のプロパティを定義します。
  5. void sayHello()Personクラス内にsayHelloというメソッドを定義します。このメソッドは自己紹介のメッセージを表示します。
  6. def person = new Person(name: "Alice")Personクラスのインスタンスpersonを生成し、nameプロパティに"Alice"を設定します。
  7. person.sayHello()personインスタンスのsayHelloメソッドを呼び出し、自己紹介のメッセージを表示します。結果として、"Hello, I'm Alice!"が表示されます。

このコードでは、クロージャを使用した関数の定義と呼び出し方法が示されています。クロージャは無名関数として使用され、変数に代入して関数のように扱うことができます。

また、クラス内でのメソッドの定義と呼び出し方法も示されています。クラスを定義し、その中でメソッドを定義して使用することができます。メソッドはクラスのインスタンスに対して呼び出されます。

メソッドのオーバーロードとメソッドチェーン[編集]

// メソッドのオーバーロード
class MathUtils {
  static int add(int a, int b) {
    a + b
  }

  static double add(double a, double b) {
    a + b
  }
}

println MathUtils.add(2, 3)        // 結果: 5
println MathUtils.add(2.5, 3.5)    // 結果: 6.0

// メソッドチェーン
class StringBuilderUtils {
  StringBuilder builder

  StringBuilderUtils appendString(String str) {
    builder.append(str)
    this
  }

  StringBuilderUtils appendNumber(int num) {
    builder.append(num)
    this
  }

  String build() {
    builder.toString()
  }
}

def result = new StringBuilderUtils()
  .appendString("Hello")
  .appendString(", ")
  .appendNumber(42)
  .build()

println result  // 結果: Hello, 42
  1. class MathUtils:クラスMathUtilsを定義します。
  2. static int add(int a, int b)MathUtilsクラス内でオーバーロードされたメソッドaddを定義します。このメソッドは2つの整数引数abの和を返します。
  3. static double add(double a, double b)MathUtilsクラス内でオーバーロードされたもう一つのメソッドaddを定義します。このメソッドは2つの浮動小数点数引数abの和を返します。
  4. println MathUtils.add(2, 3)MathUtilsクラスのaddメソッドを呼び出し、整数引数2と3を渡して和を計算し、結果として5が表示されます。
  5. println MathUtils.add(2.5, 3.5)MathUtilsクラスのaddメソッドを呼び出し、浮動小数点数引数2.5と3.5を渡して和を計算し、結果として6.0が表示されます。

このコードでは、メソッドのオーバーロードが示されています。MathUtilsクラスのaddメソッドは、引数の型に応じて異なる動作をします。整数引数の場合と浮動小数点数引数の場合で、適切なメソッドが呼び出されます。

  1. class StringBuilderUtils:クラスStringBuilderUtilsを定義します。
  2. StringBuilder builderStringBuilderUtilsクラス内にbuilderというStringBuilderオブジェクトを定義します。
  3. StringBuilderUtils appendString(String str)StringBuilderUtilsクラス内にappendStringというメソッドを定義します。このメソッドは文字列引数strbuilderに追加し、thisを返します。
  4. return this;appendStringメソッドとappendNumberメソッド内で、自身のインスタンスthisを返します。これにより、メソッドチェーンを実現します。つまり、連続してメソッドを呼び出すことができます。
  5. StringBuilderUtils appendNumber(int num)StringBuilderUtilsクラス内にappendNumberというメソッドを定義します。このメソッドは整数引数numbuilderに追加し、自身のインスタンスthisを返します。
  6. String build()StringBuilderUtilsクラス内にbuildというメソッドを定義します。このメソッドはbuilderを文字列に変換して返します。
  7. def result = new StringBuilderUtils()...StringBuilderUtilsクラスのインスタンスを生成し、メソッドチェーンで複数のメソッドを呼び出します。appendStringメソッドとappendNumberメソッドを交互に呼び出し、最後にbuildメソッドを呼び出して結果を取得します。
  8. println result:結果の文字列を表示します。結果として、"Hello, 42"が表示されます。

このコードでは、メソッドチェーンの概念が示されています。 StringBuilderUtilsクラスのインスタンスを生成し、複数のメソッドを連続して呼び出すことができます。 各メソッドは自身のインスタンスを返すため、次のメソッドを続けて呼び出すことができます。 これにより、コードをシンプルに保ちながら、複数の処理を効率的に実行することができます。

メソッドのオーバーライド[編集]

// メソッドのオーバーライド
class Animal {
  void makeSound() {
    println "The animal makes a sound."
  }
}

class Cat extends Animal {
  @Override
  void makeSound() {
    println "Meow!"
  }
}

class Dog extends Animal {
  @Override
  void makeSound() {
    println "Woof!"
  }
}

def cat = new Cat()
cat.makeSound()  // 結果: Meow!

def dog = new Dog()
dog.makeSound()  // 結果: Woof!
  1. class Animal:クラスAnimalを定義します。
  2. void makeSound()Animalクラス内にmakeSoundというメソッドを定義します。このメソッドは「動物は音を出します」というメッセージを表示します。
  3. class Cat extends AnimalAnimalクラスを継承するCatクラスを定義します。
  4. @OverrideCatクラス内のmakeSoundメソッドがAnimalクラスのメソッドをオーバーライドしていることを明示します。
  5. void makeSound()Catクラス内に再定義されたmakeSoundメソッドを定義します。このメソッドは「Meow!」と表示します。
  6. class Dog extends AnimalAnimalクラスを継承するDogクラスを定義します。
  7. @OverrideDogクラス内のmakeSoundメソッドがAnimalクラスのメソッドをオーバーライドしていることを明示します。
  8. void makeSound()Dogクラス内に再定義されたmakeSoundメソッドを定義します。このメソッドは「Woof!」と表示します。
  9. def cat = new Cat()Catクラスのインスタンスcatを生成します。
  10. cat.makeSound()catインスタンスのmakeSoundメソッドを呼び出し、「Meow!」と表示します。
  11. def dog = new Dog()Dogクラスのインスタンスdogを生成します。
  12. dog.makeSound()dogインスタンスのmakeSoundメソッドを呼び出し、「Woof!」と表示します。

このコードでは、メソッドのオーバーライドが示されています。AnimalクラスにはmakeSoundメソッドがありますが、CatクラスとDogクラスではそれをオーバーライドして独自の動作を定義しています。それぞれのインスタンスを生成してメソッドを呼び出すと、適切なサウンドが表示されます。

クラスとオブジェクト[編集]

クラス定義とインスタンス化[編集]

class Person {
  String name
  int age

  void sayHello() {
    println "Hello, my name is $name and I am $age years old."
  }
}

def person1 = new Person()
person1.name = "Alice"
person1.age = 25
person1.sayHello()  // 結果: Hello, my name is Alice and I am 25 years old.

def person2 = new Person()
person2.name = "Bob"
person2.age = 30
person2.sayHello()  // 結果: Hello, my name is Bob and I am 30 years old.
  1. class PersonPersonというクラスを定義します。
  2. String namePersonクラスにnameという文字列型のプロパティを定義します。
  3. int agePersonクラスにageという整数型のプロパティを定義します。
  4. void sayHello()PersonクラスにsayHelloというメソッドを定義します。このメソッドは「Hello, my name is $name and I am $age years old.」と表示します。
  5. def person1 = new Person()Personクラスのインスタンスperson1を生成します。
  6. person1.name = "Alice"person1インスタンスのnameプロパティに"Alice"を代入します。
  7. person1.age = 25person1インスタンスのageプロパティに25を代入します。
  8. person1.sayHello()person1インスタンスのsayHelloメソッドを呼び出し、「Hello, my name is Alice and I am 25 years old.」と表示します。
  9. def person2 = new Person()Personクラスのインスタンスperson2を生成します。
  10. person2.name = "Bob"person2インスタンスのnameプロパティに"Bob"を代入します。
  11. person2.age = 30person2インスタンスのageプロパティに30を代入します。
  12. person2.sayHello()person2インスタンスのsayHelloメソッドを呼び出し、「Hello, my name is Bob and I am 30 years old.」と表示します。

このコードでは、Personというクラスが定義されています。Personクラスにはnameageというプロパティがあり、sayHelloというメソッドも定義されています。インスタンス化されたperson1person2Personクラスのオブジェクトであり、それぞれのプロパティに値を代入し、sayHelloメソッドを呼び出して自己紹介をします。

継承とオーバーライド[編集]

// 継承とオーバーライド
class Student extends Person {
  String major

  void introduce() {
    println "I am a student majoring in $major."
  }

  @Override
  void sayHello() {
    println "Hello, my name is $name, I am $age years old, and I am a student."
  }
}

def student1 = new Student()
student1.name = "Charlie"
student1.age = 20
student1.major = "Computer Science"
student1.sayHello()    // 結果: Hello, my name is Charlie, I am 20 years old, and I am a student.
student1.introduce()   // 結果: I am a student majoring in Computer Science.
  1. class Student extends PersonStudentクラスはPersonクラスを継承します。
  2. String majorStudentクラスにmajorという文字列型のプロパティを追加します。
  3. void introduce()Studentクラスにintroduceというメソッドを定義します。このメソッドは「I am a student majoring in $major.」と表示します。
  4. @OverridesayHelloメソッドをオーバーライドすることを示すアノテーションです。
  5. void sayHello()PersonクラスのsayHelloメソッドをStudentクラスでオーバーライドします。新しいメッセージ「Hello, my name is $name, I am $age years old, and I am a student.」を表示します。
  6. def student1 = new Student()Studentクラスのインスタンスstudent1を生成します。
  7. student1.name = "Charlie"student1インスタンスのnameプロパティに"Charlie"を代入します。
  8. student1.age = 20student1インスタンスのageプロパティに20を代入します。
  9. student1.major = "Computer Science"student1インスタンスのmajorプロパティに"Computer Science"を代入します。
  10. student1.sayHello()student1インスタンスのsayHelloメソッドを呼び出し、「Hello, my name is Charlie, I am 20 years old, and I am a student.」と表示します。
  11. student1.introduce()student1インスタンスのintroduceメソッドを呼び出し、「I am a student majoring in Computer Science.」と表示します。

このコードでは、StudentクラスがPersonクラスを継承しています。Studentクラスには追加のプロパティmajorとメソッドintroduceがあります。sayHelloメソッドはPersonクラスのメソッドをオーバーライドしています。

静的メソッドとプロパティ[編集]

// 静的メソッドとプロパティ
class MathUtils {
  static int add(int a, int b) {
    return a + b
  }

  static final double PI = 3.14159
}

def result = MathUtils.add(5, 3)
println result  // 結果: 8

println MathUtils.PI  // 結果: 3.14159
  1. static int add(int a, int b)MathUtilsクラスにaddという静的メソッドを定義します。このメソッドは2つの整数を受け取り、それらの和を返します。
  2. static final double PI = 3.14159MathUtilsクラスにPIという静的な定数を定義します。
  3. def result = MathUtils.add(5, 3)MathUtilsクラスの静的メソッドaddを呼び出して、53の和を計算し、結果をresult変数に代入します。
  4. println resultresult変数の値を表示します。結果は8となります。
  5. println MathUtils.PIMathUtilsクラスの静的な定数PIの値を表示します。結果は3.14159となります。

このコードでは、MathUtilsクラスが定義されています。このクラスには静的メソッドaddと静的定数PIがあります。静的メソッドはインスタンス化せずにクラス名を使って直接呼び出すことができます。同様に、静的定数もクラス名を使ってアクセスできます。result変数にはaddメソッドの結果が代入され、それが表示されます。また、MathUtils.PIPI定数の値を表示します。

コンストラクタとインスタンスメソッド[編集]

// コンストラクタとインスタンスメソッド
class Rectangle {
  int width
  int height

  Rectangle(int w, int h) {
    width = w
    height = h
  }

  int calculateArea() {
    return width * height
  }
}

def rectangle1 = new Rectangle(5, 3)
def area = rectangle1.calculateArea()
println area  // 結果: 15
  1. Rectangle(int w, int h)Rectangleクラスにコンストラクタを定義します。このコンストラクタは幅wと高さhを受け取り、それぞれの値をインスタンスのwidthheightプロパティに代入します。
  2. int calculateArea()RectangleクラスにcalculateAreaというインスタンスメソッドを定義します。このメソッドは長方形の面積を計算して返します。
  3. def rectangle1 = new Rectangle(5, 3)Rectangleクラスのインスタンスrectangle1を生成します。引数53はコンストラクタに渡されます。
  4. def area = rectangle1.calculateArea()rectangle1インスタンスのcalculateAreaメソッドを呼び出して、面積を計算し、結果をarea変数に代入します。
  5. println areaarea変数の値を表示します。結果は15となります。

このコードでは、Rectangleクラスが定義されています。このクラスにはコンストラクタとインスタンスメソッドがあります。コンストラクタはインスタンス化時に呼び出され、幅と高さの値を受け取ってインスタンスのプロパティに代入します。calculateAreaメソッドは長方形の面積を計算して返します。rectangle1Rectangleクラスのインスタンスであり、calculateAreaメソッドを呼び出して面積を計算し、その結果が表示されます。

アクセサメソッドとプロパティ[編集]

// アクセサメソッドとプロパティ
class Person {
  private String name
  private int age

  void setName(String n) {
    name = n
  }

  String getName() {
    return name
  }

  void setAge(int a) {
    age = a
  }

  int getAge() {
    return age
  }
}

def person1 = new Person()
person1.setName("Alice")
person1.setAge(25)
println person1.getName()  // 結果: Alice
println person1.getAge()   // 結果: 25
  1. private String namePersonクラスにnameというプライベートな文字列型のプロパティを定義します。外部から直接アクセスすることはできません。
  2. private int agePersonクラスにageというプライベートな整数型のプロパティを定義します。
  3. void setName(String n)PersonクラスにsetNameというメソッドを定義します。このメソッドは引数nを受け取り、nameプロパティに代入します。
  4. String getName()PersonクラスにgetNameというメソッドを定義します。このメソッドはnameプロパティの値を返します。
  5. void setAge(int a)PersonクラスにsetAgeというメソッドを定義します。このメソッドは引数aを受け取り、ageプロパティに代入します。
  6. int getAge()PersonクラスにgetAgeというメソッドを定義します。このメソッドはageプロパティの値を返します。
  7. def person1 = new Person()Personクラスのインスタンスperson1を生成します。
  8. person1.setName("Alice")person1インスタンスのsetNameメソッドを呼び出して、名前を設定します。
  9. person1.setAge(25)person1インスタンスのsetAgeメソッドを呼び出して、年齢を設定します。
  10. println person1.getName()person1インスタンスのgetNameメソッドを呼び出して、名前を表示します。
  11. println person1.getAge()person1インスタンスのgetAgeメソッドを呼び出して、年齢を表示します。

このコードでは、Personクラスにプライベートなプロパティnameageが定義されています。プロパティには外部から直接アクセスできないため、setNamesetAgeのようなメソッドを用意します。このようなメソッドをアクセサメソッドと呼びます。

継承とポリモーフィズム[編集]

// 継承とポリモーフィズム
class Animal {
  String sound() {
    return "Animal makes a sound."
  }
}

class Cat extends Animal {
  String sound() {
    return "Meow!"
  }
}

class Dog extends Animal {
  String sound() {
    return "Woof!"
  }
}

Animal animal1 = new Animal()
println animal1.sound()  // 結果: Animal makes a sound.

Animal cat1 = new Cat()
println cat1.sound()     // 結果: Meow!

Animal dog1 = new Dog()
println dog1.sound()     // 結果: Woof!
  1. class AnimalAnimalクラスが定義されています。このクラスにはsoundというメソッドがあり、"Animal makes a sound."という文字列を返します。
  2. class Cat extends AnimalCatクラスがAnimalクラスを継承しています。Catクラスはsoundメソッドをオーバーライドし、"Meow!"という文字列を返します。
  3. class Dog extends AnimalDogクラスもAnimalクラスを継承しています。Dogクラスもsoundメソッドをオーバーライドし、"Woof!"という文字列を返します。
  4. Animal animal1 = new Animal()Animalクラスのインスタンスanimal1を生成します。
  5. println animal1.sound()animal1インスタンスのsoundメソッドを呼び出して、結果を表示します。Animalクラスのsoundメソッドが実行され、"Animal makes a sound."が表示されます。
  6. Animal cat1 = new Cat()Catクラスのインスタンスcat1Animal型の変数に代入します。ポリモーフィズムの特性により、cat1Animalクラスとして扱われます。
  7. println cat1.sound()cat1インスタンスのsoundメソッドを呼び出して、結果を表示します。Catクラスのsoundメソッドが実行され、"Meow!"が表示されます。
  8. Animal dog1 = new Dog()Dogクラスのインスタンスdog1Animal型の変数に代入します。同様に、dog1Animalクラスとして扱われます。
  9. println dog1.sound()dog1インスタンスのsoundメソッドを呼び出して、結果を表示します。Dogクラスのsoundメソッドが実行され、"Woof!"が表示されます。

抽象クラスとインターフェース[編集]

// 抽象クラスとインターフェース
abstract class Shape {
  abstract double calculateArea()
  abstract double calculatePerimeter()
}

class Circle extends Shape {
  double radius

  Circle(double r) {
    radius = r
  }

  double calculateArea() {
    return Math.PI * radius * radius
  }

  double calculatePerimeter() {
    return 2 * Math.PI * radius
  }
}

interface Drawable {
  void draw()
}

class Square implements Drawable {
  double sideLength

  Square(double length) {
    sideLength = length
  }

  void draw() {
    println "Drawing a square"
  }
}

Circle circle = new Circle(5)
println "Circle area: ${circle.calculateArea()}"  // 結果: Circle area: 78.53981633974483
println "Circle perimeter: ${circle.calculatePerimeter()}"  // 結果: Circle perimeter: 31.41592653589793

Square square = new Square(10)
square.draw()  // 結果: Drawing a square
  1. abstract class ShapeShapeという抽象クラスが定義されています。このクラスはcalculateAreacalculatePerimeterという抽象メソッドを持ちます。抽象クラスは直接インスタンス化できず、継承して利用する必要があります。
  2. abstract double calculateArea()Shapeクラスには抽象メソッドcalculateAreaがあります。具体的な実装はサブクラスで行われます。
  3. abstract double calculatePerimeter()Shapeクラスには抽象メソッドcalculatePerimeterがあります。こちらも具体的な実装はサブクラスで行われます。
  4. class Circle extends ShapeCircleクラスがShapeクラスを継承しています。Circleクラスではradiusというフィールドを持ち、calculateAreacalculatePerimeterメソッドをオーバーライドしています。
  5. double calculateArea()CircleクラスにはcalculateAreaメソッドがあります。円の面積を計算して返します。
  6. interface DrawableDrawableというインターフェースが定義されています。このインターフェースはdrawというメソッドを持ちます。
  7. class Square implements DrawableSquareクラスがDrawableインターフェースを実装しています。SquareクラスはsideLengthというフィールドを持ち、drawメソッドを実装しています。
  8. Circle circle = new Circle(5)Circleクラスのインスタンスcircleを生成します。
  9. println "Circle area: ${circle.calculateArea()}"circleインスタンスのcalculateAreaメソッドを呼び出し、結果を表示します。
  10. println "Circle perimeter: ${circle.calculatePerimeter()}"circleインスタンスのcalculatePerimeterメソッドを呼び出し、結果を表示します。
  11. Square square = new Square(10)Squareクラスのインスタンスsquareを生成します。
  12. square.draw()squareインスタンスのdrawメソッドを呼び出し、結果を表示します。

このコードでは、抽象クラスとインターフェースの概念を示しています。Shapeクラスは抽象クラスであり、サブクラスであるCircleクラスがcalculateAreacalculatePerimeterメソッドを実装しています。また、Drawableインターフェースを実装するSquareクラスでは、drawメソッドを定義しています。

Circleクラスのインスタンスを作成し、calculateAreacalculatePerimeterメソッドを呼び出して円の面積と円周を計算します。また、Squareクラスのインスタンスを作成し、drawメソッドを呼び出して四角形を描画します。

結果として、円の面積と円周が表示され、四角形が描画されます。

クラスの継承とオーバーライド[編集]

// クラスの継承とオーバーライド
class Vehicle {
  String brand

  Vehicle(String brand) {
    this.brand = brand
  }

  void drive() {
    println "Driving the $brand vehicle"
  }
}

class Car extends Vehicle {
  Car(String brand) {
    super(brand)
  }

  @Override
  void drive() {
    println "Driving the $brand car"
  }
}

class Bicycle extends Vehicle {
  Bicycle(String brand) {
    super(brand)
  }

  @Override
  void drive() {
    println "Riding the $brand bicycle"
  }
}

Vehicle vehicle = new Vehicle("Generic")
vehicle.drive()  // 結果: Driving the Generic vehicle

Car car = new Car("Toyota")
car.drive()  // 結果: Driving the Toyota car

Bicycle bicycle = new Bicycle("Giant")
bicycle.drive()  // 結果: Riding the Giant bicycle
  1. class VehicleVehicleクラスが定義されています。このクラスはbrandというフィールドを持ち、driveというメソッドがあります。
  2. Vehicle(String brand)Vehicleクラスのコンストラクタです。引数で渡されたbrandをインスタンスフィールドに代入します。
  3. void drive()Vehicleクラスにはdriveメソッドがあります。デフォルトの実装では、"$brand vehicle"と表示します。
  4. class Car extends VehicleCarクラスがVehicleクラスを継承しています。Carクラスでは、親クラスのコンストラクタを呼び出すためのsuperキーワードを使用しています。
  5. @OverrideCarクラスのdriveメソッドには@Overrideアノテーションが付いています。これは、メソッドが親クラスのメソッドをオーバーライドしていることを示しています。
  6. void drive()Carクラスにはオーバーライドされたdriveメソッドがあります。"Driving the $brand car"と表示します。
  7. class Bicycle extends VehicleBicycleクラスもVehicleクラスを継承しています。同様に、親クラスのコンストラクタを呼び出すためのsuperキーワードを使用しています。
  8. @OverrideBicycleクラスのdriveメソッドにも@Overrideアノテーションが付いています。
  9. void drive()Bicycleクラスにはオーバーライドされたdriveメソッドがあります。"Riding the $brand bicycle"と表示します。
  10. Vehicle vehicle = new Vehicle("Generic")Vehicleクラスのインスタンスvehicleを生成します。
  11. vehicle.drive()vehicle.drive() // 結果: Driving the Generic vehicle
  12. Car car = new Car("Toyota")Carクラスのインスタンスcarを生成します。
  13. car.drive()carインスタンスのdriveメソッドを呼び出し、結果を表示します。
  14. Bicycle bicycle = new Bicycle("Giant")Bicycleクラスのインスタンスbicycleを生成します。
  15. bicycle.drive()bicycleインスタンスのdriveメソッドを呼び出し、結果を表示します。

このコードでは、クラスの継承とメソッドのオーバーライドの例を示しています。Vehicleクラスは親クラスとして定義されており、CarクラスとBicycleクラスがそれを継承しています。

Vehicleクラスのインスタンスを作成し、driveメソッドを呼び出すと、"Driving the Generic vehicle"と表示されます。

Carクラスのインスタンスを作成し、driveメソッドを呼び出すと、"Driving the Toyota car"と表示されます。Carクラスでは@Overrideアノテーションを使用してdriveメソッドをオーバーライドしています。

Bicycleクラスのインスタンスを作成し、driveメソッドを呼び出すと、"Riding the Giant bicycle"と表示されます。同様に、Bicycleクラスでもdriveメソッドをオーバーライドしています。

これにより、異なるクラスが親クラスのメソッドをオーバーライドし、それぞれの特定の動作を実行することができるようになります。

Groovyの応用[編集]

ファイル入出力[編集]

正規表現[編集]

XMLの処理[編集]

JSONの処理[編集]

データベースアクセス[編集]

Webアプリケーション開発[編集]

テスト自動化[編集]

Groovyスクリプトの実行[編集]

Groovyの拡張[編集]

Groovy DSLの作成[編集]

AST変換[編集]

Groovyメタプログラミング[編集]

GroovyのJava統合[編集]

Grailsの紹介[編集]

Groovyの最新トピックス[編集]

非同期処理[編集]

リアクティブプログラミング[編集]

マルチスレッド処理[編集]

Groovyの最新機能[編集]

Groovyの将来展望[編集]

付録:Groovyリファレンス[編集]

// コメントはこのように書くことができます

// 変数の宣言
def x = 10
def y = "Hello World"
def z = true

// 文字列の出力
println "x = ${x}, y = ${y}, z = ${z}"

// 制御フロー
if (x > 5) {
    println "x is greater than 5"
} else {
    println "x is less than or equal to 5"
}

// ループ
for (i in 0..4) {
    println i
}

// リスト
def myList = [1, 2, 3, 4, 5]

// リストの要素を出力
println myList[0]
println myList[-1]

// リストの要素をループで出力
myList.each { println it }

// リストの操作
myList.add(6)
myList.remove(2)
myList.each { println it }

// マップ
def myMap = [key1: "value1", key2: "value2", key3: "value3"]

// マップの値を出力
println myMap.key1
println myMap["key2"]
println myMap.get("key3")

// マップのキーと値をループで出力
myMap.each { key, value -> println "${key} = ${value}" }

// クラス
class MyClass {
    def myMethod() {
        println "My Method"
    }
}

// クラスのインスタンス化とメソッドの呼び出し
def myObject = new MyClass()
myObject.myMethod()

// 継承
class MySubClass extends MyClass {
    def mySubMethod() {
        println "My Sub Method"
    }
}

// サブクラスのインスタンス化とメソッドの呼び出し
def mySubObject = new MySubClass()
mySubObject.myMethod()
mySubObject.mySubMethod()

Groovyの文法やAPIのリファレンス[編集]

文法[編集]

変数宣言と初期化
Groovyでは、変数の型宣言が必要ありません。また、変数の初期化が必要な場合でも、初期値を省略することができます。
def age = 30
メソッドの定義
Groovyでは、メソッドの引数リストや戻り値型を省略することができます。また、メソッド名に対して引数を指定することもできます。
def sayHello(name) {
    println "Hello, $name!"
}
文字列の操作
Groovyでは、文字列の連結に+演算子を使用することができます。また、文字列内に変数や式を埋め込むことができます。
def name = "John"
def message = "Hello, ${name}!"
リストやマップの操作
Groovyでは、リストやマップの要素に対して、ドット演算子を使用して直接操作することができます。
def list = [1, 2, 3]
def map = [name: 'John', age: 30]
list.add(4)
map.age = 31
スコープ
Groovyでは、変数のスコープを明示的に指定することができます。また、クロージャやグローバル変数の定義にも対応しています。

API[編集]

文字列関連
Groovyでは、JavaのStringクラスに加え、文字列操作を容易にするための拡張メソッドが用意されています。例えば、文字列の先頭や末尾に文字列を追加することができます。
def str = "Hello"
str = str.plus(" World")
コレクション関連
Groovyでは、JavaのCollectionやMapなどのインタフェースに対して、拡張メソッドが用意されています。例えば、リストやマップから特定の要素を取得するメソッドや、条件に合致する要素を抽出するメソッドなどがあります。
def list = [1, 2, 3, 4, 5]
def evenList = list.findAll { it % 2 == 0 }
ファイル入出力関連
Groovyでは、JavaのFileクラスに加え、ファイル入出力を容易にするための拡張メソッドが用意されています。例えば、ファイルから一行ずつ読み込んで処理をするメソッドや、ファイルに書き込むメソッドがあります。
def file = new File("example.txt")
file.eachLine { line -> println line }
file.write("Hello, world!")
並列処理関連
Groovyでは、Javaの並列処理ライブラリであるJava.util.concurrentパッケージを利用することができます。また、Groovy独自の並列処理機能も用意されています。例えば、Parallelコレクションを使用して、複数のスレッドでコレクションを処理することができます。
def list = (1..10)
def parallelList = list.parallel()
parallelList.each { println it }

以上は、Groovyの文法やAPIの一部です。GroovyはJavaの拡張版であるため、Javaと同じく、オブジェクト指向言語としての特性を持っています。Groovyの機能を活用することで、Javaよりも簡潔で表現力豊かなコードを書くことができます。また、Javaのライブラリを容易に使用することができるため、Java開発者にとっても親和性が高い言語となっています。

よく使うGroovyのコード例[編集]