`

Groovy学习1

 
阅读更多

groovy的执行有两种方式
1.先将groovy文件编译(用groovyc编译器)为class类,之后交由JVM加载执行(这种方式跟JAVA没什么太大的区别)
2.在运行时生成groovy类,直接通过groovy Myscript.groovy来运行这个脚本,那么其执行的步骤具体来说有:
  (1)Myscript.groovy被传递给groovy的转换器
  (2)转换器产生了一个抽象语法树(AST)来表达在Myscript.groovy中的所有代码。
  (3)groovy类生成器根据AST产生JAVA字节码,根据脚本的内容,结果可能是多个类,现在类通过groovy类加载器是可以使用的了。
  (4)java运行时像调用一个java类Myscript一样来调用第三步产生的类。
第二种的方式执行如果不从这个步骤来看,表象是解释执行的一样,而事实上他在背后执行了如上的一些动作,这些类在使用之前已经完整的构建并且在运行时不能进行更改。
说groovy是动态语言,但groovy类是一次性产生并且在加载之后不能改变字节码的,类不能改变,那怎么能增加方法呢?groovy类生成器生成的字节码必然不同于java编译器生成的字节码(不是在格式方面,而是在内容方面),假设一个groovy文件包括一个像foo语句,groovy产生的字节码不是直接调用这个方法,而是这样:
getMetaClass().invokeMethod(this, "foo", EMPTY_PARAMS_ARRAY)
也就是说,方法的调用被重定向为通过对象的MetaClass进行处理,这个MetaClass现在能在运行时处理如拦截,重定向,增加/删除方法等之类的方法调用。这个原则运用到所有通过groovy代码的处理。
动态代码的第二个选项是把代码放在一个字符串中并且通过groovy来运行它,如
def code = '1 + 1.5'
println code   //1 + 1.5
println evaluate(code)   //2.5

groovy中不存在原始类型,一切都是对象,在JVM中,这些原始类型对应的对象是通过JAVA平台已经存在的包装类型进行包装的。

操作符重写:
class Money{
  private int amount;
  Money(amountValue){
    amount = amountValue
  }
  Money plus(Money other){
    if(null == other) return null
    return new Money(amount + other.amount)
  }

def buck = new Money(2)
assert buck + buck == new Money(4) //pass

JAVA中判断两个对象值是否相等,是通过equals,而groovy中则用==
而判断两个对象是否是同一个引用,JAVA是通过==,而groovy中则用is
特别的例子:def abc1 = 'abc'    def abc2 = ‘abc’  println abc1.is(abc2) 返回true,这是因为这与JAVA中的String一样,缓存在string常量池的,两者指向相同的引用。

GDK也定义了times,upto,downto,step方法
def store = ''
10.times{
  store += 'x'
}
assert store == 'xxxxxxxxxx'
store = ''
1.upto(5) { number ->
   store += number
}
assert store == '12345'
store = ''
2.downto(-2) { number ->
   store += number + ' '
}
assert store == '2 1 0 -1 -2 '
store = ''
0.step(0.5, 0.1){ number ->
   store += number + ' '
}
assert store == '0 0.1 0.2 0.3 0.4 '

range的使用:
assert (0..10).containes(0)
assert (0..10).containes(5)
assert (0..10).containes(10)

assert (0..10).containes(-1) == false
assert (0..10).containes(11) == false

assert (0..<10).containes(9)
assert (0..<10).containes(10) == false

def a = 0..10
assert a instanceof Range
assert a.contains(5)

a = new IntRange(0, 10)
assert a.contains(5)

assert (0.0..1.0).contains(0.5)

def today == new Date()
def yesterday = today - 1
assert (yesterday..today).size() == 2

assert ('a'..'c').contains('b')

def log =''
for (element in 9..5){
  log += element
}
assert log == '98765'

log = ''
(9..<5).each{ element ->
    log +=element
}
assert log == '9876'

age = 36
switch(age){
   case  16..20  :  rate = 0.05; break
   case  21..50  :  rate = 0.06; break
   case  51..65  :  rate = 0.07; break
   default : throw new Exception()
}
assert rate == 0.6

ages = [20,36,42,56]
midage = 21..50
assert ages.grep(midage) == [36,42]

上面的例子中,使用了date和String类型的范围,其实,range可以使用任何类型,只要这个类型满足以下两个条件:
1. 实现了next和previous方法,也就是说,重写++和--操作符
2. 实现了java.lang.Compareable接口,也就是说实现了compareTo方法,实际上是重写<==>操作符。

list通过index处理:
myList = ['a','b','c','d','e','f']
assert myList[0..2] == ['a','b','c']
assert myList[0,2,4] == ['a','c','e']
myList[0..2] = ['x','y','z']
assert myList == ['x','y','z','d','e','f']
myList[3..5] = []
assert myList == ['x','y','z']
myList[1..1] = ['y','1','2']
assert myList == ['x','y','1','2','z']
groovy里的索引也可以是负数,从负数索引是从列表的最后往前周。如
list = [0,1,2,3,4], 则list[-1] = 4, list[-2] = 3, list[4..0] =
[4,3,2,1,0], list[-2..2] = [3,4,0,1,2],不过一般为避免迷惑,不要这么去用。

除了通过索引操作List,还可以通过方法操作:

myList = []
myList += 'a'
assert myList == ['a']
myList += ['b','c']
assert myList == ['a','b','c']
myList = []
myList << 'a' << 'b'
assert myList == ['a','b']
assert myList - ['b'] == ['a']
assert myList * 2 == ['a','b','a','b']

GDK增加了额外的方法到List接口,Collection接口和Object类上。

list里的一些方法:
assert [1,[2,3]].flatten() == [1,2,3]
assert [1,2,3].intersect([4,3,1]) == [3,1]
assert [1,2,3].disjoint([4,5,6])

list = [1,2,3]
popped = list.pop()
assert popped == 3
assert list == [1,2]

assert [1,2].reverse() == [2,1]
assert [3,1,2].sort() == [1,2,3]

def list = [[1,0],[0,1,2]]
list = list.sort{a,b -> a[0] <=>b[0]}
assert list == [[1,0],[0,1,2]]

list = ['a','b','c']
list.remove(2)
assert list == ['a','b']
list.remove('b')
assert list == ['a']

list = ['a','b','b','c']
list.removeAll(['b','c'])
assert list == ['a']

def odd = [1,2,3].findAll{ item ->
    item%2 == 1
}
assert odd == [1,3]

def x = [1,1,1]
assert [1] == new HashSet(x).toList()
assert [1] == x.unique

def x = [1,null,1]
assert [1,1] == x.findAll{it != null}
assert [1,1] == x.grep{it}

list遍历:
def list = [1,2,3]
assert list.count(2) == 1
assert list.max() == 3
assert list.min() == 1

def even = list.find{ item ->
   item%2 == 0
}
assert even == 2

assert list.every{item -> item < 5}
assert list.any{item -> item < 2}

def store = ''
list.each{ item ->
   store += item
}
assert store == '123'

store = ''
list.reverseEach{ item ->
    store += item
}
assert store == '321'

assert list.join('-') == '1-2-3'

result = list.inject(0){ clinks, guest ->
   clinks += guests
}
assert result == 0 + 1+2+3
assert list.sum() == 6

map的取值使用:
def myMap = [a:1,b:2,c:3]

assert myMap['a'] == 1
assert myMap.a == 1
assert myMap.get('a') == 1
assert myMap.get('a',0) == 1

assert myMap['d'] == null
assert myMap.d == null
assert myMap.get('d') == null

map的其他方法:
def myMap = [a:1,b:2,c:3]
def other = [b:2,c:3,a:1]
assert myMap == other
assert myMap.isEmpty() == false
assert myMap.size() == 3
assert myMap.containsKey('a')
assert myMap.containsValue(1)
assert myMap.keySet() == toSet(['a','b','c'])
assert toSet(myMap.values()) == toSet([1,2,3])
assert myMap.entrySet() instanceof Collection

assert myMap.any {entry -> entry.value > 2}
assert myMap.every {entry -> entry.key < 'd'}

map的遍历:
def myMap = [a:1,b:2,c:3]

myMap.each{ entry ->
   //entry.key
   //entry.value
}
myMap.each{key,value ->
   //key
   //value
}

for(key in ,myMap.keySet()){
   //key
}
for(value in ,myMap.values()){
   //value
}

面向对象的最高原则是对象有自己的行为和数据,闭包也是对象,他主要的目的是他们的行为。
一个闭包是被包装为一个对象的代码块,实际上闭包像一个接受参数并且能够有返回值的方法。闭包是一个普通对象,因为你能够通过一个变量引用到它,正如你能够引用到任何别的对象一样。不要忘记JVM根本就不知道你正在运行groovy代码,因此你能处理闭包对象也没有什么特别奇怪,闭包仅仅是一个对象,groovy提供了一种非常容易创建闭包的方式和启用了一些非常常用的行为。

处理资源上,JAVA需要try,catch,finally,在finally里close掉这个资源,而在groovy中,可以像以下代码:
new File('myfile.txt').eachLine { println it }
file的eachLine方法负责处理文件输入流的打开和关闭,这样避免我们偶尔的错误处理形成资源泄露。在JDK7中提供了try-with-resource,可以自动关闭相关的资源(只要该资源实现了AutoCloseable接口,jdk7为绝大部分资源对象都实现了这个接口):
static String readFirstLineFromFile(String path) throws IOException{
   try(BufferedReader br = new BufferedReader(new FileReader(path))){
       return br.readLine();
   }
}

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics