Groovy 语言基础

前面一节我们为大家介绍了什么是 Gradle?Gradle 是一个构建工具,它的构建脚本是基于 Groovy 或是 Kotlin 语言编写的。

今天我们就来看下 Groovy 的基础语法。Groovy 结合了 Java、Python、Ruby 等当下几大流行语言的优点。它可以说是从 Java 中衍生出来的,为什么这么说呢?因为它的语法和 Java 非常的相似,它的文件也是可以编译为 .class 文件,而且可以使用 Java 的类库。

1. Groovy 基础语法

1.1 基础语法

1. 定义变量 def
在 Groovy 中,我们除了指定类型定义变量外,还可以使用def关键字来定义变量,变量是由数字、字母、下划线组成。但是它不能以数字开头。我们看下下面一段代码:

//定义一个整型变量
def i = 5;
println(i.class)
//定义一个字符串
def _name = "Groovy语言基础"
println(_name.class)
//无效变量(变量不能以数字开头)
//def 5imooc = 0;

以上输出结果为:

class java.lang.Integer
class java.lang.String

通过上面的代码可以发现,其实它和 Java 是差不多的,不过 Java 中我们定义变量必须指明它的类型。而 Groovy 中我们可以使用def,系统会自动帮我们转换。

2. 引入包 import
这点跟我们在 Java 中的是一样的,用的是import。下面我们看个简单例子[引入MarkupBuilder类,创建 xml]:

import groovy.xml.MarkupBuilder 
def newXml = new MarkupBuilder() 

这里我们引入了 MarkupBuilder 类。

我们再来看一个例子:

def _name = "Groovy语言基础"
println(_name.class)

细心的同学会发现,我们这里定义 String 时,并没有引入 String 对应的包。但是我们写 Java 时需要引入 java.lang.String。这就是我们下面说的一个小知识点。

Tips:在开发 Groovy 时,以下一些库,我们不需要显式的去引入它们,系统已经包含了这些库。

import java.lang.*
import java.util.*
import java.io.*
import java.net.*

import groovy.lang.*
import groovy.util.*

import java.math.BigInteger
import java.math.BigDecimal

3. 注释和分号
在 Groovy 语言中它的注释及分号和 Java 语言完全一样。以分号为语句间的分隔。可以有多行注释和单行注释。

//这是单行注释
/** 这是
 *  多行
 *  注释**/
 def i = 0;  
 println('Hello Mooc');  

4. 关键字
在 Java 和 C 语言中我们都知道,定义变量的时候不能是关键字,那么我们来看下 Groovy 有哪些关键字呢?

as assert break case enum extends
catch class const continue false Finally
def default do else for goto
import in instanceof interface if implements
new pull package return throws trait
super switch this throw true try
while

2. 字符串 String 与 GString

2.1 字符串 String

在 Groovy 中,字符串较 Java 中比较特殊,在 Java 中我们用单引号(’’)来表示 char,用双引号("")表示字符串。但是在 Groovy 中字符串不仅可以用双引号 (""),而且单引号 (’’),三引号 ("’’")也可以。我们看下下面这个例子:

class Example { 
   static void main(String[] args) { 
      String a = '单引号'; 
      String b = "双引号"; 
      String c = '''这是三引号 
    Gradle专题
    Groovy语言基础''';
      println(a); 
      println(b); 
      println(c); 
   } 
}

最终输出结果为:

单引号
双引号
这是三引号 
    Gradle专题
    Groovy语言基础

我们发现三引号(’’’ ‘’’)其实还可以换行,多行字符串也可以用三引号(’’’ ‘’’)来引用。不像 Java 一样我们如果字符串换行还需要用“ + 和 \n”连接起来。

2.2 插值字符串 GString

在 Groovy 中有 2 种字符串,一种是我们上面写的 String[java.lang.String]这类字符串跟 Java 一样不能插值,还有一种是 Groovy 的插值字符串 GString,这类字符串可以实现插值。

所谓插值,就是用 ${变量名}读取该变量的值,而拼接起来的字符串。

如下:

class Example { 
   static void main(String[] args) { 
      def a = 'Gradle专题'; 
      def b = "${a} Groovy语言基础"; //插值字符串 GStringImpl
      println(a.class); 
      println(b.class); 
      println(b); 
   } 
}

它的运行结果为:

class java.lang.String
class org.codehaus.groovy.runtime.GStringImpl
Gradle专题 Groovy语言基础

从运行结果可以看出,字符串 a 是一个 Java 字符串,字符串 b 它是一个插值字符串 GStringImpl,它继承自 GString。上面代码中${a}就是读取到 a 的值为 Gradle 专题。

3. 方法

Groovy 的方法定义跟 Java 比较类似,它的返回类型可以用返回值的类型或是def定义,也可以使用 publicstatic,private等修饰。如下我们定义一个add(int a)方法:

