Groovy
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と同様にランタイム時に型エラーが検出されます。
- 関数型プログラミング:Rubyは、関数型プログラミングの特徴も持ち、簡潔なコードで高度な処理が可能です。一方、Groovyは、オブジェクト指向プログラミングが中心となっています。
- メタプログラミング:Rubyは、Groovyと同様に強力なメタプログラミング機能を提供しています。Rubyのメタプログラミング機能は、非常に強力であり、DSL(Domain-Specific Language)の開発にも向いています。
- 実行速度:Rubyは、Groovyよりも実行速度が遅く、大規模なアプリケーションには向かない場合があります。一方、Rubyは、高い生産性を持ち、短い時間でコードを書くことができます。
- コーディングスタイル:Rubyは、Groovyと同様に柔軟なスタイルでコーディングできます。ただし、Rubyには独自のスタイルがあり、初心者には学習コストがかかる場合があります。
Groovyのインストールと設定
編集Groovyの開発にはJREまたはJDKが必要です。まず、JREまたはJDKをインストールしてください。
GroovyはApacheのWebサイトからダウンロードできます。以下の手順に従って、Groovyをインストールしてください。
- GroovyのWebサイトにアクセスし、Groovyダウンロードページに移動します。
- ダウンロードページで、最新のバージョンを選択します。zipファイル形式を使用することをお勧めします。
- ダウンロードを開始する前に、Apacheアカウントにサインアップする必要がある場合があります。アカウントを持っていない場合は、新規登録してください。
- zipファイルをダウンロードし、適当なディレクトリに展開します。
- 環境変数を設定します。PATH環境変数にGroovyのbinフォルダへのパスを追加します。
- 文法:Javaは、静的な型付けの言語であり、コンパイル時に型エラーを検出できます。一方、Groovyは動的な型付けの言語であり、ランタイム時に型エラーが検出されます。Groovyは、Javaよりも簡潔な文法を持ち、コードの書き方が自由度が高いです。
- コードの量:Groovyは、Javaよりも短く、コードの書き方が自由度が高いため、同じ機能を実現するためのコードの量が少なくて済む場合があります。
- メタプログラミング:Groovyは、Javaよりも強力なメタプログラミング機能を提供しています。メタプログラミングとは、プログラムが自己修正することができる機能のことで、GroovyはJavaに比べてメタプログラミングが簡単に実現できます。
- 実行速度:Javaは、コンパイル時に最適化されるため、実行速度が速く、大規模なアプリケーションに適しています。一方、Groovyは、動的型付けのため、実行速度が遅い場合があります。
- コーディングスタイル:Javaは、コードのスタイルを統一するための多くの規則がありますが、Groovyは、柔軟なスタイルでコーディングできます。
変数とデータ型
編集Groovyでは、変数とデータ型について以下のように説明できます:
- 動的型付けな変数: Groovyは動的型付け言語です。変数を宣言する際に、その型を明示的に指定する必要はありません。変数に代入される値によって、その型が自動的に決定されます。例えば:
def x = 10 // 動的型付けされた変数 x = "ABC" // 可能
- 静的型付けな変数: 静的型付けもサポートされており、変数宣言時に型を明示的に指定することができます。この場合、変数はその型の値しか受け付けません。例えば:
String name = "John" // 静的型付けされた変数 // name = 42 // コンパイルエラー
- データ型: 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"
では、name
がnull
であれば"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
文は、条件式が真であることをアサーション(検証)します。もし条件式が偽の場合、アサーションエラーが発生し、プログラムの実行が停止します。この例では、x
がy
よりも大きいことを検証しています。
三項演算子とnull安全演算子を組み合わせることで、nullチェックと条件付きの値の代入を行うことができます。name?.length() > 0
は、name
がnull
でない場合にのみ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のリスト操作とコレクション演算子に関する例です。以下に各部分の解説をします。
def numbers = [1, 2, 3, 4, 5]
:整数のリストを作成します。numbers.each { num -> println num }
:each
メソッドを使用してリストの要素を繰り返し処理し、各要素を表示します。結果として、リストの要素1から5が順番に表示されます。def squaredNumbers = numbers.collect { num -> num * num }
:collect
メソッドを使用してリストの要素を変換します。各要素を2乗した結果を含む新しいリストを生成します。squaredNumbers
には[1, 4, 9, 16, 25]というリストが代入されます。println squaredNumbers
:変換されたリストsquaredNumbers
を表示します。結果として、[1, 4, 9, 16, 25]が表示されます。def evenNumbers = numbers.findAll { num -> num % 2 == 0 }
:findAll
メソッドを使用して条件に合致する要素を抽出します。この場合、リストの中から偶数の要素を抽出し、新しいリストを生成します。evenNumbers
には[2, 4]というリストが代入されます。println evenNumbers
:抽出された偶数のリストevenNumbers
を表示します。結果として、[2, 4]が表示されます。def sum = numbers.inject { result, num -> result + num }
:inject
メソッドを使用してリストの要素を累積的に演算します。各要素を順番に足し合わせて合計値を計算します。sum
には15が代入されます。println sum
:合計値sum
を表示します。結果として、15が表示されます。def names = ["Alice", "Bob", "Charlie", "Amy", "David"]
:文字列のリストを作成します。def groupedNames = names.groupBy { name -> name.length() }
:groupBy
メソッドを使用してリストの要素を指定されたクロージャの戻り値に基づいてグループ化します。ここでは、名前の長さをキーとしてグループ化します。groupedNames
にはグループ化された結果がマップとして代入されます。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の関数とメソッドに関する例が示されています。
def sayHello()
:関数sayHello
を定義します。この関数は引数を受け取らずに「Hello, World!」と表示します。sayHello()
:関数sayHello
を呼び出して、「Hello, World!」と表示します。def greet(name)
:引数を受け取る関数greet
を定義します。この関数は引数name
を使用して挨拶を表示します。greet("Alice")
:引数を指定して関数greet
を呼び出し、「Hello, Alice!」と表示します。greet("Bob")
:別の引数を指定して関数greet
を呼び出し、「Hello, Bob!」と表示します。def calculateArea(width, height = 1)
:デフォルト引数を持つ関数calculateArea
を定義します。width
とheight
の引数を使用して、面積を計算します。calculateArea(5)
:引数width
のみを指定して関数calculateArea
を呼び出し、結果として5が表示されます。calculateArea(5, 3)
:引数width
とheight
を指定して関数calculateArea
を呼び出し、結果として15が表示されます。def sumNumbers(...numbers)
:可変長引数を持つ関数sumNumbers
を定義します。numbers
の可変長引数を使用して、総和を計算します。sumNumbers(1, 2, 3)
:引数リスト1, 2, 3
を指定して関数sumNumbers
を呼び出し、結果として6が表示されます。sumNumbers(4, 5, 6, 7)
:引数リスト4, 5, 6, 7
を指定して関数sumNumbers
を呼び出し、結果として22が表示されます。class Calculator
:クラスCalculator
を定義します。static int add(int a, int b)
:クラス内の静的メソッドadd
を定義します。このメソッドは2つの整数引数a
とb
を受け取り、それらの合計を計算します。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!
def multiplier = { x, y -> x * y }
:クロージャを使用して関数multiplier
を定義します。このクロージャは2つの引数x
とy
を受け取り、それらの積を返します。println multiplier(3, 4)
:クロージャmultiplier
を呼び出し、引数3と4を渡して積を計算し、結果として12が表示されます。class Person
:クラスPerson
を定義します。String name
:Person
クラス内にname
という文字列型のプロパティを定義します。void sayHello()
:Person
クラス内にsayHello
というメソッドを定義します。このメソッドは自己紹介のメッセージを表示します。def person = new Person(name: "Alice")
:Person
クラスのインスタンスperson
を生成し、name
プロパティに"Alice"を設定します。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
class MathUtils
:クラスMathUtils
を定義します。static int add(int a, int b)
:MathUtils
クラス内でオーバーロードされたメソッドadd
を定義します。このメソッドは2つの整数引数a
とb
の和を返します。static double add(double a, double b)
:MathUtils
クラス内でオーバーロードされたもう一つのメソッドadd
を定義します。このメソッドは2つの浮動小数点数引数a
とb
の和を返します。println MathUtils.add(2, 3)
:MathUtils
クラスのadd
メソッドを呼び出し、整数引数2と3を渡して和を計算し、結果として5が表示されます。println MathUtils.add(2.5, 3.5)
:MathUtils
クラスのadd
メソッドを呼び出し、浮動小数点数引数2.5と3.5を渡して和を計算し、結果として6.0が表示されます。
このコードでは、メソッドのオーバーロードが示されています。MathUtils
クラスのadd
メソッドは、引数の型に応じて異なる動作をします。整数引数の場合と浮動小数点数引数の場合で、適切なメソッドが呼び出されます。
class StringBuilderUtils
:クラスStringBuilderUtils
を定義します。StringBuilder builder
:StringBuilderUtils
クラス内にbuilder
というStringBuilder
オブジェクトを定義します。StringBuilderUtils appendString(String str)
:StringBuilderUtils
クラス内にappendString
というメソッドを定義します。このメソッドは文字列引数str
をbuilder
に追加し、this
を返します。return this;
:appendString
メソッドとappendNumber
メソッド内で、自身のインスタンスthis
を返します。これにより、メソッドチェーンを実現します。つまり、連続してメソッドを呼び出すことができます。StringBuilderUtils appendNumber(int num)
:StringBuilderUtils
クラス内にappendNumber
というメソッドを定義します。このメソッドは整数引数num
をbuilder
に追加し、自身のインスタンスthis
を返します。String build()
:StringBuilderUtils
クラス内にbuild
というメソッドを定義します。このメソッドはbuilder
を文字列に変換して返します。def result = new StringBuilderUtils()...
:StringBuilderUtils
クラスのインスタンスを生成し、メソッドチェーンで複数のメソッドを呼び出します。appendString
メソッドとappendNumber
メソッドを交互に呼び出し、最後にbuild
メソッドを呼び出して結果を取得します。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!
class Animal
:クラスAnimal
を定義します。void makeSound()
:Animal
クラス内にmakeSound
というメソッドを定義します。このメソッドは「動物は音を出します」というメッセージを表示します。class Cat extends Animal
:Animal
クラスを継承するCat
クラスを定義します。@Override
:Cat
クラス内のmakeSound
メソッドがAnimal
クラスのメソッドをオーバーライドしていることを明示します。void makeSound()
:Cat
クラス内に再定義されたmakeSound
メソッドを定義します。このメソッドは「Meow!」と表示します。class Dog extends Animal
:Animal
クラスを継承するDog
クラスを定義します。@Override
:Dog
クラス内のmakeSound
メソッドがAnimal
クラスのメソッドをオーバーライドしていることを明示します。void makeSound()
:Dog
クラス内に再定義されたmakeSound
メソッドを定義します。このメソッドは「Woof!」と表示します。def cat = new Cat()
:Cat
クラスのインスタンスcat
を生成します。cat.makeSound()
:cat
インスタンスのmakeSound
メソッドを呼び出し、「Meow!」と表示します。def dog = new Dog()
:Dog
クラスのインスタンスdog
を生成します。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.
class Person
:Person
というクラスを定義します。String name
:Person
クラスにname
という文字列型のプロパティを定義します。int age
:Person
クラスにage
という整数型のプロパティを定義します。void sayHello()
:Person
クラスにsayHello
というメソッドを定義します。このメソッドは「Hello, my name is $name and I am $age years old.」と表示します。def person1 = new Person()
:Person
クラスのインスタンスperson1
を生成します。person1.name = "Alice"
:person1
インスタンスのname
プロパティに"Alice"
を代入します。person1.age = 25
:person1
インスタンスのage
プロパティに25
を代入します。person1.sayHello()
:person1
インスタンスのsayHello
メソッドを呼び出し、「Hello, my name is Alice and I am 25 years old.」と表示します。def person2 = new Person()
:Person
クラスのインスタンスperson2
を生成します。person2.name = "Bob"
:person2
インスタンスのname
プロパティに"Bob"
を代入します。person2.age = 30
:person2
インスタンスのage
プロパティに30
を代入します。person2.sayHello()
:person2
インスタンスのsayHello
メソッドを呼び出し、「Hello, my name is Bob and I am 30 years old.」と表示します。
このコードでは、Person
というクラスが定義されています。Person
クラスにはname
とage
というプロパティがあり、sayHello
というメソッドも定義されています。インスタンス化されたperson1
とperson2
はPerson
クラスのオブジェクトであり、それぞれのプロパティに値を代入し、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.
class Student extends Person
:Student
クラスはPerson
クラスを継承します。String major
:Student
クラスにmajor
という文字列型のプロパティを追加します。void introduce()
:Student
クラスにintroduce
というメソッドを定義します。このメソッドは「I am a student majoring in $major.」と表示します。@Override
:sayHello
メソッドをオーバーライドすることを示すアノテーションです。void sayHello()
:Person
クラスのsayHello
メソッドをStudent
クラスでオーバーライドします。新しいメッセージ「Hello, my name is $name, I am $age years old, and I am a student.」を表示します。def student1 = new Student()
:Student
クラスのインスタンスstudent1
を生成します。student1.name = "Charlie"
:student1
インスタンスのname
プロパティに"Charlie"
を代入します。student1.age = 20
:student1
インスタンスのage
プロパティに20
を代入します。student1.major = "Computer Science"
:student1
インスタンスのmajor
プロパティに"Computer Science"
を代入します。student1.sayHello()
:student1
インスタンスのsayHello
メソッドを呼び出し、「Hello, my name is Charlie, I am 20 years old, and I am a student.」と表示します。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
static int add(int a, int b)
:MathUtils
クラスにadd
という静的メソッドを定義します。このメソッドは2つの整数を受け取り、それらの和を返します。static final double PI = 3.14159
:MathUtils
クラスにPI
という静的な定数を定義します。def result = MathUtils.add(5, 3)
:MathUtils
クラスの静的メソッドadd
を呼び出して、5
と3
の和を計算し、結果をresult
変数に代入します。println result
:result
変数の値を表示します。結果は8
となります。println MathUtils.PI
:MathUtils
クラスの静的な定数PI
の値を表示します。結果は3.14159
となります。
このコードでは、MathUtils
クラスが定義されています。このクラスには静的メソッドadd
と静的定数PI
があります。静的メソッドはインスタンス化せずにクラス名を使って直接呼び出すことができます。同様に、静的定数もクラス名を使ってアクセスできます。result
変数にはadd
メソッドの結果が代入され、それが表示されます。また、MathUtils.PI
はPI
定数の値を表示します。
コンストラクタとインスタンスメソッド
編集// コンストラクタとインスタンスメソッド 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
Rectangle(int w, int h)
:Rectangle
クラスにコンストラクタを定義します。このコンストラクタは幅w
と高さh
を受け取り、それぞれの値をインスタンスのwidth
とheight
プロパティに代入します。int calculateArea()
:Rectangle
クラスにcalculateArea
というインスタンスメソッドを定義します。このメソッドは長方形の面積を計算して返します。def rectangle1 = new Rectangle(5, 3)
:Rectangle
クラスのインスタンスrectangle1
を生成します。引数5
と3
はコンストラクタに渡されます。def area = rectangle1.calculateArea()
:rectangle1
インスタンスのcalculateArea
メソッドを呼び出して、面積を計算し、結果をarea
変数に代入します。println area
:area
変数の値を表示します。結果は15
となります。
このコードでは、Rectangle
クラスが定義されています。このクラスにはコンストラクタとインスタンスメソッドがあります。コンストラクタはインスタンス化時に呼び出され、幅と高さの値を受け取ってインスタンスのプロパティに代入します。calculateArea
メソッドは長方形の面積を計算して返します。rectangle1
はRectangle
クラスのインスタンスであり、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
private String name
:Person
クラスにname
というプライベートな文字列型のプロパティを定義します。外部から直接アクセスすることはできません。private int age
:Person
クラスにage
というプライベートな整数型のプロパティを定義します。void setName(String n)
:Person
クラスにsetName
というメソッドを定義します。このメソッドは引数n
を受け取り、name
プロパティに代入します。String getName()
:Person
クラスにgetName
というメソッドを定義します。このメソッドはname
プロパティの値を返します。void setAge(int a)
:Person
クラスにsetAge
というメソッドを定義します。このメソッドは引数a
を受け取り、age
プロパティに代入します。int getAge()
:Person
クラスにgetAge
というメソッドを定義します。このメソッドはage
プロパティの値を返します。def person1 = new Person()
:Person
クラスのインスタンスperson1
を生成します。person1.setName("Alice")
:person1
インスタンスのsetName
メソッドを呼び出して、名前を設定します。person1.setAge(25)
:person1
インスタンスのsetAge
メソッドを呼び出して、年齢を設定します。println person1.getName()
:person1
インスタンスのgetName
メソッドを呼び出して、名前を表示します。println person1.getAge()
:person1
インスタンスのgetAge
メソッドを呼び出して、年齢を表示します。
このコードでは、Person
クラスにプライベートなプロパティname
とage
が定義されています。プロパティには外部から直接アクセスできないため、setName
とsetAge
のようなメソッドを用意します。このようなメソッドをアクセサメソッドと呼びます。
継承とポリモーフィズム
編集// 継承とポリモーフィズム 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!
class Animal
:Animal
クラスが定義されています。このクラスにはsound
というメソッドがあり、"Animal makes a sound."という文字列を返します。class Cat extends Animal
:Cat
クラスがAnimal
クラスを継承しています。Cat
クラスはsound
メソッドをオーバーライドし、"Meow!"という文字列を返します。class Dog extends Animal
:Dog
クラスもAnimal
クラスを継承しています。Dog
クラスもsound
メソッドをオーバーライドし、"Woof!"という文字列を返します。Animal animal1 = new Animal()
:Animal
クラスのインスタンスanimal1
を生成します。println animal1.sound()
:animal1
インスタンスのsound
メソッドを呼び出して、結果を表示します。Animal
クラスのsound
メソッドが実行され、"Animal makes a sound."が表示されます。Animal cat1 = new Cat()
:Cat
クラスのインスタンスcat1
をAnimal
型の変数に代入します。ポリモーフィズムの特性により、cat1
はAnimal
クラスとして扱われます。println cat1.sound()
:cat1
インスタンスのsound
メソッドを呼び出して、結果を表示します。Cat
クラスのsound
メソッドが実行され、"Meow!"が表示されます。Animal dog1 = new Dog()
:Dog
クラスのインスタンスdog1
をAnimal
型の変数に代入します。同様に、dog1
はAnimal
クラスとして扱われます。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
abstract class Shape
:Shape
という抽象クラスが定義されています。このクラスはcalculateArea
とcalculatePerimeter
という抽象メソッドを持ちます。抽象クラスは直接インスタンス化できず、継承して利用する必要があります。abstract double calculateArea()
:Shape
クラスには抽象メソッドcalculateArea
があります。具体的な実装はサブクラスで行われます。abstract double calculatePerimeter()
:Shape
クラスには抽象メソッドcalculatePerimeter
があります。こちらも具体的な実装はサブクラスで行われます。class Circle extends Shape
:Circle
クラスがShape
クラスを継承しています。Circle
クラスではradius
というフィールドを持ち、calculateArea
とcalculatePerimeter
メソッドをオーバーライドしています。double calculateArea()
:Circle
クラスにはcalculateArea
メソッドがあります。円の面積を計算して返します。interface Drawable
:Drawable
というインターフェースが定義されています。このインターフェースはdraw
というメソッドを持ちます。class Square implements Drawable
:Square
クラスがDrawable
インターフェースを実装しています。Square
クラスはsideLength
というフィールドを持ち、draw
メソッドを実装しています。Circle circle = new Circle(5)
:Circle
クラスのインスタンスcircle
を生成します。println "Circle area: ${circle.calculateArea()}"
:circle
インスタンスのcalculateArea
メソッドを呼び出し、結果を表示します。println "Circle perimeter: ${circle.calculatePerimeter()}"
:circle
インスタンスのcalculatePerimeter
メソッドを呼び出し、結果を表示します。Square square = new Square(10)
:Square
クラスのインスタンスsquare
を生成します。square.draw()
:square
インスタンスのdraw
メソッドを呼び出し、結果を表示します。
このコードでは、抽象クラスとインターフェースの概念を示しています。Shape
クラスは抽象クラスであり、サブクラスであるCircle
クラスがcalculateArea
とcalculatePerimeter
メソッドを実装しています。また、Drawable
インターフェースを実装するSquare
クラスでは、draw
メソッドを定義しています。
Circle
クラスのインスタンスを作成し、calculateArea
とcalculatePerimeter
メソッドを呼び出して円の面積と円周を計算します。また、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
class Vehicle
:Vehicle
クラスが定義されています。このクラスはbrand
というフィールドを持ち、drive
というメソッドがあります。Vehicle(String brand)
:Vehicle
クラスのコンストラクタです。引数で渡されたbrand
をインスタンスフィールドに代入します。void drive()
:Vehicle
クラスにはdrive
メソッドがあります。デフォルトの実装では、"$brand vehicle"と表示します。class Car extends Vehicle
:Car
クラスがVehicle
クラスを継承しています。Car
クラスでは、親クラスのコンストラクタを呼び出すためのsuper
キーワードを使用しています。@Override
:Car
クラスのdrive
メソッドには@Override
アノテーションが付いています。これは、メソッドが親クラスのメソッドをオーバーライドしていることを示しています。void drive()
:Car
クラスにはオーバーライドされたdrive
メソッドがあります。"Driving the $brand car"と表示します。class Bicycle extends Vehicle
:Bicycle
クラスもVehicle
クラスを継承しています。同様に、親クラスのコンストラクタを呼び出すためのsuper
キーワードを使用しています。@Override
:Bicycle
クラスのdrive
メソッドにも@Override
アノテーションが付いています。void drive()
:Bicycle
クラスにはオーバーライドされたdrive
メソッドがあります。"Riding the $brand bicycle"と表示します。Vehicle vehicle = new Vehicle("Generic")
:Vehicle
クラスのインスタンスvehicle
を生成します。vehicle.drive()
:vehicle.drive()
// 結果: Driving the Generic vehicleCar car = new Car("Toyota")
:Car
クラスのインスタンスcar
を生成します。car.drive()
:car
インスタンスのdrive
メソッドを呼び出し、結果を表示します。Bicycle bicycle = new Bicycle("Giant")
:Bicycle
クラスのインスタンスbicycle
を生成します。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開発者にとっても親和性が高い言語となっています。