这里对Groovy的基本语法进行介绍
数字类型 不同于Java使用基本类型、引用类型进行区分。对于Groovy而言,其一切均是对象。虽然Groovy语法中保留并使用int、short、boolean这些关键字。但并不代表相应的数据类型是基本类型,其使用的依然是Java中相应基本类型的包装类型。示例代码如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class NumberDemo { static void testType1() { byte b1 = 1 assert b1 instanceof Byte Byte b2 = 2 assert b2 instanceof Byte def b3 = 3 as byte assert b3 instanceof Byte def b4 = 4 as Byte assert b3 instanceof Byte short s1 = 1 assert s1 instanceof Short Short s2 = 2 assert s2 instanceof Short int i1 = 1 assert i1 instanceof Integer Integer i2 = 2 assert i2 instanceof Integer long l1 = 1 assert l1 instanceof Long Long l2 = 2 assert l2 instanceof Long float f1 = 1 assert f1 instanceof Float Float f2 = 2 assert f2 instanceof Float double d1 = 1 assert d1 instanceof Double Double d2 = 2 assert d2 instanceof Double boolean b6 = true assert b6 instanceof Boolean Boolean b7 = false assert b7 instanceof Boolean } }
类似地,可以通过在数字后面添加相应的后缀来表示数字的类型。具体地如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class NumberDemo { static void testType2() { def num1 = 15 assert num1 instanceof Integer def num2 = 15 l def num3 = 15 L assert num2 instanceof Long assert num3 instanceof Long def num4 = 2147483648 assert num4 instanceof Long def num5 = 15 g def num6 = 15 G assert num5 instanceof BigInteger assert num6 instanceof BigInteger def num7 = 7.7 def num8 = 8.8 g def num9 = 9.9 G assert num7 instanceof BigDecimal assert num8 instanceof BigDecimal assert num9 instanceof BigDecimal def num10 = 5.55 f def num11 = 6.66 F assert num10 instanceof Float assert num11 instanceof Float def num12 = 7.77 d def num13 = 8.88 D assert num12 instanceof Double assert num13 instanceof Double } }
前面提到既然数字是对象类型而不是基本类型的,那自然可以直接调用方法。这里就Groovy增强的方法进行实践,如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class NumberDemo { static void testMethod() { def msg1 = "" def num1 = 4 num1.times { msg1 += "A" } assert msg1 == "AAAA" def msg2 = "" num1.times { e -> msg2 += "B$e" } assert msg2 == "B0B1B2B3" def msg3 = "" 3. upto(5 ) { num -> msg3 += num } assert msg3 == "345" def msg4 = "" 5. downto(-2 ) { num -> msg4 += num } assert msg4 == "543210-1-2" def msg5 = "" 0.1 .step(1.1 , 0.2 ) { num -> msg5 += "H$num, " } assert msg5 == "H0.1, H0.3, H0.5, H0.7, H0.9, " } }
字符串 Groovy中支持多种形式的字符串定义方式
单引号 直接利用单引号定义字符串,则其实际上是Java String类的实例
1 2 3 4 5 6 7 8 9 10 11 12 class StringDemo { static void main(args) { def x = 1 def str1 = 'str 1: $x' assert str1 instanceof String println("-------------------" ) println(str1) } }
测试结果,如下所示
双引号 在Groovy中使用双引号定义字符串,则是有特殊含义的。即支持使用占位符${}进行插值,其中占位符的花括号{}在不引起歧义的前提下可以省略。具体地,字符串中如果不含占位符, 则其是Java String的实例;反正,则是Groovy GString的实例。示例代码如下所示,可以看到str2b中的x已经被替换为1了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class StringDemo { static void main(args) { def x = 1 def str2a = "str 2a: Hello" assert str2a instanceof String assert str2a == 'str 2a: Hello' def str2b = "str 2b: $x" assert str2b instanceof GString assert str2b == 'str 2b: 1' } }
三重单引号 Groovy还支持通过三重单引号定义存在多行的字符串。由于其只是一个普通的Java String实例,故不支持通过占位符进行插值。由于在定义多行字符串过程中,字符串的任何缩进均会被视为有效的空格字符。故str3a变量中的字符串都需要顶格写。如果执意进行缩进,那么最后应该通过stripIndent方法移除指定数量的缩进
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class StringDemo { static void main(args) { def x = 1 def str3a = '''str3a line 1 $x line 2 line 3''' assert str3a instanceof String println("-------------------" ) println(str3a) def str3b = '''\ str3b hello''' println("-------------------" ) println( str3b.stripIndent(12 ) ) } }
测试结果,如下所示
三重双引号 如果期望对多行字符串支持占位符进行插值,则可进一步通过三重双引号进行定义。类似地,字符串中如果不含占位符, 则其是Java String的实例;反正,则是Groovy GString的实例。示例代码如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class StringDemo { static void main(args) { def x = 1 def str4a = """str4a line 1 line 2 line 3""" assert str3a instanceof String println("-------------------" ) println(str4a) def str4b = """str4b line 1 $x line 3""" assert str4b instanceof GString println("-------------------" ) println(str4b) } }
测试结果,如下所示
斜杠 字符串中如果存在一些特殊字符时,需要使用大量的反斜杠进行转义。为此Groovy提供一种通过斜杠定义字符串的方法。类似地,字符串中如果不含占位符, 则其是Java String的实例;反正,则是Groovy GString的实例。示例代码如下所示。显然此种方式十分适合用来定义、表示正则表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class StringDemo { static void main(args) { def x = 1 def str5a = /Hello"12\World/ assert str5a instanceof String assert str5a == "Hello\"12\\World" def str5b = /a${x}c/ assert str5b instanceof GString assert str5b == 'a1c' } }
字符类型 这里对字符类型的字面量作一些补充说明,Groovy中没有专门用来表示单个字符的方式。故可以将只包含单个字符的字符串转换为字符。具体地转换方式如下述代码所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class StringDemo { static void main(args) { char c1 = "A" assert c1 instanceof Character Character c2 = "B" assert c2 instanceof Character def c3 = "C" as char assert c3 instanceof Character def c4 = "D" .toCharacter() assert c4 instanceof Character def c5 = (char )'E' assert c5 instanceof Character } }
表达式真值规则 对于Java而言,其要求表达式的结果必须是布尔类型才可以判断真/假。而在Groovy中表达式真值判定的限制被进一步放宽,其可以对任何一个表达式进行真值判定。下面就Groovy中的表达式的真值规则进行介绍
布尔值可以直接 作为 真值结果
1 2 3 4 assert true assert !false
布尔表达式计算的布尔值结果 作为 真值结果
1 2 3 assert 2 >1 assert !(2 <1 )
对于数组、集合而言,非空为真、空为假
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 def list1 = ["a" , 23 ]def list2 = []assert list1assert !list2assert ["Ok" :200 , "Error" : 404 ]def map1 = [:]assert !map1def array1 = [211 ,985 ] as int []def array2 = [] as int []assert array1assert !array2
对于字符串而言,非空为真、空为假
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 assert 'A' assert !'' def str1 = "ABC" def str2 = "" assert str1assert !str2def str3 = "$str1" def str4 = "$str2" assert str3assert !str4
对于数字而言,非零为真、零为假
1 2 3 4 5 6 7 8 9 assert 985 assert 3.14 fassert 3.14 gassert !0 assert !0 gassert !0.0 fassert !0.0 d
对于引用而言,非NULL为真、NULL为假
需要注意的是对于指向空集合的引用而言,即使非NULL,但根据集合的真值判定规则,空集合为假
1 2 3 4 5 6 7 8 9 10 11 12 def obj = new Object()assert objdef map2 = null assert !map2def map3 = new HashMap()assert !map3
对于正则匹配而言,匹配成功为真、匹配失败为假
1 2 3 4 assert "Aaron" =~ /Aar/ assert !("Aaron" =~ /Bob/ )
异常 对于异常机制而言,Groovy与Java一样不仅支持传统的try/catch/finally语句,同样还支持资源自动管理ARM机制,即TWR语法。不同之处在于,Groovy方法无论是抛出CheckedException受查异常,还是抛出RuntimeException运行时异常。方法签名处的异常抛出声明均是可选的。示例如下所示,可以看出总体上与Java保持了一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 class ExceptionDemo { static void main(String[] args) { def result1 = test1("Java 8 In Action" ) assert result1 =="JAVA 8 IN ACTION" try { test1("Groovy In Action" ) } catch (e) { assert e instanceof FileNotFoundException assert e.getMessage() == "文件不存在异常" } def result2 = -1 try { test2(null ) } catch (NullPointerException | ArithmeticException e) { assert e.getMessage() == "num不能为null" || "num不能为负数" } finally { result2 = 996 } assert result2 == 996 try ( FileReader file = new FileReader("src/main/resources/ReadMe.txt" ) ) { file.each {line -> println line} }catch (e) { println ("Happen Exception: ${e.getMessage()}" ) } } static def test1 (String fileName) { if ( fileName == "Groovy In Action" ) { throw new FileNotFoundException("文件不存在异常" ) } return fileName.toUpperCase() } static int test2 (def num) { if ( num == null ) { throw new NullPointerException("num不能为null" ) } else if ( num<0 ) { throw new ArithmeticException("num不能为负数" ) } return num } }
控制结构 if语句 Groovy在if语句上与Java并无二致,只不过在条件表达式上更加丰富。可以使用任何的表达式,并应用上文所述的真值规则判定表达式的结果。示例代码如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class StatementDemo { static void testIf() { def x if (true ) { x = 1 } else { x = 2 } assert x == 1 if (false ) { x = 1 } else { x = 2 } assert x == 2 if (null ) { x = 1 } else { x = 2 } assert x == 2 if ("Hello" ) { x = 1 } else { x = 2 } assert x == 1 def foo = 99 def bar if (foo==1 ) { bar = 1 } else if (foo==2 ) { bar = 2 } else { bar = 3 } assert bar == 3 } }
while语句 whiile语句方面,同样支持while、do-while两种形式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class StatementDemo { static void testWhile() { def bar = 0 while ( bar < 10 ) { bar++ } assert bar == 10 def count = 4 def fact = 1 do{ fact *= count count-- }while (count>1 ) assert fact == 24 } }
for语句 Groovy不仅支持传统for循环、Java经典的for each循环,还针对集合容器提供了for in循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 class StatementDemo { static testFor() { def msg = "" for (int i=1 ; i<=5 ; i++) { msg += i } assert msg == "12345" def str = "" for ( def (x, y) = ["Hello" , 42 ]; y<45 ; x++, y++) { str += "$x $y, " } assert str == "Hello 42, Hellp 43, Hellq 44, " def list = [1 ,3 ,5 ] def x = 0 for ( e in list ) { x += e } assert x == 9 def array = [2 , 6 , 4 ] as int [] def y = 0 for ( e in array ) { y += e } assert y == 12 def map = ["Aaron" :1 , "Bob" :3 , "Tina" :2 ] def names = "" def sum = 0 for ( e in map ) { names += e.key + "," sum += e.value } assert names == "Aaron,Bob,Tina," assert sum == 6 def sum1 = 0 for ( e in map.values()) { sum1 += e } assert sum1 == 6 def text = "Hello" def list2 = [] for ( c in text ) { list2.add( c ) } assert list2 == ["H" , "e" , "l" , "l" , "o" ] def range = 1. .3 def result2 = 0 for ( e in range ) { result2 += e } assert result2 == 6 def list3 = [1 ,3 ,5 ] def result = 0 for (def e : list3) { result += e } assert result == 9 } }
switch语句 Groovy支持传统的switch语句.需要注意的是,当匹配到某个case时如若未遇到break,则其会一直执行下去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class StatementDemo { static testSwitch1() { def result = "" def num = 3 switch (num) { case 0 : result += "A" case 1 : { result += "B" break } case 2 : result += "C" case 3 : result += "D" case 4 : { result += "E" break } case 5 : result += "F" default: result += "Z" } assert result == "DE" } }
特别地,Groovy中的Switch语句还支持使用分类器,用来判断某个值是否属于某个分类。示例如下所示。事实上进行分类判断时,本质上是通过调用分类器的isCase方法实现的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class StatementDemo { static testSwitch2() { Closure closure1 = { num -> def result = "Z" switch (num) { case -1 : result = "A" ; break case 1. .<2 : result = "B" ; break case 2. .4 : result = "C" ; break case {it%5 ==0 } : result = "D" ; break case [11 ,31 ] : result = "E" ; break case Integer: result = "F" ; break } return result } assert closure1(-1 ) == "A" assert closure1(1 ) == "B" assert closure1(2 ) == "C" assert closure1(5 ) == "D" assert closure1(10 ) == "D" assert closure1(31 ) == "E" assert closure1(996 ) == "F" } }
参考文献
Groovy In Action · 2nd Edition Dierk König、Guillaume Laforge著