class Example { 
   static void main(String[] args) { 
     def i = 3;
     println("befor add(i): "+ i);
     i=add(i);
     println("after add(i): "+i);
   } 
   static def add(int a) {
     ++a;
     return a;
   };
}

执行结果如下:

befor add(): 3
after add(): 4

这点跟 Java 是非常相似的。但是大家注意一点:那就是方法不要定义在 main 方法里面,之前遇到有同学问我这么一个错误:

Method definition not expected here. Please define the method at an appropriate place or perhaps try using a block/Closure instead. at line: 7 column: 4. File: ConsoleScript42 at line: 7, column: 4

这个错的原因就是,他把自己的方法定义在 main 方法里面了。这里特别提一下让大家谨记。

4. 逻辑控制

我们知道逻辑控制一般有 3 种:

  • 顺序执行: 就是按顺序一步步执行。
  • 条件判断: 这个就是我们 Java 中的if/elseswitch/case
  • 循环语句: 跟 Java 中一样还是whilefor.

Tips: 虽然 Groovy 的逻辑控制和 Java 中是一样的,但是 Groovy 又扩展了一些新功能。其中条件语句的if/else和循环语句的while与 Java 中是一样的,但是条件语句的switch/case和循环语句中的for, Groovy 在 Java 的基础上做了扩展。

4.1 switch/case 语句

下面我们先看下switch/case:

class Example { 
   static void main(String[] args) { 
    def x = 0.98
    //def x = 3
    def result
    switch (x){
    case [4,5,6,'Gradle']:   //列表
        result = 'list'
        break
    case 3..11:
        result = 'range'     //范围
        break
    case Integer:
        result = 'Integer'   //类型
        break
    case BigDecimal:
        result = 'BigDecimal'//类型
        break
    default:
        result = 'default'
        break
    }
    println(result)
   };
}

执行结果如下:

//x = 0.98时输出结果为
BigDecimal
//x = 3时输出结果为
range

通过上面的代码我们其实可以看出,相较于 Java 的switch/case,Groovy 它的判断类型可以是任何类型。

4.2 for 循环

Groovy 除了支持 Java 的for(int i = 0;i < length;i++)for(int i :array)形式的循环语句,还支持以下形式的循环语句:

class Example { 
   static void main(String[] args) { 
//1 对范围的for循环
def sum = 0
for (i in 0..100){
    sum += i
}
println("0到100的和为:"+sum)
//2 对List的循环
def sumList = 0;
for (i in [1,2,3,4,5,6,7,8,9,10]){
    sumList += i
}
println("0到10的和为:"+sumList)
//3 对Map的循环
def sumMap = 0
for (i in ['张三':21,'李四':25,'王五':36]){
    sumMap += i.value
    println i.key
}
println("他们的年龄和为:"+sumMap)
   };
}

它的运行结果为:

0100的和为:5050
010的和为:55
张三
李四
王五
他们的年龄和为:82

for 循环是我们每一门编程语言中都有的循环语句的关键字,我们从上面的代码示例和输出中,可以看到 for 循环其实非常简单。它比我么在 Java 或是 C/C++ 中的 for 语句好使用太多了,尤其是对 MAP 和 List 的遍历。

5. 闭包(Closure)

在 Groovy 中闭包是非常灵活且强大的。

首先我们了解下什么是闭包

闭包就是一段用 {} 包起来的代码块,使用方法和方法类型,可以命名,可以传参,可以被调用。下面我们来定义一个简单闭包,并且调用它。

class Example { 
   static void main(String[] args) { 
//1 定义一个闭包
def closer = {
    println "Gradle专题之Groovy语法"
}

//2 闭包的两种调用方式
closer.call()
closer()
   };
}


它的运行结果为:

Gradle 专题之 Groovy 语法
Gradle 专题之 Groovy 语法

我们看到上面有 2 种闭包的调用方式,但是平时编写代码的时候,我们建议大家使用第一种方式去调用,以免和方法的调用混淆。

上面定义的是无参的闭包,下面我们定义一个传参的闭包:

class Example { 
   static void main(String[] args) { 
//1 定义一个传参的闭包
def closer = {
   String name -> println "${name}专题之Groovy语法"
}

closer.call('Gradle')
   };
}

它的运行结果为:

Gradle专题之Groovy语法

闭包的传参的定义其实我们上面看到换算比较简单,我们调用的时候将值出入,最终就会在闭包的代码中使用到传入的值。

6. I/O操作

前面我们学习了闭包,下面我们来看下 Groovy 的 I/O 操作。总的来说 Groovy 的 I/O 操作比 Java 简单多了。

6.1 Groovy的文件读取

我们在 D 盘下创建一个 groovy.txt 的文档,在里面输入:Gradle 专题之 Groovy 语言。以读取这个文件的内容为例我们来看下 Groovy 的代码:

