5.4.数字类型后缀
通过使用大写或小写类型后缀(见下表),我们能强制将一个数字(包括二进制,八进制,十六进制)给一个指定类型。
Type Suffix BigInteger G 或 g Long L 或 l Integer I 或 i BigDecimal G 或 g Double D 或 d Float F 或 f
如:
assert 42I == new Integer('42')
assert 42i == new Integer('42') // lowercase i more readable
assert 123L == new Long("123") // uppercase L more readable
assert 2147483648 == new Long('2147483648') // Long type used, value too large for an Integer
assert 456G == new BigInteger('456')
assert 456g == new BigInteger('456')
assert 123.45 == new BigDecimal('123.45') // default BigDecimal type used
assert 1.200065D == new Double('1.200065')
assert 1.234F == new Float('1.234')
assert 1.23E23D == new Double('1.23E23')
assert 0b1111L.class == Long // binary
assert 0xFFi.class == Integer // hexadecimal
assert 034G.class == BigInteger // octal
5.5.数学运算
尽管运算在以后会被覆盖,讨论数学运算和结果类型仍然是重要的。
除法与幂方二元操作符放在一边(下文讨论)。
- byte char short和int进行二元操作的结果是int
- 使用long与byte char short int进行二元操作的结果是long
- 使用BigInteger与任意其他整数类型进行二元操作结果是BigInteger
- float double与BigDecimal进行二元运算的结果是double
- 两个BigDecimal进行二元运算的结果是BigDecimal
下表总结了这些原则:
byte char short int long BigInteger float double BigDecimal byte int int int int long BigInteger double double double char int int int long BigInteger double double double short int int long BigInteger double double double int int long BigInteger double double double long long BigInteger double double double BigInteger BigInteger double double double float double double double double double double BigDecimal BigDecimal
由于Groovy操作符重载,BigInteger与BigDecimal通常也能进行运算操作,与Java不同,在Java中你不得不显式使用方法操作这些数字。
5.5.1除法运算符的情况
如果任何一个操作数是float或double,那么除法运算符/(和/= 用于除法和赋值)产生double结果,否则(当两个操作数是一个与整型类型short, char, byte, int, long, BigInteger or BigDecimal的任意组合)是一个BigDecimal结果。
如果除法是精确的(如,结果可以在相同的精度和标度范围内精确表示),那么BigDecimal的除法实际执行的是divide()方法,或使用两个操作数的最大精度加10,和一个最大值为10的标度的MathContext。
对于整数除法和Java相同,你应该使用intdiv()方法,因为Groovy没有专门提供一个整数操作符。
5.5.2.幂运算情况
幂运算操作符使用**操作符,有两个参数:基数和指数。幂运算的结果取决于它的操作数以及操作的结果(特别是结果可以被表示为一个整数值)。
以下这些原则被用于决定Groovy幂运算操作结果的类型:
(1)如果指数是一个小数 1.如果结果能作为一个Integer表示,那么返回一个Integer 2..如果结果能作为一个Long表示,那么返回一个Long 3.否则返回一个Double (2)如果指数是一个整数 1.如果是一个严格的负数,那么返回一个Integer,Long或Double,结果值使用那种类型填充。 2.如果指数是正数或0 1)如果基数是BigDecimal,那么返回一个BigDecimal结果值 2)如果基数是BigInteger,那么返回一个BigInteger结果值 3)如果基数是Integer,那么返回一个Integer值,否则返回BigInteger 4)如果基数是Long,那么返回一个Long值,否则返回BigInteger
我们使用一些实例说明这些原则:
// base and exponent are ints and the result can be represented by an Integer assert 2 ** 3 instanceof Integer // 8 assert 10 ** 9 instanceof Integer // 1_000_000_000
// the base is a long, so fit the result in a Long // (although it could have fit in an Integer) assert 5L ** 2 instanceof Long // 25
// the result can't be represented as an Integer or Long, so return a BigInteger assert 100 ** 10 instanceof BigInteger // 10e20 assert 1234 ** 123 instanceof BigInteger // 170515806212727042875...
// the base is a BigDecimal and the exponent a negative int // but the result can be represented as an Integer assert 0.5 ** -2 instanceof Integer // 4
// the base is an int, and the exponent a negative float // but again, the result can be represented as an Integer assert 1 ** -0.3f instanceof Integer // 1
// the base is an int, and the exponent a negative int // but the result will be calculated as a Double // (both base and exponent are actually converted to doubles) assert 10 ** -1 instanceof Double // 0.1
// the base is a BigDecimal, and the exponent is an int, so return a BigDecimal assert 1.2 ** 10 instanceof BigDecimal // 6.1917364224
// the base is a float or double, and the exponent is an int // but the result can only be represented as a Double value assert 3.4f ** 5 instanceof Double // 454.35430372146965 assert 5.6d ** 2 instanceof Double // 31.359999999999996
// the exponent is a decimal value // and the result can only be represented as a Double value assert 7.8 ** 1.9 instanceof Double // 49.542708423868476 assert 2 ** 0.1f instanceof Double // 1.0717734636432956
6.布尔
Boolean是一种特殊的数据类型,用于表示真值:true和false。使用这种数据类型作为跟踪真假条件的简单标志。
Boolean能被存储在变量中,成员变量中,就像其他数据类型一样:
def myBooleanVariable = true
boolean untypedBooleanVar = false
booleanField = true
true和false是仅有的两个原始布尔值。但更复杂的布尔表达式能使用逻辑操作符表示。
除此之外,Groovy有一些特殊的规则(经常因为Groovy真值涉及)用于将非布尔值对象转化为一个布尔值。
7.列表
Groovy使用逗号分隔列表中的值,并使用方括号包围,用来指定一个列表。Groovy的列表是java.util.List,因为Groovy没有定义任何集合类。当定义一个列表常量时,默认的列表具体实现是java.util.ArrayList,除非你指定,我们将在后面看到。
def numbers = [1, 2, 3] (1)
assert numbers instanceof List (2) assert numbers.size() == 3 (3)
(1)我们定义用逗号分隔,并用方括号包围列表数字,并将列表赋值给一个变量
(2)list是java java.util.List接口的实例
(3)列表的大小可以使用size()方法查询,表明列表有三个元素
在上面的示例中,我们使用了一个元素类型相同的列表,我们也能创建包含不同类型元素的列表:
def heterogeneous = [1, "a", true] (1)
(1)我们的列表包含一个数字,一个字符串,一个布尔值
我们提及到,默认的列表字面量实际是java.util.ArrayList的实例,但列表使用不同返回类型也是可以的,使用as操作符进行类型转换,或使用变量的定义类型:
def arrayList = [1, 2, 3] assert arrayList instanceof java.util.ArrayList
def linkedList = [2, 3, 4] as LinkedList (1) assert linkedList instanceof java.util.LinkedList
LinkedList otherLinked = [3, 4, 5] (2) assert otherLinked instanceof java.util.LinkedList
(1)我们使用as操作符进行类型转换,显式请求一个java.util.LinkedList实现
(2)我们使用类型为java.util.LinkedList的变量保存列表字面量
你能通过下标操作符[](读和写元素值)并使用正索引值访问列表元素或负索引值从列表尾部访问元素,也可以使用范围,或使用左移<<追加列表元素:
def letters = ['a', 'b', 'c', 'd']
assert letters[0] == 'a' (1) assert letters[1] == 'b'
assert letters[-1] == 'd' (2) assert letters[-2] == 'c'
letters[2] = 'C' (3) assert letters[2] == 'C'
letters << 'e' (4) assert letters[ 4] == 'e' assert letters[-1] == 'e'
assert letters[1, 3] == ['b', 'd'] (5) assert letters[2..4] == ['C', 'd', 'e'] (6)
(1)访问列表的第一个元素(索引从零开始计算)
(2)使用负索引访问列表的最后一个元素:-1是列表从尾部开始的第一个元素
(3)使用赋值操作为列表的第三个元素设置一个新值
(4)使用<<左移操作符在列表尾部追加一个元素
(5)一次访问两个元素,并返回一个包含这两个元素的新列表
(6)使用范围访问列表中这个范围内的元素,从start到end元素位置
因为列表可以很自然的做到元素类型不同,因此列表也可以包含列表用于创建多维列表:
def multi = [[0, 1], [2, 3]] (1)
assert multi[1][0] == 2 (2)
(1)定义一个数字列表的列表
(2)访问顶级列表的第二个元素,内部列表的第一个元素
8.数组
Groovy使用列表标记来标记数组,但为了创建字面量数组,你需要通过类型转换或类型定义来定义数组类型。
String[] arrStr = ['Ananas', 'Banana', 'Kiwi'] (1)
assert arrStr instanceof String[] (2) assert !(arrStr instanceof List)
def numArr = [1, 2, 3] as int[] (3)
assert numArr instanceof int[] (4) assert numArr.size() == 3
(1)使用显式变量类型定义一个字符串数组
(2)断言说明我们创建了一个字符串数组
(3)使用as操作符创建以int数组
(4)断言表明我们创建了一个原始类型的int数组
你也能创建多维数组:
def matrix3 = new Integer[3][3] (1) assert matrix3.size() == 3
Integer[][] matrix2 (2) matrix2 = [[1, 2], [3, 4]] assert matrix2 instanceof Integer[][]
(1)你能定义一个新数组的边界
(2)或不指定它的边界定义一个新数组
通过与列表相同的标记访问数组的元素:
String[] names = ['Cédric', 'Guillaume', 'Jochen', 'Paul'] assert names[0] == 'Cédric' (1)
names[2] = 'Blackdrag' (2) assert names[2] == 'Blackdrag'
(1)取得数组的第一个元素
(2)为数组的第三个元素设置一个新值
Java数组初始化标记Groovy不支持,因为大括号会被误解为Groovy的闭包标记。
9.映射
在其它语言中,有时候称为字典或关联数组,Groovy称为映射。映射使键到值关联,使用冒号将键值分隔开,每个键值对使用逗号,整个键和值使用方括号包围。
def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF'] (1)
assert colors['red'] == '#FF0000' (2) assert colors.green == '#00FF00' (3)
colors['pink'] = '#FF00FF' (4) colors.yellow = '#FFFF00' (5)
assert colors.pink == '#FF00FF' assert colors['yellow'] == '#FFFF00'
assert colors instanceof java.util.LinkedHashMap
(1)我们定义了一个字符串颜色名关联十六进制的html颜色的映射
(2)我们使用下标标记检查red键值关联的内容
(3)我们也能使用属性标记访问绿颜色十六进制表达式
(4)相似的,我们也能使用下标标记添加一个新的键值对
(5)或者使用属性标记添加yellow颜色
当使用这些键的名字时,我们实际上在映射中定义了一个键值。
Groovy创建的映射实际是java.util.LinkedHashMap的实例。
如果你尝试在映射中访问不存在的键:
assert colors.unknown == null
你将取回null。
在上面的示例中我们使用字符串键值,你也可以使用其他类型作为键值:
def numbers = [1: 'one', 2: 'two']
assert numbers[1] == 'one'
这里我们使用数字作为键值,作为数字能清楚的识别数字,因此Groovy不会像之前的示例一样创建一个字符串的键。但是考虑你想传递一个变量代替键的情况下,有一个变量值将会作为键:
def key = 'name' def person = [key: 'Guillaume'] (1)
assert !person.containsKey('name') (2) assert person.containsKey('key') (3)
(1)key同’Guillaume’关联,名字将会变为”key”字符串,而不是其值
(2)这个映射不包括”name”键
(3)代替的是,映射包括一个”key”键
你也能通过引用的字符串以及键: [“name”: “Guillaume”]。如果你的见字符串不是一个合法的标识符,这是强制的,例如,如果你想创建一个字符串键像哈希:
["street-name": "Main street"]。
在映射定义中需要传递变量值,你必须使用圆括号包围这个变量或表达式:
person = [(key): 'Guillaume'] (1)
assert person.containsKey('name') (2) assert !person.containsKey('key') (3)
(1)这次,我们使用圆括号包围key变量,指示解析器我们传递一个变量,而不是定义一个字符串键
(2)映射包含name键
(3)但映射不像之前包含key键