倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

Groovy in Addiction (2) : 基本データ型

今回は基本データ型、特に数値について『Groovyイン・アクション』Chapter3 を参考にしています(一覧)。

Groovyイン・アクション

Groovyイン・アクション

Groovy の基本的アプローチ

  • 値 → オブジェクト(参照として扱われる)
  • 演算子 → メソッド呼び出し
  • Java と Groovy の境界を越えるときに、自動的に boxing/unboxing が行われる

数値リテラル

リテラルの例
java.lang.Integer 15, 0x1234ffff
java.lang.Long 100L*1
java.lang.Float 1.23f, 4.56F
java.lang.Double 1.23d, 4.56D
java.math.BigInteger 123g, 456G
java.math.BigDecimal 1.23, 4.5e6, 7.8E9, 1.23g, 4.56G

数値リテラルの宣言、型指定


数値リテラルの宣言をあれこれ列挙。 Byte, Short は省略

//***** Integer *****
int i1 = 1
Integer i2 = 1
def i3 = 1
def i4 = (int)1
def i5 = (Integer)1
def i6 = 1 as int
def i7 = 1 as Integer
//***** Long *****
long l1 = 1
Long l2 = 1
def l3 = 1L
def l4 = (long)1
def l5 = (Long)1
def l6 = 1 as long
def l7 = 1 as Long
//***** Float *****
float f1 = 1
Float f2 = 1
def f3 = 1f
def f4 = 1F
def f5 = (float)1
def f6 = (Float)1
def f7 = 1 as float
def f8 = 1 as Float
//***** Double *****
double d1 = 1
Double d2 = 1
def d3 = 1d
def d4 = 1D
def d5 = (double)1
def d6 = (Double)1
def d7 = 1 as double
def d8 = 1 as Double
//***** BigInteger *****
BigInteger bi1 = 1
def bi2 = 1g
def bi3 = 1G
def bi4 = (BigInteger)1
def bi5 = 1 as BigInteger
//***** BigDecimal *****
BigDecimal bd1 = 1
def bd2 = 1.0
def bd3 = 1.0g
def bd4 = 1.0G
def bd5 = (BigDecimal)1
def bd6 = 1 as BigDecimal
//***** Character *****
char c1 = 'a'
Character c2 = 'a'
char c3 = 0x61
Character c4 = 0x61
def c5 = (char)0x61
def c6 = (Character)0x61
def c7 = 'a' as char
def c8 = 'a' as Character
def c9 = 'a'.toCharacter()

演算子オーバーライド、演算子オーバーロード、演算子実装


特に言葉の細かな違いを気にする必要なし。 「演算子オーバーロード」が一般的なのかな?

  • Groovy での演算子はすべてメソッド呼び出し
  • 特定のインターフェースを実装する必要はない。 メソッド名と引数の個数が一致していれば良さそう。

こちらを優先して参照。

単項演算子

演算子 メソッド 対象
+a a.positive() 整数
-a a.negative() 整数
~a a.bitwiseNegate() 整数、文字列
a++, ++a a.next() 数値、文字列、範囲
a--, --a a.previous() 数値、文字列、範囲

Groovyイン・アクション』には positive(), negative(), bitwiseNegate() がなく、代わりに negate() が載ってますが、Groovy1.7 では動かなかったので省略。

2項演算子

演算子 メソッド 対象
a + b a.plus(b) 数値、文字列、コレクション
a - b a.minus(b) 数値、文字列、コレクション
a * b a.multiply(b) 数値、文字列、コレクション
a / b a.div(b) 数値、文字列
a % b a.mod(b) 数値、文字列
a**b a.power(b) 数値
a | b a.or(b) 整数
a & b a.and(b) 整数
a ^ b a.xor(b) 整数
a << b a.leftShift(b) 整数。 StringBuilder, Writer, File, Socket, リストなどへの「追加」
a >> b a.rightShift(b) 整数
a >>> b a.rightShiftUnsigned(b) 整数
a == b a.equals(b) オブジェクト
a != b ! a.equals(b) オブジェクト
a <=> b a.compareTo(b) java.lang.Comparable
a < b a.compareTo(b) < 0 java.lang.Comparable
a <= b a.compareTo(b) <= 0 java.lang.Comparable
a > b a.compareTo(b) > 0 java.lang.Comparable
a >= b a.compareTo(b) >= 0 java.lang.Comparable

