注册

"Gradle"系列: 一、Gradle相关概念理解,Groovy基础(2)

三、Groovy 基础语法


再次强调 Groovy 是基于 java 扩展的动态语言,直接写 java 代码是没问题的,既然如此,Groovy 的优势在哪里呢?


在于 Groovy 提供了更加灵活简单的语法,大量的语法糖以及闭包特性可以让你用更少的代码来实现和Java同样的功能。比如解析xml文件,Groovy 就非常方便,只需要几行代码就能搞定,而如果用 Java 则需要几十行代码。


1、支持动态类型,使用 def 关键字来定义一个变量


在 Groovy 中可以使用 def 关键字定义一个变量,当然 Java 里面定义数据类型的方式,在 Groovy 中都能用

//Java 中,我们一般会这么定义
int age = 16
String name = "erdai"

//Groovy 中,我们可以这样定义,在变量赋值后,Groovy 编译器会推断出变量的实际类型
def age = 16
def name = 'erdai'

2、不用写 ; 号


现在比较新的语言都不用写,如 Kotlin

def age = 16
def name = 'erdai'

3、没有基本数据类型了,全是引用类型


上面说到,定义一个变量使用 def 关键字,但是 Groovy 是基于 Java 扩展的,因此我们也可以使用 Java 里面的类型,如 Java 中8大基本类型:byte , short , int , long , float , double ,char,boolean

//定义8大基本类型
byte mByte = 1
short mShort = 2
int mInt = 3
long mLong = 4
float mFloat = 5
double mDouble = 6
char mChar = 'a'
boolean mBoolean = true
//对类型进行打印
println(mByte.class)
println(mShort.class)
println(mInt.class)
println(mLong.class)
println(mFloat.class)
println(mDouble.class)
println(mChar.class)
println(mBoolean.class)

//打印结果如下:
class java.lang.Byte
class java.lang.Short
class java.lang.Integer
class java.lang.Long
class java.lang.Float
class java.lang.Double
class java.lang.Character
class java.lang.Boolean

因此我们可以得出结论:Groovy中没有基本数据类型,全是引用类型,即使定义了基础类型,也会被转换成对应的包装类


4、方法变化


1、使用 def 关键字定义一个方法,方法不需要指定返回值类型,参数类型,方法体内的最后一行会自动作为返回值,而不需要return关键字


2、方法调用可以不写 () ,最好还是加上 () 的好,不然可读性不好


3、定义方法时,如果参数没有返回值类型,我们可以省略 def,使用 void 即可


4、实际上不管有没有返回值,Groovy 中返回的都是 Object 类型


5、类的构造方法,避免添加 def 关键字

def sum(a,b){
a + b
}
def sum = sum(1,2) //还可以写成这样,但是可读性不好 def sum = sum 1,2
println(sum)

//打印结果
3

//如果方法没有返回值,我们可以这样写:
void doSomething(param1, param2) {

}

//类的构造方法,避免添加 def 关键字
class MyClass {
MyClass() {

}
}

5、字符串变化


在 Groovy 中有三种常用的字符串定义方式,如下所示:


这里先解释一下可扩展字符串的含义,可扩展字符串就是字符串里面可以引用变量,表达式等等


1 、单引号 '' 定义的字符串为不可扩展字符串


2 、双引号 "" 定义的字符串为可扩展字符串,可扩展字符串里面可以使用 ${} 引用变量值,当 {} 里面只有一个变量,非表达式时,{}也可以去掉


3 、三引号 ''' ''' 定义的字符串为输出带格式的不可扩展字符串

