"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
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。