==演算子equals() メソッドを呼び出すことに注意。 Java ではこれらは別物。

その他

演算子 メソッド 対象
switch(a){
 case b:
}
b.isCase(a) オブジェクト、範囲、リスト、コレクション、パターン、クロージャ
コレクション c に対する c.grep(b)
a[b] a.getAt(b) オブジェクト、リスト、マップ、文字列、配列
a[b] = c a.putAt(b, c) オブジェクト、リスト、マップ、StringBuilder、配列
a as type a.asType(typeClass) 任意の型

強制型変換


演算子「+, -, *」について、計算結果の型を表に(『Groovyイン・アクション』より)。 結果が Byte, Short, Character, Float になることはない模様:

+-* Byte Short Integer Character Long BigInteger BigDecimal Float Double
Byte I I I I L BI BD D D
Short I I I I L BI BD D D
Integer I I I I L BI BD D D
Character I I I I L BI BD D D
Long L L L L L BI BD D D
BigInteger BI BI BI BI BI BI BD D D
BigDecimal BD BD BD BD BD BD BD D D
Float D D D D D D D D D
Double D D D D D D D D D

他の演算子も含めていくつかサンプルを:

//***** 整数 *****
def x1 = 1f * 2f
assert x1 == 2d
assert x1 instanceof Double // Java では Float

def x2 = ((byte)1) + ((byte)2)
assert x2 == 3
assert x2 instanceof Integer // Java では Byte

def x3 = Integer.MAX_VALUE + 1
assert x3 == Integer.MIN_VALUE
assert x3 instanceof Integer

def x4 = 1 / 2
assert x4 == 0.5  // Java では 0
assert x4 instanceof BigDecimal // Java では Integer

def x5 = 1.intdiv(2)  // Java での 1 / 2 と同じ
assert x5 == 0
assert x5 instanceof Integer

注意が必要なのは「1 / 2 == 0.5」でしょうか。 Java での整数の割り算をしたい場合は intdiv() メソッドを使う必要があります。

//***** 冪乗演算子 *****
def p1 = 2**30
assert p1 == 1073741824
assert p1 instanceof Integer

def p2 = 2**31
assert p2 == 2147483648L
assert p2 instanceof Long

def p3 = 2**3.5
assert p3 instanceof Double

Groovyイン・アクション』に載っている例では、「2**31 が Integer」となってますが、これは間違い(Java でも)。 Integer は -231 〜 231-1 (-2**31 〜 2**31 - 1)

//***** BigXxxx *****
def g1 = 1G + 2G 
assert g1 == 3G
assert g1 instanceof BigInteger

def g2 = 1.0G + 2G
assert g2 == 3.0
assert g2 instanceof BigDecimal

数値に関するユーティリティ・メソッド


数値に定義されているユーティリティ・メソッド:

  • times()
  • upto()
  • downto()
  • step()
//***** times() *****
def store1 = ''
5.times {
    store1 += 'x'
}
assert store1 == 'xxxxx'
//***** upto() *****
def store2 = ''
1.upto(5){ number ->
    store2 += number
}
assert store2 == '12345'
//***** downto() *****
def store3 = ''
5.downto(1){ number ->
    store3 += number
}
assert store3 == '54321'
//***** step() *****
def store4 = ''
0.step(0.3, 0.1){ number->
    store4 += number + ' '
}
assert store4 == '0 0.1 0.2 '

*1:100l も可能だが、1と間違えやすいので非推奨。