def age = 16
def name = 'erdai'
//定义一个不可扩展字符串,和我门在Java中使用差不多
def str1 = 'hello ' + name
//定义可扩展字符串,字符串里面可以引用变量值,当 {} 里面只有一个变量时,{}也可以去掉
def str2 = "hello $name ${name + age}"
//定义带输出格式的不可扩展字符串 使用 \ 字符来分行
def str3 = '''
\
hello
name
'''
//打印类型和值 下面代码我省略了 println 方法的(),上面有讲到这种语法也是允许的
println 'str1类型: ' + str1.class
println 'str1输出值: ' + str1
println 'str2类型: ' + str2.class
println 'str2输出值: ' + str2
println 'str3类型: ' + str3.class
println 'str3输出值: ' + str3

//打印结果
str1类型: class java.lang.String
str1输出值: hello erdai
str2类型: class org.codehaus.groovy.runtime.GStringImpl
str2输出值: hello erdai erdai16
str3类型: class java.lang.String
str3输出值:
hello
name

从上面代码我们可以看到,str2 是 GStringImpl 类型的,而 str1 和 str3 是 String 类型的,那么这里我就会有个疑问,这两种类型在相互赋值的情况下是否需要强转呢?我们做个实验在测试下:

//定义一个 String 类型的变量接收 GStringImpl 类型的变量,并没有强转
String str4 = str2
println 'str4类型: ' + str4.class
println 'str4输出值: ' + str4

//打印类型和值
str4类型: class java.lang.String
str4输出值: hello erdai erdai16

因此我们可以得出结论:编码的过程中,不需要特别关注 String 和 GString 的区别,编译器会帮助我们自动转换类型


6. 不用写 get 和 set 方法


1、在我们创建属性的时候,Groovy会帮我们自动创建 get 和 set 方法


2、当我们只定义了一个属性的 get 方法,而没有定义这个属性,默认这个属性只读


3、我们在使⽤对象 object.field 来获取值或者使用 object.field = value 来赋值的时候,实际上会自动转而调⽤ object.getField() 和 object.setField(value) 方法,如果我们不想调用这个特殊的 get 方法时则可以使用 .@ 直接域访问操作符访问属性本身


我们来模拟1,2,3这三种情况

//情况1:在我们创建属性的时候,Groovy会帮我们自动创建 get 和 set 方法
class People{
def name
def age
}

def people = new People()
people.name = 'erdai'
people.age = 19
println "姓名: $people.name 年龄: $people.age"
//打印结果
姓名: erdai 年龄: 19

//情况2 当我们定义了一个属性的 get 方法,而没有定义这个属性,默认这个属性只读
//我们修改一下People类
class People{
def name
def getAge(){
12
}
}

def people = new People()
people.name = 'erdai'
people.age = 19
println "姓名: $people.name 年龄: $people.age"
//运行一下代码 打印结果报错了,如下:
Caught: groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: age for class: variable.People
//大概错误意思就是我们不能修改一个只读的属性

//情况3: 如果我们不想调用这个特殊的 get 方法时则可以使用 .@ 直接域访问操作符访问属性本身
class People{
def name
def age

def getName(){
"My name is $name"
}
}
//这里使用了命名的参数初始化和默认的构造器创建people对象,后面会讲到
def people = new People(name: 'erdai666')
people.age = 19
def myName = people.@name

//打印值
println myName
println "姓名: $people.name 年龄: $people.age"

//打印结果
erdai666
姓名: My name is erdai666 年龄: 19
//看到区别了吗?使用 people.name 则会去调用这个属性的get方法,而 people.@name 则会访问这个属性本身

7、Class 是一等公民,所有的 Class 类型可以省略 .Class

//定义一个Test类
class Test{

}

//定义一个测试class的方法,从前面的语法我们知道,方法的参数类型是可以省略的
def testClass(myClass){

}

//测试
testClass(Test.class)
testClass(Test)

8、== 和 equals


在 Groovy 中,== 就相当于 Java 的 equals,如果需要比较两个对象是否是同一个,需要使用 .is()

class People{
def name
def age
}

def people1 = new People(name: 'erdai666')
def people2 = new People(name: 'erdai666')

