groovy常用语法及实战

groovy语言简介

  • 一种基于JVM的敏捷开发语言,作为编程语言可编译成java字节码,也可以作为脚本语言解释执行。
  • 结合了Python、Ruby和Smalltalk的许多强大的特性
  • 支持面向对象编程也支持面向过程编程
  • 支持动态类型,闭包等语言特性
  • 无缝集成所有已经存在的java类库

groovy环境搭建

参考官网groovy环境搭建

groovy的hello world

在groovy语言中,如下两种写法效果完全相同

版本1:

class HelloGroovy {
    public static void main(String[] args) {
        System.out.println("hello groovy!");
    }
}

版本2:

print "hello groovy"

版本2看起来是脚本,其实是编译器帮我们变成了class,版本2脚本对应的class反编译为如下代码:

import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.InvokerHelper;
public class HelloGroovy extends Script {
    public HelloGroovy() {
    }
    public HelloGroovy(Binding context) {
        super(context);
    }
    public static void main(String... args) {
      InvokerHelper.class.invoke<invokedynamic>(InvokerHelper.class, HelloGroovy.class, args);
   }
    public Object run() {
      return this.invoke<invokedynamic>(this, "hello groovy");
   }
}

我们直观感受一个是编译语言,一个是脚本语言,但其实最后都是编译执行的。

groovy基础语法

变量

变量类型:全部为对象类型,不存在基本类型,基本类型的定义都会被转化为对象类型。

package variable
int x = 10 
println x.class
double y = 3.14
println y.class

输出为:

class java.lang.Integer
class java.lang.Double

变量定义:强类型和弱类型def定义

def x_1 = 3.1415
println x_1.class

def定义时,会根据值的类型将变量转化为对应类型,重新赋值为其他数据类型的值,则变量类型也会变为其他数据类型

建议:内部使用的变量建议使用def定义,而提供给外部程序使用的变量,则建议使用强类型

字符串

StringGString

字符串使用单引号、双引号和三个单引号定义都等同为String,区别:

  • 单引号没有格式,格式需要转义,比如换行需要拼接;三个单引号可以直接指定格式
  • 单引号不能引入扩展表达式,双引号可以在字符串中引入扩展表达式。如果双引号存在扩展表达式,类型则为GString
//def name = 'a single \'a\'string'
//println name.class

def thupleName = '''\
line one
line two
line three
'''
//println thupleName

def doubleName = "this a common String"
//println doubleName.class

def name = "Qndroid"
def sayHello = "Hello: ${name}"
//println sayHello
//println sayHello.class

def sum = "the sum of 2 and 3 equals ${2 + 3}" //可扩展做任意的表达式
//println sum

String方法来源:

java.lang.String,常用java类型,比较熟悉了

DefaultGroovyMethods,groovy所有类型都有的方法

StringGroovyMethods,继承DefaultGroovyMethods,有普通类型的参数和闭包类型的参数

package org.codehaus.groovy.runtime;
...
public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
...

groovy新增的部分string方法如下:

/* ==================字符串的方法=================== */
def str = "groovy Hello"
//println str.center(8)
//println str.padLeft(8, 'a')
def str2 = 'Hello'
//println str > str2
//println str[0]
//println str[0..1]
//println str - str2

//println str.reverse()
//println str.capitalize()

逻辑控制

//对范围的for循环
def sum = 0
for (i in 0..9) {
    sum += i
}
//println sum
sum = 0
/**
 * 对List的循环
 */
for (i in [1, 2, 3, 4, 5, 6, 7, 8, 9]) {
    sum += i
}
/**
 * 对Map进行循环
 */
for (i in ['lili': 1, 'luck': 2, 'xiaoming': 3]) {
    sum += i.value
}

方法调用

方法如果只有一个参数,可以省略()

groovy闭包

闭包定义、调用和返回值

闭包就是一段代码块,代码块用{ }表示

def clouser = { println "hello groovy!" }
//闭包调用
//clouser.call()
clouser()

闭包普通参数和隐式参数

->之前就是参数部分,可以为空(没有参数)

//普通参数
def clouser = { String name -> println "hello ${name}!" }
//闭包调用
//clouser.call()def name = 'groovy!'
clouser(name)

//多个参数
def clouser = {String name, int age -> 
    println "hello ${name}, My age is ${age}"
}
def name = 'groovy!'
clouser(name,4)

//默认隐式参数 it
def clouser = { println "hello ${it}"}
def name = 'groovy!'
clouser(name)

 

闭包的返回值

如果有return语句,则返回对应值,如果没有return语句,则返回null

闭包的用法

与基本类型的结合,闭包参数需要查看源码,看需要传入的参数