class Example { 
   static void main(String[] args) { 
        def filePath = "D:/groovy.txt"
        def file = new File(filePath) ;
        file.eachLine {
            println it
        }
   };
}

----------或是我们也可以像下面这么简洁---------
class Example { 
   static void main(String[] args) { 
        def filePath = "D:/groovy.txt"
        def file = new File(filePath) ;
        println file.text
    };
}

通过上面的代码示例我们可以看到 Groovy 中文件的读取非常简单快捷,比我们在 Java 和 C 语言中方便太多了。只需要文件的路径地址,通过 new File(filePath) 就可以实现读取文件。

6.2 Groovy 的文件写入

文件写入跟读取一样简洁,如下:

class Example { 
   static void main(String[] args) { 
        def filePath = "D:/groovy.txt"
        def file = new File(filePath) ;
        file.withPrintWriter {
            it.println("Gradle专题")
            it.println("Groovy语言")
            it.println("文件写入")
        }
   };
}

这里我们看到文件的写入跟读取一样非常的方便快捷,其实 Groovy 在 java.io.File 的基础上做了一些扩展.

7. 数据结构

Groovy 的数据结构我们常用的主要有:列表,范围,映射。这个跟我们 Java 的数据结构比较类似,下面做简单介绍。

7.1 列表(List)

列表的定义跟 Java 差不多,但是较 Java 中比较简单。我们从代码中来比较:

class Example { 
   static void main(String[] args) { 
// Java的定义方式
    def list = new ArrayList() //定义一个空的列表
//groovy中定义
    def list2 = []          //定义一个空的列表
    def list3 = [1,2,3,4]   //定义一个非空的列表

    println list2.class
    println list3.class
   };
}
--------------输出----------------
class java.util.ArrayList
class java.util.ArrayList

----------------------------------

我们从上面看到,这样定义完是跟 Java 一样的都是ArrayList
下面我们再看下在 Groovy 中定义数组:

//在groovy中使用as关键字定义数组
def array = [1,2,3,4] as int[]
//或者使用强类型的定义方式
int[] array2 = [1,2,3]

Tips: 在 Groovy 中定义数组的方式有两周,一种是跟 Java 一样直接指定 int,一种是用as关键字,但是我们使用时要注意和 List 的区别。

7.2 范围(Range)

范围的使用非常简单,我们直接看下面的代码及注释:

class Example { 
   static void main(String[] args) { 
   //范围的定义
    def range = 1..15

    //范围的使用
     //第一个元素的值
    println ("第一个元素的值:"+range[0])
    //是否包含8
    println ("是否包含8 "+range.contains(8))
    //范围的起始值   
    println ("范围的起始值:"+range.from)
    //范围的结束值
    println ("范围的结束值:"+range.to )
      };
}

--------------输出----------------
第一个元素的值:1
是否包含8 true
范围的起始值:1
范围的结束值:15

----------------------------------

7.3 映射(MAP)

在 Groovy 中定义映射 (MAP) 和 List 类似使用[]并且要指明它的键 (key)和值 (value),默认的实现类为java.util.LinkedHashMap.

class Example { 
   static void main(String[] args) { 
   //1 映射的定义
    def swordsman = [one:'张三丰',two:'金毛狮王谢逊',three:'张无忌']

    //2 映射的使用
    println swordsman['one']
    println swordsman.get('two')
    println swordsman.three

    //3 添加元素
    swordsman.four = '成坤'
    println swordsman

    //4 groovy中,可以添加一个复杂的元素,比如添加一个map
    swordsman.five = [a:1,b:2]
    println swordsman
   };
}

------------------输出----------------------
张三丰
金毛狮王谢逊
张无忌
[one:张三丰, two:金毛狮王谢逊, three:张无忌, four:成坤]
[one:张三丰, two:金毛狮王谢逊, three:张无忌, four:成坤, five:[a:1, b:2]]
--------------------------------------------

我们从上面的代码中看到,Groovy 定义 MAP 时必须要指定它的键和值,包括新增元素时也要明确键和值,但是它的值可以是任意类型,可以是数字、字符串、列表,也可以是 MAP。

8. 小结

这篇文章我们主要学习了 Groovy 语言的语法基础,从基础的语法到字符串,方法,闭包再到数据结构。我们总结一下和一些注意点:

  • Groovy 的语法和 Java 非常相似;
  • Groovy 中定义变量可以使用def系统会自动帮我们转换为具体类型;
  • 定义基本数据类型时不需要导包,Groovy 系统包含那些包;
  • Groovy 的字符串可以用,单引号,双引号,三引号。换可以支持字符串的插值;
  • Groovy 的方法跟 Java 一样不能定义在方法内部;
  • Groovy 的switch/case支持任意类型的判断;
  • Groovy 的for支持列表,范围和映射的遍历;
  • Groovy 的闭包灵活且强大建议使用第一种方式调用;
  • Groovy 的数组使用as关键字定义;
  • Groovy 的映射必须指明键和值。