println("people1.name == people2.name is: " + (people1.name == people2.name))
println("people1 is people2 is: " + people1.is(people2))

//打印结果
people1.name == people2.name is: true
people1 is people2 is: false

9、使用 assert 来设置断言,当断言的条件为 false 时,程序将会抛出异常

assert  2 ** 4 == 15
//运行程序,报错了,结果如下:
Caught: Assertion failed:
assert 2 ** 4 == 15
| |
16 false

10、支持 ** 次方运算符

assert  2 ** 4 == 16

11、简洁的三元表达式

//在java中,我们会这么写
String str = obj != null ? obj : ""

//在Groovy中,我们可以这样写,?: 操作符表示如果左边结果不为空则取左边的值,否则取右边的值
String str = obj ?: ""

12、简洁的非空判断

//在java中,我们可能会这么写
if(obj != null){
if(obj.group != null){
if(obj.group.artifact != null){
//do something
}
}
}

//在Groovy中,我们可以这样写 ?. 操作符表示如果当前调用对象为空就不执行了
obj?.group?.artifact


13、强大的 Switch


在 Groovy 中,switch 方法变得更加灵活,强大,可以同时支持更多的参数类型,比在 Java 中增强了很多

def result = 'erdai666'
switch (result){
case [1,2,'erdai666']:
println "匹配到了result"
break
default:
println 'default'
break
}
//打印结果
匹配到了result

14、判断是否为 null 和 非运算符


在 Groovy 中,所有类型都能转成布尔值,比如 null 就相当于0或者相当于false,其他则相当于true

//在 Java 中,我们会这么用
if (name != null && name.length > 0) {

}

//在 Groovy 中,可以这么用,如果name为 null 或 0 则返回 false,否则返回true
if(name){

}

//非运算符 erdai 这个字符串为非 null ,因此为true,而 !erdai 则为false
assert (!'erdai') = false

15、可以使用 Number 类去替代 float、double 等类型,省去考虑精度的麻烦


16、默认是 public 权限


默认情况下,Groovy 的 class 和 方法都是 public 权限,所以我们可以省略 public 关键字,除非我们想使用 private 修饰符

class Server { 
String toString() { "a server" }
}

17、使用命名的参数初始化和默认的构造器


Groovy中,我们在创建一个对象实例的时候,可以直接在构造方法中通过 key value 的形式给属性赋值,而不需要去写构造方法,说的有点抽象,上代码感受一下:

//定义一个people
class People{
def name
def age
}

//我们可以通过以下几种方式去实例化一个对象,注意我们People类里面没有写任何一个构造方法哦
def people1 = new People()
def people1 = new People(age: 15)
def people2 = new People(name: 'erdai')
def people3 = new People(age: 15,name: 'erdai')

18、使用 with 函数操作同一个对象的多个属性和方法


with 函数接收一个闭包,闭包下面会讲,闭包的参数就是当前调用的对象

class People{
def name
def age

void running(){
println '跑步'
}
}
//定义一个 people 对象
def people = new People()
//调用 with 函数 闭包参数即为peopeo 如果闭包不写参数,默认会有一个 it 参数
people.with{
name = "erdai"
age = 19
println "$name $age"
running()
}
//打印结果
erdai 19
跑步

19、异常捕获


如果你实在不想关心 try 块里抛出何种异常,你可以简单的捕获所有异常,并且可以省略异常类型:

//在 java 中我们会这样写
try {
// ...
} catch (Exception e) {
// do something
}

//在 Groovy 中,我们可以这样写
try {
// ...
} catch (any) {
// do something
}


上面 Groovy 的写法其实就是省略了参数类型,实际上 any 的参数类型也是 Exception, 并不包括 Throwable ,如果你想捕获所有的异常,你可以明确捕获异常的参数类型



作者:妖孽那里逃
链接:https://www.jianshu.com/p/124effa509bb
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1 个评论

系列文章很好,都是精髓

要回复文章请先登录注册