int x = fab(5)
println x
//用来求指点number的阶乘
int fab(int number) {
    int result = 1
    1.upto(number, {num -> result *= num})
    return result
}
//结果为120

int cal(int number) {
    int result = 0
    number.times {
        num -> result += num
    }
    return result
}

 

upto源码

public static void upto(Number self, Number to, @ClosureParams(FirstParam.class) Closure closure) {
    int self1 = self.intValue();
    int to1 = to.intValue();
    if (self1 <= to1) {
        for (int i = self1; i <= to1; i++) {
            closure.call(i);
        }
    } else
        throw new GroovyRuntimeException("The argument (" + to +
                                         ") to upto() cannot be less than the value (" + self + ") it's called on.");
}

 

 

 

与String结合

String str = 'the 2 and 3 is 5'
//each的遍历,返回值为本身
str.each {
    String temp -> print temp
}
//find 来查找符合条件的第一个
str.find {
    String s-> s.isNumber()
}

 

find源码

public static Object find(Object self, Closure closure) {
    BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
    for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
        Object value = iter.next();
        if (bcw.call(value)) {
            return value;
        }
    }
    return null;
} 

与数据结构结合

与文件等结合

闭包进阶

闭包关键变量this

闭包关键变量owner

闭包关键变量delegate

/**
 * 闭包的三个重要变量:this,owner,delegate
 */
def scriptClouser = {
    println "scriptClouser this:" + this //闭包定义处的类
    println "scriptClouser owner:" + owner //闭包定义处的类或者对象
    println "scriptClouser delegate:" + delegate //任意对象,默认为owner一致
}
scriptClouser.call()

//this为闭包定义处的类,

//定义了一个内部类,在脚本类中
class Person {
    def static classClouser = {
        println "classClouser this:" + this
        println "classClouser owner:" + owner
        println "classClouser delegate:" + delegate
    }
    def static say() {
        def classClouser = {
        println "methodClassClouser this:" + this
        println "methodClassClouser owner:" + owner 
        println "methodClassClouser delegate:" + delegate
        }
        classClouser.call()
    }
}
Person.classClouser.call()
Person.say()

//闭包中定义一个闭包
def nestClouser = {
    def innerClouser = {
        println "innerClouser this:" + this
        println "innerClouser owner:" + owner 
        println "innerClouser delegate:" + delegate
    }
    innerClouser.call()
}
nestClouser.call()

 

闭包的委托策略

/**
 * 闭包的委托策略
 */
class Student {
    String name
    def pretty = { "My name is ${name}"}
    
    String toString() {
        pretty.call()
    }
}
class Teacher {
    String name
}
def stu = new Student('Sarash')
def tea = new Teacher('Ondroid')
stu.pretty.delegate = tea
stu.pretty.resolveStrategy = Closure.DELEGATE_FIRST
println stu.toString() 

常见数据结构使用

列表的定义

//def list = new ArrayList() //java的定义方式
def list = [1, 2, 3, 4, 5]
println list.class
println list.size()
def array = [1, 2, 3, 4, 5] as int[]
int[] array2 = [1, 2, 3, 4, 5]

 

列表的操作:原理为操作ArrayList

映射map的定义

//def map = new HashMap()
def colors = [red  : 'ff0000',
              green: '00ff00',
              blue : '0000ff']
//索引方式
//println colors['red']
//println colors.red
colors.blue
//添加元素
//colors.yellow = 'ffff00'
colors.complex = [a: 1, b: 2]
//println colors.getClass()

 

范围range的定义和使用

def range = 1..10
//println range[0]
//println range.contains(10)
println range.from
println range.to

//遍历
range.each {
    // println it
}

for (i in range) {
    //  println i
}

def result = getGrade(75)
println result

def getGrade(Number number) {
    def result
    switch (number) {
        case 0..<60:
            result = '不及格'
            break
        case 60..<70:
            result = '及格'
            break
        case 70..<80:
            result = '良好'
            break
        case 80..100:
            result = '优秀'
            break
    }

    return result
}

 

面向对象特性

类、接口等的定义和使用

类:

  1. groovy中默认都是public
  2. 无论你是直接还是调用get/set,最终都是调用get/set

接口:

接口中不许定义非public的方法

Trait:

和接口一样,唯一不同是可以有默认实现

元编程

方法寻找流程

  1. 类中是否有此方法
  2. MetaClass中是否有此方法
  3. 是否重写了methodMissing()
  4. 是否重写了InvokeMathod()
  5. Throw MissingMethodException

为类动态的添加一个属性

Person.metaClass.sex = 'male'

为类动态的添加方法

Person.metaClass.nameUpperCase = { -> sex.toUpperCase()}

