一,java和groovy的区别点
//进行系统级进程交互
println "git help".execute().text
//当在string实例上调用execute()方法时,groovy创建了一个扩展了java.lang.Process的类的实例,就像java代码中runtime类的exec()方法所做的那样
println "groovy -v".execute().getClass().name
//调用查看groovy版本号
println("groovy -v".execute().text)
groovy的for循环有多种写法
//groovy的for循环写法
for (i in 0..3){
println("好困鸭")
}
//for循环的写法2
0.upto(3){
println("$it")
}
//for循环的写法3
3.times {
println("$it")
}
println("@@@@@@@@@@@")
/***
* 选择在循环是跳过一些值
* 10是最大值,3是叠加数
*/
0.step(10,3){
println("$it")
}
在这个方法中,foo()的?.操作符只有在引用不为null的时候才会调动指定方法或属性
//if的另一种写法
def foo(str){
//if (str!=null){str.reverse()}
str?.reverse()
}
println foo("evil")
println(foo(null))
异常处理
异常可以不处理,groovy中是自动抛出给更高一层
def openFile(def fileName){
new FileInputStream(fileName)
}
//异常处理和捕获
try {
openFile("nonexistentfile")
} catch (FileNotFoundException f) {
println("Oops:"+f)
}
但是要注意的是,他不能捕获Exception之外的Error或Throwwable。要捕获这些,需要使用catch(Throwable throwable)
groovy是轻量级的java,
方法和类是默认公开的(public)
?.操作符只有对象引用不为空时才会分派调用
静态方法内可以使用this来引用class的对象
二,javabean
groovy的class写法可以更简便一些
groovyCar.groovy
class Car {
def milse = 0
final year
Car(theCar) { year = theCar }
}
groovy.Car car = new groovy.Car(2008)
println("year:$car.year")
println("milse:$car.milse")
println("setting milse")
car.milse=25
println("milse: $car.milse")
在groovy中,get和set方法是默认创建的,不可见。(就像在java中,空参的构造方法是默认创建的一样)
在程序调用milse时,应用的不是一个字段,而是他的get。要把属性设置为只读的时候,需要用final来声明该属性,和java一样
final是不可更改的,修改final的字段任何尝试都会导致异常。因此,如果要把变量设置为私有的,必须实现一个拒绝任何修改的更改器。
GroovyCar2.groovy
class Car {
final year
private milse = 0
//相当于构造方法
Car(theCar) { year = theCar }
def getMilse() {
println("getMilse called")
milse
}
private void setMilse(milse) {
throw new IllegalAccessException("you're not allowed to change milse")
}
def drive(dist) {
if (dist > 0) milse += dist
}
}
这里使用final声明year,使用private声明milse,在drive()实例方法中,无法修改year,但是可以修改milse.milse的set()方法不允许在类的外部对该属性的值进行修改
package groovy
class Car2 {
final year
private milse = 0
//相当于构造方法
Car2(theCar) { year = theCar }
def getMilse() {
println("getMilse called")
milse
}
private void setMilse(milse) {
throw new IllegalAccessException("you're not allowed to change milse")
}
def drive(dist) {
if (dist > 0) milse += dist
}
}
def car = new Car2(2012)
println("year:$car.year")
println "milse: $car.milse"
println("Driving")
car.drive(10)
println("milse:$car.milse")
try {
print "can i set the year?"
car.year = 1900
} catch (ReadOnlyPropertyException ex) {
println(ex.message)
}
try {
print "can i set the milse?"
car.milse = 12
} catch (IllegalAccessException ex) {
println(ex.message)
}
从输出看到结果
year:2012
getMilse called
milse: 0
Driving
getMilse called
milse:10
can i set the year?Cannot set readonly property: year for class: groovy.Car2
can i set the milse?you’re not allowed to change milse
存取属性
//存取属性
Calendar.instance
//代替Calendar.getInsrance()
str="hello"
println str.class.name
//代替str.getClass().getName()
//注意:不能用map.builder等类型
//为保险起见,请使用str.getClass().name
灵活的初始化参数
groovy可以初始化一个javabean类,可以用逗号分隔赋值,也可以设计自己的方法,使其接受具名参数要利用这个特性,需要把第一个形参设置为map
package groovy
class Robot {
def type, height, width
def access(location, weight, fragile) {
println "Received fragile? $fragile,weight:$weight,loc:$location"
}
}
robot = new Robot(type: "arm", width: 10, height: 40)
println "$robot.type,$robot.height,$robot.width"
robot.access(x: 30, y: 20, z: 10, 50, true)
//可以修改参数程序
robot.access(50, true, x: 30, y: 20, z: 10)
`
运行一下,
arm,40,10
Received fragile? true,weight:50,loc:[x:30, y:20, z:10]
Received fragile? true,weight:50,loc:[x:30, y:20, z:10]
``
可选形参
groovy可以吧方法和构造器的形参设置为可选的,但是形参必须未与形参列表的末尾
package groovy
def log(x, base = 10) {
Math.log(x) / Math.log(base)
}
println(log(1024))
println(log(1024, 10))
println(log(1024, 2))
打印一下
3.0102999566398116
3.0102999566398116
10.0
groovy还会吧末尾的数组形参视为可选的
所以在下面的例子中,可以为最后一个形参提供零个或多个值
def task(name,String[] details){
println("$name -$details")
}
task("call","123-456-7890")
task("call","123-456-7890","231-546-0987")
task("call")
打印一下
call -[123-456-7890]
call -[123-456-7890, 231-546-0987]
call -[]
使用多赋值
从方法中返回多个结果,可能非常使用,要想从方法中返回多个结果,并将他们一次赋给多个变量,我们可以返回一个数组,然后将多个变量以逗号相隔,放在圆括号中,置于赋值表达式左侧即可,
def splitName(fullName){
fullName.split(" ")
}
def (firstName,lastName)=splitName("james Bond")
println("$lastName,$firstName,$lastName")
打印一下,
Bond,james,Bond
可以看到,在将字符串切割后,返回的数组赋值个了两个对象,
还可以使用该特性来交换变量,无需创建中间变量来保存被交换的值,只需要将预交换的变量放在圆括号里,置于赋值表达式左侧,同时将他们以相反的顺序放在方括号里,置于右侧即可,
def name1="Thomson"
def name2="Thompson"
println("$name1 and $name2")
(name1,name2)=[name2,name1]
println("$name1 and $name2")
打印结果
Bond,james,Bond
Thomson and Thompson
Thompson and Thomson
切换完成,
在变量和值数量不匹配时,groovy也会处理,多余的的变量,会被设置为null,多余的值则会被丢弃
def (String cat,String mouse)=['tom','jerry','spike','tyke']
println("$cat and $mouse")
打印结果为:
tom and jerry
def(first,second,third)=['tom','jerry']
println("$first $second $third")
打印结果:
tom jerry null
但是这只是针对变量可以被设置为null的类型,在不能被设定为null的时候,groovy会抛出异常
Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'null' with class 'null' to class 'int'. Try 'java.lang.Integer' instead
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'null' with class 'null' to class 'int'. Try 'java.lang.Integer' instead
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
Process finished with exit code 1
布尔值
在java中,if判断必须要这样写
if(str != null){}
在groovy中,他会尝试判断,在布尔值的地方放置一个对象,他会检查该引用是否为null,他将null视作false,将非null视作true
String str="hello"
if (str) {print" hello"}
输出:
hello
操作符重载
for (ch = "a"; ch < "z"; ch++) {
println(ch)
}
for (ch in "a".."g"){
println(ch)
}
lst=["hello"]
lst<<"world"
println(lst)
使用’++’操作符来循环’a’—‘c’中的字符.这个’++’操作符映射到String类的next( ) 方法. 上面代码的输出:
++操作符实现了循环,使用的是string的next()的方法
<<操作符,向集合中添加元素,该操作符会被转换成groovy的collection添加的leftShift()方法
通过添加映射的方法,可以为自己的类提供操作符,比如为+添加plus()方法
package groovy
class CommplexNumber {
def real, imaginary
def plus(other) {
new CommplexNumber(real: real + other.real,imaginary: imaginary + other.imaginary)
}
String toString() { "$real ${imaginary > 0 ? '+' : ''} ${imaginary}i" }
}
c1 = new CommplexNumber(real: 1, imaginary: 2)
c2 = new CommplexNumber(real: 4, imaginary: 1)
println c1 + c2
因为你ComplexNumber类中添加了plus( ) 方法,Groovy 允许你使用 + 获取两个复数相加 的结果 ,输出:5 + 3i
在某些方面操作符重载使表达式更具表现力. 不过, 通常情况下我并不喜欢操作符重载,因为 它很难被理解.
可变参数
等同于java 5中的变长参数。首先我们定义一个变长参数的方法sum:
int sum(int… var) {
def total = 0
for (i in var)
total += i
return total
}
我们可以在调用sum时使用任意个数的参数(1个,2个,3个……):
println sum(1)
println sum(1,2)
println sum(1,2,3)
def receiveVarArgs(int a, int ... b) {
println("you passed $a and $b")
}
def receiveArray(int a, int[] b) {
println("you passed $a and $b")
}
receiveVarArgs(1,2,3,4,5)
receiveArray(1,2,3,4,5)
打印结果:
you passed 1 and [2, 3, 4, 5]
you passed 1 and [2, 3, 4, 5]
注解
groovy支持所有java的注解,直接导入即可
静态导入
在java:
格式:import static 包名….类名.方法名;
可以直接导入到方法的级别
在groovy中,可以像java一样导入,可以为静态方法和类名定义别名,
import static Math.random as rand
import groovy.lang.ExpandoMetaClass as EMC
double value=rand()
def metaClass=new EMC(Integer)
assert metaClass.getClass().name=="groovy.lang.ExpandoMetaClass"
泛型
groovy支持泛型,但并不会提前检查,在运行中检查
在数据不符合泛型的时候,会尝试强制转型,如果失败,则抛出异常。
闭包和匿名内部类的冲突、
Groovyd 闭包是使用花括号的,而内部类也是使用的花括号,在正常情况下,可以通过把一个代码块附到函数调用末尾,将闭包传递给函数:instance.ethod(){}。按照这个习惯,我们可以向Calibrartor的构造器传递一个闭包来实例化一个实例,但在groovy中,错误的会认为要创建一个匿名内部类,
def calibrator3=new Calibrator(){
println("123")
}
要绕开的话,就要修改调用方式,将闭包放在构造器调用语句的圆括号内。
def calibrator= new Calibrator({
println("123")
})
def calculation={
println("456")
}
def calibrator2=new Calibrator(calculation)