为类动态的添加静态方法

Person.metaClass.static.createPerson = {}

高级用法实战

json文件处理及json,model互转

代码样例:

import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import objectorention.Person

//def json = JsonOutput.toJson(list)
def reponse =
        getNetworkData(
                'http://xxx.json')

println reponse.data.head.name

def getNetworkData(String url) {
    //发送http请求---完全是使用java库
    def connection = new URL(url).openConnection()
    connection.setRequestMethod('GET')
    connection.connect()
    def response = connection.content.text
    //将json转化为实体对象
    def jsonSluper = new JsonSlurper()
    return jsonSluper.parseText(response)
} 

xml文件读取

代码样例:

import groovy.xml.MarkupBuilder

final String xml = '''
    <response version-api="2.0">
        <value>
            <books id="1" classification="android">
                <book available="20" id="1">
                    <title>疯狂Android讲义</title>
                    <author id="1">李刚</author>
                </book>
                <book available="14" id="2">
                   <title>第一行代码</title>
                   <author id="2">郭林</author>
               </book>
               <book available="13" id="3">
                   <title>Android开发艺术探索</title>
                   <author id="3">任玉刚</author>
               </book>
               <book available="5" id="4">
                   <title>Android源码设计模式</title>
                   <author id="4">何红辉</author>
               </book>
           </books>
           <books id="2" classification="web">
               <book available="10" id="1">
                   <title>Vue从入门到精通</title>
                   <author id="4">李刚</author>
               </book>
           </books>
       </value>
    </response>
'''

//开始解析此xml数据
def xmlSluper = new XmlSlurper()
def response = xmlSluper.parseText(xml)

//println response.value.books[0].book[0].title.text()
//println response.value.books[0].book[0].author.text()
//println response.value.books[1].book[0].@available

def list = []
response.value.books.each { books ->
    //下面开始对书结点进行遍历
    books.book.each { book ->
        def author = book.author.text()
        if (author.equals('李刚')) {
            list.add(book.title.text())
        }
    }
}
//println list.toListString()

//深度遍历xml数据
def titles = response.depthFirst().findAll { book ->
    return book.author.text() == '李刚' ? true : false
}
//println titles.toListString()

//广度遍历xml数据
def name = response.value.books.children().findAll { node ->
    node.name() == 'book' && node.@id == '2'
}.collect { node ->
    return node.title.text()
}

//println name

 

普通文件的读写

java文件处理

  1. 节点流:InputStream,OutputStream及其子类
  2. 处理流:ReaderWriter及其子类

所有java对文件的处理类,groovy都可以使用

groovy扩展了许多更加快捷和强大的方法

代码示范:

def file = new File(pathname:'../../test.txt')
file.eachline { line ->
    println line
}

def text = file.getText()
println text

def result = file.readLines()

//读取文件部分内容
def reader = file.withReader { reader ->
    char[] buffer = new char[100]
    reader.read(buffer)
    return buffer
}
println reader
def copy(String sourcePath, String destationPath) {
    try {
        //首先创建目标文件
        def desFile = new File(destationPath)
        if (!desFile.exists()) {
            desFile.createNewFile()
        }

        //开始copy
        new File(sourcePath).withReader { reader ->
            def lines = reader.readLines()
            desFile.withWriter { writer ->
                lines.each { line ->
                    writer.append(line + "\r\n")
                }
            }
        }
        return true
    } catch (Exception e) {
        e.printStackTrace()
    }
    return false
} 

groovy与java对比

  • 没有java那么多的限制
  • 对java的功能进行了极大的扩展
  • 既可以编写应用,也可以编写脚本

语法上区别:

  • Groovy 语句可以不用分号结尾
  • 定义变量的时候可以不指定其类型、Groovy 中函数的返回值也可以是无类型的
  • 最后一行代码的执行结果就是函数的返回值
  • 如果指定了函数返回类型,则可不必加 def 关键字来定义函数
  • Groovy中函数调用的时候还可以不加括号
  • 闭包是一段代码,所以需要用花括号括起来
  • -> 箭头前面是参数定义,箭头后面是代码
  • Groovy 中,当函数的最后一个参数是闭包的话,可以省略圆括号或闭包放在后面
  • 如果发送的实参的个数多于方法的形参个数,而且多出的实参是名值对,那么Groovy会假设方法的第一个形参是一个Map,然后将实参列表中的所有名值对组织到一起,作为第一个形参的值,之后,再将剩下的实参按照给出的顺序赋给其他的形参,就和我们输出的结果一样。
posted @ 2019-08-05 14:26  GisFe  阅读(5151)  评论(0编辑  收藏  举报