groovy_groovy 取值 - CSDN
groovy 订阅
Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码。由于其运行在 JVM 上的特性,Groovy也可以使用其他非Java语言编写的库。 展开全文
Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码。由于其运行在 JVM 上的特性,Groovy也可以使用其他非Java语言编写的库。
信息
类    别
编程语言
发行时间
2003年
外文名
Groovy
创作者
Guillaume Laforge
Groovy简介
Groovy 是 用于Java虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。使用该种语言不必编写过多的代码,同时又具有闭包和动态语言中的其他特性。Groovy是JVM的一个替代语言(替代是指可以用 Groovy 在Java平台上进行 Java 编程),使用方式基本与使用 Java代码的方式相同,该语言特别适合与Spring的动态语言支持一起使用,设计时充分考虑了Java集成,这使 Groovy 与 Java 代码的互操作很容易。(注意:不是指Groovy替代java,而是指Groovy和java很好的结合编程。 [1]  (概述图片来源:)
收起全文
精华内容
参与话题
  • Groovy精简教程

    千人学习 2018-10-22 21:38:03
    注重实践,剔除繁琐的理论,通过案例讲解我们常用的知识点,各个知识点之间相对独立,不用担心某一个知识点学不会而耽搁学其他的知识点。轻轻松松入门Groovy
  • Groovy入门(一)—— Groovy语法

    万次阅读 2017-10-14 14:42:07
    Groovy语法 1. 注释 1.1. 单行注释 Groovy单行注释以//开头,可以出现在程序的各个位置。 // a standalone single line comment println "hello" // a comment till the end of the line 1.2. 多行注释 多行...

    Groovy语法

    1. 注释

    1.1. 单行注释

    Groovy单行注释以//开头,可以出现在程序的各个位置。

    // a standalone single line comment
    println "hello" // a comment till the end of the line

    1.2. 多行注释

    多行注释以 /* 开头,以 */ 结尾,可以出现在程序的任何位置。

    /* a standalone multiline comment
       spanning two lines */
    println "hello" /* a multiline comment starting
                       at the end of a statement */
    println 1 /* one */ + 2 /* two */

    1.3. GroovyDoc

    GroovyDoc以 /** 开头,以 */结尾,中间行一般可以选择性的以 * 开头。

    GroovyDoc一般用于:

    • 类型定义 (classes, interfaces, enums, annotations)
    • 字段或属性定义
    • 方法定义
    /**
     * A Class description
     */
    class Person {
        /** the name of the person */
        String name
        /**
         * Creates a greeting method for a certain person.
         *
         * @param otherPerson the person to greet
         * @return a greeting message
         */
        String greet(String otherPerson) {
           "Hello ${otherPerson}"
        }
    }

    1.4. Shebang line

    #开头写在文件的第一行,告诉Unix或类Unix系统以何种解释器去运行脚本。前提是已经安装了Groovy,并且配置完PATH。

    #!/usr/bin/env groovy
    println "Hello from the shebang line"

    2. 关键字

    as assert break case catch class const continue def default do else enum extends false finally for goto if implements import in instanceof interfacenew null package return super switch this throwthrows trait true try while

    3. 标识符

    3.1. 普通标识符(Normal identifiers)

    标识符以字母、$、_开头,不能以数字开头,但后面可以跟数字。

    字母的的取值区间为:

    • 'a' to 'z' (lowercase ascii letter)
    • 'A' to 'Z' (uppercase ascii letter)
    • '\u00C0' to '\u00D6'
    • '\u00D8' to '\u00F6'
    • '\u00F8' to '\u00FF'
    • '\u0100' to '\uFFFE'

    eg:

    def name
    def item3
    def with_underscore
    def $dollarStart

    3.2. 引用标识符(Quoted identifiers)

    引用标识符是.(dot)后的表达式。比如说nameperson.name的一部分,那么我们可以通过person."name"或者person.'name'来引用它。这点与Java不同,Java不允许这种格式的引用。eg:

    def map = [:]
    
    map."an identifier with a space and double quotes" = "ALLOWED"
    map.'with-dash-signs-and-single-quotes' = "ALLOWED"
    
    assert map."an identifier with a space and double quotes" == "ALLOWED"
    assert map.'with-dash-signs-and-single-quotes' == "ALLOWED"

    Groovy提供了不同种类的字符串字面量,所有String类型的字面量都允许写到.后作为引用标识符。eg:

    map.'single quote'
    map."double quote"
    map.'''triple single quote'''
    map."""triple double quote"""
    map./slashy string/
    map.$/dollar slashy string/$

    4. String

    Groovy支持java.lang.String和GString(groovy.lang.GString)字符串类型,其中GString在一些编程语言中被称作interpolated stringsWikipedia - String interpolation

    4.1. 单引号字符串(Single quoted string)

    单引号字符串被解释成java.lang.string,不支持内插值。

    'a single quoted string'

    4.2. 字符串拼接

    Groovy中连接字符串使用+

    assert 'ab' == 'a' + 'b'

    4.3. 三单引号字符串(Triple single quoted string)

    三单引号字符串被解释成java.lang.String类型,不支持内插值。

    三单引号支持多行,支持文本跨行,并且不需要换行符,字符串原样输出。eg:

    def aMultilineString = '''line one
    line two
    line three'''

    通常,代码在格式化完毕之后,会保持缩进。对于三单引号字符串来说,会把缩进也原样输出。Groovy提供了String#stripIndent()方法来去掉字符串前的缩进,并且提供了String#stripMargin()方法,可以删除字符串开始位置的指定分隔符。

    当我们创建如下的字符串时:

    def startingAndEndingWithANewline = '''
    line one
    line two
    line three
    '''

    会发现字符串开头包含一个换行符\n,可以通过字符串开头添加``来消除开头的换行符。

    def strippedFirstNewline = '''\
    line one
    line two
    line three
    '''
    assert !strippedFirstNewline.startsWith('\n')

    4.4. 双引号字符串

    "a double quoted string"

    当双引号字符串中没有插值表达式时,字符串的类型为java.lang.String,当双引号字符串中包含插值表达式时,字符串类型为groovy.lang.GString

    4.4.1 字符串插值(String interpolation)

    除了单引号字符串和三单引号字符串以外,任何Groovy表达式可以出现在所有的字符串字面量中。插值实际上是替换字符串中的占位符。占位符表达式是被${}围绕或以$为前缀的点表达式(dotted expressions),当GString传递给一个以String类型作为参数的方法时,会调用toString方法,将占位符替换为表达式所代表的值。eg:

    def name = 'Guillaume' // a plain string
    def greeting = "Hello ${name}"
    assert greeting.toString() == 'Hello Guillaume'
    def sum = "The sum of 2 and 3 equals ${2 + 3}"
    assert sum.toString() == 'The sum of 2 and 3 equals 5'

    实际上${}中不仅可以使用表达式,也可以写声明语句,但是这些语句的返回值为null,例如"The sum of 1 and 2 is equal to ${def a = 1; def b = 2; a + b}"在Groovy中是被支持的,但是一般在Groovy中不推荐这样写。更好的写法是在GString中只使用简单的占位符。

    使用$点表达式(dotted expressions),eg:

    def person = [name: 'Guillaume', age: 36]
    assert "$person.name is $person.age years old" == 'Guillaume is 36 years old'

    使用$点表达式(dotted expressions)的时候,只允许a.ba.b.c的写法,不能调用方法,否则会抛出groovy.lang.MissingPropertyException的异常。因为Groovy在替换插值时调用的是toString方法。

    def number = 3.14
    
    shouldFail(MissingPropertyException) {
        println "$number.toString()" // groovy.lang.MissingPropertyException
    }

    "$number.toString()" 替换为 "${number.toString}()" 可以正常运行。

    4.4.2. 特殊的插值闭包表达式(Special case of interpolating closure expressions)

    闭包表达式的格式为:${->},简单的理解为一个闭包前面加了一个$符号。eg:

    def sParameterLessClosure = "1 + 2 == ${-> 3}" 
    assert sParameterLessClosure == '1 + 2 == 3'
    
    def sOneParamClosure = "1 + 2 == ${ w -> w << 3}" 
    assert sOneParamClosure == '1 + 2 == 3'

    关于闭包表达式:

    • 闭包是无参的
    • 闭包包含一个java.io.StringWriter参数,可以通过追加内容到>>后面的方式添加。

    闭包表达式只能有0个或1个参数。

    闭包表达式和普通表达式唯一的不同是:lazy evaluation 。详情移步 —> Wikipedia - Lazy evaluation

    def number = 1 
    def eagerGString = "value == ${number}"
    def lazyGString = "value == ${ -> number }"
    
    assert eagerGString == "value == 1" 
    assert lazyGString == "value == 1" 
    
    number = 2 
    assert eagerGString == "value == 1" // eagerGString不会再次求值
    assert lazyGString == "value == 2"  // lazyGString会再次求值
    4.4.3. GString and String hashCodes

    尽管GString可以代替String,但是他们还一处不同:他们的hashCodes不同。原生的Java String 是immutable(不可变的),但是GString所表示的String却是可变的,依赖于的它的插值。即使GString和Java原生String类型有相同的字面量,它们的hashCodes的值可能不同。eg:

    assert "one: ${1}".hashCode() != "one: 1".hashCode()

    由于GString和String的hashCodes不同,所以应该避免使用使用GString作为Map的key。eg:

    def key = "a"
    def m = ["${key}": "letter ${key}"]     
    assert m["a"] == null

    4.5. 三双引号字符串( Triple double quoted string)

    类似于三单引号字符串,支持跨行。也类似双引号字符,支持GString插值操作。

    def name = 'Groovy'
    def template = """
        Dear Mr ${name},
        You're the winner of the lottery!
        Yours sincerly,
        Dave
    """
    
    assert template.toString().contains('Groovy')

    4.6. Slashy string

    /作为界定符的字符串,叫做Slashy string。它通常被用于写正则表达式,因为不需要转译的反斜线``。

    def fooPattern = /.*foo.*/
    assert fooPattern == '.*foo.*'

    如果字符串中间出现/,这种情况下才需要转译。eg:

    def escapeSlash = /The character \/ is a forward slash/
    assert escapeSlash == 'The character / is a forward slash'

    Slashy string允许跨行,eg:

    def multilineSlashy = /one
        two
        three/
    
    assert multilineSlashy.contains('\n')

    Slashy string支持插值操作,类似GString。eg:

    def color = 'blue'
    def interpolatedSlashy = /a ${color} car/
    
    assert interpolatedSlashy == 'a blue car'

    如果Slashy string是空字符串//,那么编译过程中会把//当做注释。

    4.7. Dollar slashy string

    Dollar slashy string相当于跨行的GString,以$/开头,以/$结尾。以$作为转译字符,可以转译另一个$/

    4.8. 字符(Characters)

    Groovy没有明确的字符类型,可以通过以下三种方式创建:

    char c1 = 'A'  // 类型声明为char
    assert c1 instanceof Character 
    
    def c2 = 'B' as char  // 通过as将类型强制指定为char
    assert c2 instanceof Character
    
    def c3 = (char)'C'  // 通过类型转换
    assert c3 instanceof Character

    5. 数值(Numbers)

    5.1. 整型(Integral literals)

    Groovy的整型和Java类似:

    • byte
    • char
    • short
    • int
    • long
    • java.lang.BigInteger

    eg:

    // primitive types 原始类型
    byte b = 1
    char c = 2
    short s = 3
    int i = 4
    long l = 5
    
    // infinite precision 引用类型
    BigInteger bi = 6

    如果使用def声明类型,那么这个整型是可变的。它会数值的大小来匹配类型。(负数也如此)

    def a = 1
    assert a instanceof Integer
    
    // Integer.MAX_VALUE
    def b = 2147483647
    assert b instanceof Integer
    
    // Integer.MAX_VALUE + 1
    def c = 2147483648
    assert c instanceof Long
    
    // Long.MAX_VALUE
    def d = 9223372036854775807
    assert d instanceof Long
    
    // Long.MAX_VALUE + 1
    def e = 9223372036854775808
    assert e instanceof BigInteger

    其它进制:

    • 2进制是以0b开头的数字
    • 8进制是以0开头的数字
    • 16进制是以0x开头的数字

    5.2. 浮点数(Decimal literals)

    浮点数类型和Java类似:

    • float
    • double
    • java.lang.BigDecimal

    浮点数类型支持指数,通过eE实现。

    // primitive types
    float f = 1.234
    double d = 2.345
    
    // infinite precision
    BigDecimal bd = 3.456
    
    assert 1e3 == 1_000.0
    assert 2E4 == 20_000.0
    assert 3e+1 == 30.0
    assert 4E-2 == 0.04
    assert 5e-1 == 0.5

    为了计算的准确性,Groovy使用BigDecimal作为浮点数的默认类型。除非显示的声明floatdouble,否则浮点数类型为java.lang.BigDecimal。尽管如此,在一些接受参数为floatdouble的方法中,依然可以使用BigDecimal类型作为参数传递。

    5.3. 数值中使用下划线

    当数值过长的时候,可以使用_对数字进行分组,以使阅读更加简洁明了。eg:

    long creditCardNumber = 1234_5678_9012_3456L
    long socialSecurityNumbers = 999_99_9999L
    double monetaryAmount = 12_345_132.12
    long hexBytes = 0xFF_EC_DE_5E
    long hexWords = 0xFFEC_DE5E
    long maxLong = 0x7fff_ffff_ffff_ffffL
    long alsoMaxLong = 9_223_372_036_854_775_807L
    long bytes = 0b11010010_01101001_10010100_10010010

    5.4. 数值类型后缀(Number type suffixes)

    可以通过使用后缀来指定数字类型

    • BigInteger类型后缀为Gg
    • Long类型后缀为Ll
    • Integer类型后缀为Ii
    • Bigdecimal类型后缀为Gg
    • Double类型后缀为Dd
    • Float类型后缀为Ff

    eg:

    assert 42I == new Integer('42')
    assert 42i == new Integer('42') // lowercase i more readable
    assert 123L == new Long("123") // uppercase L more readable
    assert 2147483648 == new Long('2147483648') // Long type used, value too large for an Integer
    assert 456G == new BigInteger('456')
    assert 456g == new BigInteger('456')
    assert 123.45 == new BigDecimal('123.45') // default BigDecimal type used
    assert 1.200065D == new Double('1.200065')
    assert 1.234F == new Float('1.234')
    assert 1.23E23D == new Double('1.23E23')
    assert 0b1111L.class == Long // binary
    assert 0xFFi.class == Integer // hexadecimal
    assert 034G.class == BigInteger // octal

    6. Boolean

    布尔类型是一种特殊的类型用于判断对或错:truefalse。Groovy有一套特别的规则用于强制将non-boolean类型转换为bollean类型。

    7. List

    Groovy中没有定义自己的List类型,使用的是java.util.List类型。通过一对[]包括,里面的元素以,分隔来定义一个List。默认情况下,创建的List的类型为java.util.ArrayList。eg:

    def numbers = [1, 2, 3]         
    
    assert numbers instanceof List  
    assert numbers.size() == 3

    List中元素可以是不同类型:

    def heterogeneous = [1, "a", true]

    通过使用as操作符可以强制指定List的类型,或者在声明List变量时强制指定类型。eg:

    def arrayList = [1, 2, 3]
    assert arrayList instanceof java.util.ArrayList
    
    def linkedList = [2, 3, 4] as LinkedList    
    assert linkedList instanceof java.util.LinkedList
    
    LinkedList otherLinked = [3, 4, 5]          
    assert otherLinked instanceof java.util.LinkedList

    可以使用[]获取List中的元素,可以使用<<向list末尾追加元素。

    def letters = ['a', 'b', 'c', 'd']
    assert letters[0] == 'a'     
    assert letters[1] == 'b'
    assert letters[-1] == 'd'    
    assert letters[-2] == 'c'
    letters[2] = 'C'             
    assert letters[2] == 'C'
    letters << 'e'               
    assert letters[ 4] == 'e'
    assert letters[-1] == 'e'
    assert letters[1, 3] == ['b', 'd']         
    assert letters[2..4] == ['C', 'd', 'e']

    8. Arrays

    Groovy定义数组的方式和定义list的方式一样,只不过声明时需要制定类型,或者通过as来强制制定类型为Array。

    String[] arrStr = ['Ananas', 'Banana', 'Kiwi']  
    
    assert arrStr instanceof String[]    
    assert !(arrStr instanceof List)
    
    def numArr = [1, 2, 3] as int[]    
    
    assert numArr instanceof int[]       
    assert numArr.size() == 3
    
    //多维数组
    
    def matrix3 = new Integer[3][3]         
    assert matrix3.size() == 3
    Integer[][] matrix2                     
    matrix2 = [[1, 2], [3, 4]]
    assert matrix2 instanceof Integer[][]

    Groovy不支持Java数组的初始化方式。

    9. Maps

    Map定义方式为:使用[]包括,里面的元素为key/value的形式,key和value以:分隔,每一对key/value以逗号分隔。Groovy穿件的map默认类型为java.util.LinkedHashMap。eg:

    def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']   
    
    assert colors['red'] == '#FF0000'    
    assert colors.green == '#00FF00'    
    
    colors['pink'] = '#FF00FF'           
    colors.yellow = '#FFFF00'       
    
    assert colors.pink == '#FF00FF'
    assert colors['yellow'] == '#FFFF00'
    
    assert colors instanceof java.util.LinkedHashMap

    Map中通过[key].key的方式来获取key对应的value。如果key不存在,则返回null。

    当我们使用数字作为key时,这个数字可以明确的认为是数字,并不是Groovy根据数字创建了一个字符串。但是如果以一个变量作为key的话,需要将变量用()包裹起来,否则key为变量,而不是变量所代表的值。eg:

    def key = 'name'
    def person = [key: 'Guillaume']     // key实际上为"key"
    
    assert !person.containsKey('name')   
    assert person.containsKey('key')  
    
    person = [(key): 'Guillaume']    // key实际上为"name"
    
    assert person.containsKey('name')    
    assert !person.containsKey('key')


    作者:losemycat
    链接:http://www.jianshu.com/p/f02b066bb055
    來源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    展开全文
  • groovy语言介绍

    千次阅读 2018-11-02 16:23:11
    1.什么是groovy?  Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码。由于其运行在 JVM 上的...

    1.什么是groovy?

           Groovy是一种基于JVMJava虚拟机)的敏捷开发语言,它结合了PythonRubySmalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码。由于其运行在 JVM 上的特性,Groovy 可以使用其他 Java 语言编写的库。

           Groovy是一种基于Java平台的面向对象语言。 Groovy 1.0200712日发布,其中Groovy 2.4是当前的主要版本。 Groovy通过Apache License v 2.0发布。

          目前最新版本为2.5.3

    2.Groovy的特点

    Groovy中有以下特点:

    • 同时支持静态和动态类型
    • 支持运算符重载
    • 本地语法列表和关联数组
    • 对正则表达式的本地支持
    • 各种标记语言,如XMLHTML原生支持
    • Groovy对于Java开发人员来说很简单,因为JavaGroovy的语法非常相似
    • 您可以使用现有的Java
    • Groovy扩展了java.lang.Object

    动态类型

    类型对于变量,属性,方法,闭包的参数以及方法的返回类型都是可有可无的,都是在给变量赋值的时候才决定它的类型, 不同的类型会在后面用到,任何类型都可以被使用,即使是基本类型 (通过自动包装(autoboxing). 当需要时,很多类型之间的转换都会自动发生,比如在这些类型之间的转换: 字符串(String),基本类型(int) 和类型的包装类 (Integer)之间,可以把不同的基本类型添加到同一数组(collections)中。

    运算符重载

    运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。

    3.类

    Groovy类和java类一样,完全可以用标准java bean的语法定义一个Groovy类。但作为另一种语言,可以使用更Groovy的方式定义类,这样的好处是,可以少写一半以上的javabean代码。

    1)不需public修饰符

    如前面所言,Groovy的默认访问修饰符就是public,如果Groovy类成员需要public修饰,则根本不用写它。

    2)不需要类型说明

    同样前面也说过,Groovy也不关心变量和方法参数的具体类型。

    3)不需要getter/setter方法

    在很多ide(如eclipse)早就可以为程序员自动产生getter/setter方法了,在Groovy中,不需要getter/setter方法--所有类成员(如果是默认的public)根本不用通过getter/setter方法引用它们(当然,如果一定要通过getter/setter方法访问成员属性,Groovy也提供了它们)。

    4)不需要构造函数

    不再需要程序员声明任何构造函数,因为实际上只需要两个构造函数(1个不带参数的默认构造函数,1个只带一个map参数的构造函数--由于是map类型,通过这个参数可以构造对象时任意初始化它的成员变量)。

    5)不需要;结尾

    Groovy中每一行代码不需要分号作为结束符。

    4. 文件与类的关系

    Groovy中类和文件的对应关系并不像Java中那么固定(Java中一个文件只能有一个声明为public的类和其他一些非公共的类和内嵌类) 。在同一个groovy文件中可以包含多个public的类定义。具体规则如下:

    1、如果在一个groovy文件中没有任何类定义,它将被当做script来处理,也就意味着这个文件将被透明的转换为一个Script类型的类,这个自动转换得到的类将使用原始的groovy文件名(去掉扩展名,没有包名,在default包中)作为类的名字。groovy文件的内容被打包进run方法,另外在新产生的类中被加入一个main方法以进行外部执行该脚本。

    2、如果在groovy文件正好有一个类的定义,并且该类的名字与文件名称相同,那么这就和java中的类与文件的一一对应关系相同。

    3、在一个groovy文件中可以包含多个不同可见性的类定义,并且没有强制性的要求其中有一个类的类名与文件名相同。groovy编译器会很乐于把该文件中定义的所有的类都编译成*.class文件。如果希望能够直接调用这个groovy script,比如说在使用groovy命令行或者在某个IDE中执行,那么应该在该文件中的第一个类中定义一个main方法。

    4、在一个groovy文件中可以混合类的定义和脚本定义。在这种情况下,那些脚本代码将会变成直接调用的主类,所以在这种情况下不应该再定义一个和文件同名的类。

    5、在没有经过明确的编译过程即执行时,groovy将通过文件名来查找类。在这种情况下,名称将会很重要。Groovy只能找到那些和文件名匹配的类。在找到这种名字匹配的类时,找到的文件中定义的其他类将被解析并变得对groovy可见。

    5.语法

    基本类型

    • byte -这是用来表示字节值。例如2
    • short -这是用来表示一个短整型。例如10
    • int -这是用来表示整数。例如1234
    • long -这是用来表示一个长整型。例如10000090
    • float -这是用来表示32位浮点数。例如12.34
    • double -这是用来表示64位浮点数,这些数字是有时可能需要的更长的十进制数表示。例如12.3456565
    • char -这定义了单个字符文字。例如“A”
    • Boolean -这表示一个布尔值,可以是truefalse
    • String -这些是以字符串的形式表示的文本。例如,“Hello World”的。

     

    • BigInteger类型后缀为Gg
    • Long类型后缀为Ll
    • Integer类型后缀为Ii
    • Bigdecimal类型后缀为Gg
    • Double类型后缀为Dd
    • Float类型后缀为Ff

    与Java一致,但是可以不声明类型,使用def关键字。

    字符

    Groovy没有明确的字符类型,可以通过以下三种方式创建:

    1. char c1 = 'A'  // 类型声明为char
    2. assert c1 instanceof Character
    3.  
    4. def c2 = 'B' as char  // 通过as将类型强制指定为char
    5. assert c2 instanceof Character
    6.  
    7. def c3 = (char)'C'  // 通过类型转换
    8. assert c3 instanceof Character

    字符串

    Groovy中的字符串可以用单引号('),双引号()或三引号(”“”)括起来。此外,由三重引号括起来的Groovy字符串可以跨越多行

          String a = 'Hello Single'; 
          String b = "Hello Double"; 
          String c = "'Hello Triple" + "Multiple lines'";

    运算符

    • 算术运算符:+-*/、%、++--
    • 关系运算符:==!= <<=>>=
    • 逻辑运算符:&&||、!
    • 位运算符:&、|^

    • 赋值运算符:+=-=*=/=(%)=
    • 范围运算符:..

    范围

    Groovy支持java的范围方式,同时有自己的范围运算度”..”

    • 1..10 - 包含范围的示例
    • 1 ..<10 - 独占范围的示例
    • 'a'..'x' - 范围也可以由字符组成
    • 10..1 - 范围也可以按降序排列
    • 'x'..'a' - 范围也可以由字符组成并按降序排列。

    列表(List)

    列表是用于存储数据项集合的结构。在Groovy中,List保存了一系列对象引用。List中的对象引用占据序列中的位置,并通过整数索引来区分

    要处理列表中的数据,我们必须能够访问各个元素。 Groovy列表使用索引操作符[]索引。列表索引从零开始,这指的是第一个元素。

    • [11121314] - 整数值列表
    • ['Angular''Groovy''Java'] - 字符串列表
    • [12[34]5] - 嵌套列表
    • ['Groovy'212.11] - 异构的对象引用列表
    • [] - 一个空列表

    数组

    Groovy定义数组的方式和定义list的方式一样,只不过声明时需要制定类型,或者通过as来强制制定类型为Array

    Groovy不支持Java数组的初始化方式。

    1. String[] arrStr = ['Ananas', 'Banana', 'Kiwi'
    2.  
    3. def numArr = [1, 2, 3] as int[]   
    4.  
    5. //多维数组
    6. def matrix3 = new Integer[3][3]        

    映射(Map)

    映射(也称为关联数组,字典,表和散列)是对象引用的无序集合。Map集合中的元素由键值访问。 Map中使用的键可以是任何类。当我们插入到Map集合中时,需要两个值:键和值。

    Map中通过[key].key的方式来获取key对应的value。如果key不存在,则返回null

    • ['TopicName''Lists''TopicName''Maps'] - 具有TopicName作为键的键值对的集合及其相应的值。
    • [] - 空映射。

    闭包

    闭包是一个短的匿名代码块。它通常跨越几行代码。一个方法甚至可以将代码块作为参数。它们是匿名的。

             def clos = {println "Hello World"};

        clos.call(); 

    正则表达式

    Groovy使用~”pattern” 来支持正则表达式,它将使用给定的模式字符串创建一个编译好的Java Pattern 对象。Groovy也支持 =~(创建一个Matcher)和 ==~ (返回boolean,是否给定的字符串匹配这个pattern)操作符

    对于groups的匹配, matcher[index] 是一个匹配到的group字符串的List或者string

                                                                   正则表达式的辅助符号

                                                                  正则表达式的元字符

    XML及HTML支持

    Groovy 引入了一些全新的、更加合理的方法来创建和处理 XMLHTML。代码更加简洁,更具表达性。

    1. XML标记构建器  Groovy支持基于树的标记生成器BuilderSupport,它可以被子类化以生成各种树结构对象表示
    2. XML解析器 - Groovy XmlParser类使用一个简单的模型来将XML文档解析为Node实例的树。

    JSON

    1. JsonSlurper   JsonSlurper是一个将JSON文本或阅读器内容解析为Groovy数据的类结构,例如map,列表和原始类型,如整数,双精度,布尔和字符串。
    1. JsonOutput   此方法负责将Groovy对象序列化为JSON字符串

    数据库

    Groovygroovy-sql模块提供了比当前JavaJDBC技术更高级的抽象。Groovy sql API支持各种各样的数据库,其中一些如下所示。

    • HSQLDB
    • Oracle
    • SQL Server
    • MySQL
    • MongoDB
    展开全文
  • Groovy简介与使用

    万次阅读 2018-11-04 16:59:55
    Groovy语法特性(相比于Java) Groovy与Java项目集成使用 GroovyShell GroovyClassLoader GroovyScriptEngine JSR-223 Groovy实现相关原理 Groovy代码文件与class文件的对应关系 对于没有任何类定义 对于仅有一个...
    
    
    
    

    本文首发于简书 https://www.jianshu.com/p/2c6b95097b2c

    简介

    Groovy是构建在JVM上的一个轻量级却强大的动态语言, 它结合了Python、Ruby和Smalltalk的许多强大的特性.

    Groovy就是用Java写的 , Groovy语法与Java语法类似, Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码, 相对于Java, 它在编写代码的灵活性上有非常明显的提升,Groovy 可以使用其他 Java 语言编写的库.

    使用

    下载SDK

    • Groovy Console
    • 安装IDEA groovy插件

    应用

    ElasticSearch, Jenkins 都支持执行Groovy脚本
    项目构建工具Gradle就是Groovy实现的


    Groovy语法特性(相比于Java)

    1. 不需要分号

    2. return关键字可省略, 方法的最后一句表达式可作为返回值返回 (视具体情况使用, 避免降低可读性)

    3. 类的默认作用域是public, 不需要getter/setter方法

    4. def关键字定义的变量类型都是Object, 任何变量, 方法都能用def定义/声明 , 在 Groovy 中 “一切都是对象 "

    5. 导航操作符 ( ?. )可帮助实现对象引用不为空时方法才会被调用

      // java
      if (object != null) {
          object.getFieldA();
      }
      // groovy
      object?.getFieldA()
      
    6. 命令链, Groovy 可以使你省略顶级语句方法调用中参数外面的括号。“命令链”功能则将这种特性继续扩展,它可以将不需要括号的方法调用串接成链,既不需要参数周围的括号,链接的调用之间也不需要点号

      def methodA(String name) {
          println("A: " + name)
          return this
      }
      def methodB(String name) {
          println("B: " + name)
          return this
      }
      def methodC() {
          println("C")
          return this
      }
      def methodD(String name) {
          println("D: " + name)
          return this
      }
      
      methodA("xiaoming")
      methodB("zhangsan")
      methodC()
      methodD("lisi")
      
      // 不带参数的链中需要用括号 
      methodA "xiaoming" methodB "zhangsan" methodC() methodD "lisi"
      
    7. 闭包. 闭包是一个短的匿名代码块。每个闭包会被编译成继承groovy.lang.Closure类的类,这个类有一个叫call方法,通过该方法可以传递参数并调用这个闭包.

      def hello = {println "Hello World"}
      hello.call()
      
      // 包含形式参数
      def hi = {
          person1, person2 -> println "hi " + person1 + ", "+ person2
      }
      hi.call("xiaoming", "xiaoli")
      
      // 隐式单个参数, 'it'是Groovy中的关键字
      def hh = {
          println("haha, " + it)
      }
      hh.call("zhangsan")
      
    8. with语法, (闭包实现)

      // Java
      public class JavaDeamo {
          public static void main(String[] args) {
              Calendar calendar = Calendar.getInstance();
              calendar.set(Calendar.MONTH, Calendar.DECEMBER);
              calendar.set(Calendar.DATE, 4);
              calendar.set(Calendar.YEAR, 2018);
              Date time = calendar.getTime();
              System.out.println(time);
          }
      }
      // Groovy
      Calendar calendar = Calendar.getInstance()
      calendar.with {
          // it 指 calendar 这个引用
          it.set(Calendar.MONTH, Calendar.DECEMBER)
          // 可以省略it, 使用命令链
          set Calendar.DATE, 4
          set Calendar.YEAR, 2018
          // calendar.getTime()
          println(getTime())
          // 省略get, 对于get开头的方法名并且
          println(time)
      }
      
    9. 数据结构的原生语法, 写法更便捷

      def list = [11, 12, 13, 14] // 列表, 默认是ArrayList
      def list = ['Angular', 'Groovy', 'Java'] as List // 字符串列表
      // 同list.add(8)
      list << 8
      
      [1, 2, [3, 4], 5] // 嵌套列表
      ['Groovy', 21, 2.11] // 异构的对象引用列表
      [] // 一个空列表
      
      def set = ["22", "11", "22"] as Set // LinkedHashSet, as运算符转换类型
      
      def map = ['TopicName': 'Lists', 'TopicName': 'Maps'] // map, LinkedHashMap
      [:] // 空map
      
      // 循环
      map.each {
          print it.key
      }
      
    10. Groovy Truth

    所有类型都能转成布尔值,比如null, void 对象, 等同于 0 或空的值,都会解析为false,其他则相当于true

    1. groovy支持DSL(Domain Specific Languages领域特定语言), DSL旨在简化以Groovy编写的代码,使得它对于普通用户变得容易理解

      借助命令链编写DSL

      // groovy代码
      show = { println it }
      square_root = { Math.sqrt(it) }
      
      def please(action) {
        [the: { what ->
          [of: { n -> action(what(n)) }]
        }]
      }
      
      // DSL 语言: please show the square_root of 100  (请显示100的平方根)
      
      // 调用, 等同于:please(show).the(square_root).of(100)
      please show the square_root of 100
      // ==> 10.0
      
    2. Java 的 == 实际相当于 Groovy 的 is() 方法,而 Groovy 的 == 则是一个更巧妙的 equals()。 在Groovy中要想比较对象的引用,不能用 ==,而应该用 a.is(b)


    Groovy与Java项目集成使用

    项目中引入groovy依赖

                <dependency>
                    <groupId>org.codehaus.groovy</groupId>
                    <artifactId>groovy-all</artifactId>
                    <version>x.y.z</version>
                </dependency>
    

    常见的集成机制:

    GroovyShell

    GroovyClassLoader

    GroovyScriptEngine

    JSR 223 javax.script API

    GroovyShell

    GroovyShell允许在Java类中(甚至Groovy类)求任意Groovy表达式的值。您可使用Binding对象输入参数给表达式,并最终通过GroovyShell返回Groovy表达式的计算结果

    解析为脚本(groovy.lang.Script)运行

            GroovyShell groovyShell = new GroovyShell();
            groovyShell.evaluate("println \"hello world\"");
    

    GroovyClassLoader

    用 Groovy 的 GroovyClassLoader ,动态地加载一个脚本并执行它的行为。GroovyClassLoader是一个定制的类装载器,负责解释加载Java类中用到的Groovy类。

    GroovyClassLoader loader = new GroovyClassLoader();
    Class groovyClass = loader.parseClass(new File(groovyFileName)); // 也可以解析字符串
    GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
    groovyObject.invokeMethod("run", "helloworld");
    

    GroovyScriptEngine

    groovy.util.GroovyScriptEngine 类为 GroovyClassLoader 其上再增添一个能够处理脚本依赖及重新加载的功能层, GroovyScriptEngine可以从指定的位置(文件系统,URL,数据库,等等)加载Groovy脚本

    你可以使用一个CLASSPATH集合(url或者路径名称)初始化GroovyScriptEngine,之后便可以让它根据要求去执行这些路径中的Groovy脚本了.GroovyScriptEngine同样可以跟踪相互依赖的脚本,如果其中一个被依赖的脚本发生变更,则整个脚本树都会被重新编译和加载。

            GroovyScriptEngine groovyScriptEngine = new GroovyScriptEngine(file.getAbsolutePath());
            groovyScriptEngine.run("hello.groovy", new Binding())
    

    JSR-223

    JSR-223 是 Java 中标准的脚本框架调用 API。从 Java 6 开始引入进来,主要目用来提供一种常用框架,以便从 Java 中调用多种语言

    ScriptEngine groovyEngine = new ScriptEngineManager().getEngineByName("groovy");
    // 编译成类
    groovyEngine.compile(script)
    // 直接执行
    groovyEngine.eval(script)
    

    Groovy实现相关原理

    groovy负责词法、语法解析groovy文件,然后用ASM生成普通的java字节码文件,供jvm使用。

    Groovy代码文件与class文件的对应关系

    作为基于JVM的语言,Groovy可以非常容易的和Java进行互操作,但也需要编译成class文件后才能运行,所以了解Groovy代码文件和class文件的对应关系,有助于更好地理解Groovy的运行方式和结构。

    对于没有任何类定义

    如果Groovy脚本文件里只有执行代码,没有定义任何类(class),则编译器会生成一个Script的子类,类名和脚本文件的文件名一样,而脚本的代码会被包含在一个名为run的方法中,同时还会生成一个main方法,作为整个脚本的入口。

    对于仅有一个类

    如果Groovy脚本文件里仅含有一个类,而这个类的名字又和脚本文件的名字一致,这种情况下就和Java是一样的,即生成与所定义的类一致的class文件, Groovy类都会实现groovy.lang.GroovyObject接口。

    对于多个类

    如果Groovy脚本文件含有一个或多个类,groovy编译器会很乐意地为每个类生成一个对应的class文件。如果想直接执行这个脚本,则脚本里的第一个类必须有一个static的main方法。

    对于有定义类的脚本

    如果Groovy脚本文件有执行代码, 并且有定义类, 那么所定义的类会生成对应的class文件, 同时, 脚本本身也会被编译成一个Script的子类,类名和脚本文件的文件名一样


    Spring对Groovy以及动态语言的支持

    Spring 从2.0开始支持将动态语言集成到基于 Spring 的应用程序中。Spring 开箱即用地支持 Groovy、JRuby 和 BeanShell。以 Groovy、JRuby 或任何受支持的语言编写的应用程序部分可以无缝地集成到 Spring 应用程序中。应用程序其他部分的代码不需要知道或关心单个 Spring bean 的实现语言。

    动态语言支持将 Spring 从一个以 Java 为中心的应用程序框架改变成一个以 JVM 为中心的应用程序框架

    Spring 通过 ScriptFactory 和 ScriptSource 接口支持动态语言集成。ScriptFactory 接口定义用于创建和配置脚本 Spring bean 的机制。理论上,所有在 JVM 上运行语言都受支持,因此可以选择特定的语言来创建自己的实现。ScriptSource 定义 Spring 如何访问实际的脚本源代码;例如,通过文件系统, URL, 数据库。

    在使用基于 Groovy 的 bean 时,则有几种选择:

    • 将 Groovy 类编译成普通的 Java 类文件

    • 在一个 .groovy 文件中定义 Groovy 类或脚本

    • 在 Spring 配置文件中以内联方式编写 Groovy 脚本

    1. 配置编译的 Groovy 类, 和Java一样的用法, 定义groovy class, 使用<bean/>创建bean
    class Test {
        def printDate() {
            println(new Date());
        }
    }
    
        <bean id="test" class="com.qj.study.groovytest.spring.Test" />
    
    ClassPathXmlApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml");
    Test bean = (Test) context.getBean("test");
    bean.printDate();
    
    1. 配置来自 Groovy 脚本的 bean

      • <bean/>

      • <lang:groovy>

    • <bean/>示例:
     <bean id="demo" class="org.springframework.scripting.groovy.GroovyScriptFactory">
            <constructor-arg value="classpath:script/ScriptBean.groovy"/>
     </bean>
     <bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
    
    • <lang:groovy/>示例:
        <lang:groovy id="demo" script-source="classpath:script/ScriptBean.groovy">
        </lang:groovy>
        <bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
    

    实现过程:

    Groovy 语言集成通过 ScriptFactory 的 GroovyScriptFactory 实现得到支持

    当 Spring 装载应用程序上下文时,它首先创建工厂 bean(这里是GroovyScriptFactory 类型的bean)。然后,执行 ScriptFactoryPostProcessor bean中的postProcessBeforeInstantiation方法,用实际的脚本对象替换所有的工厂 bean。

    ScriptFactoryPostProcessor:

    	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    		// 只处理ScriptFactory类型的bean
    		if (!ScriptFactory.class.isAssignableFrom(beanClass)) {
    			return null;
    		}
            // ...
            // 加载并解析groovy代码, 在scriptBeanFactory中注册BeanDefinition
    		prepareScriptBeans(bd, scriptFactoryBeanName, scriptedObjectBeanName);
            // ...
        }
    
    
         // prepareScriptBeans调用createScriptedObjectBeanDefinition
    	protected BeanDefinition createScriptedObjectBeanDefinition(BeanDefinition bd, String scriptFactoryBeanName,
    			ScriptSource scriptSource, @Nullable Class<?>[] interfaces) {
    
    		GenericBeanDefinition objectBd = new GenericBeanDefinition(bd);
    		objectBd.setFactoryBeanName(scriptFactoryBeanName);
            // 指定工厂方法, ScriptFactory.getScriptedObject, 创建脚本的Java对象 
    		objectBd.setFactoryMethodName("getScriptedObject");
    		objectBd.getConstructorArgumentValues().clear();
    		objectBd.getConstructorArgumentValues().addIndexedArgumentValue(0, scriptSource);
    		objectBd.getConstructorArgumentValues().addIndexedArgumentValue(1, interfaces);
    		return objectBd;
    	}
    

    创建bean的时候, SimpleInstantiationStrategy.instantiate

                     // 调用工厂方法创建beanInstance
    				Object result = factoryMethod.invoke(factoryBean, args);
    				if (result == null) {
    					result = new NullBean();
    				}
    
    

    GroovyScriptFactory.getScriptedObject

                          // 通过groovyClassLoader 加载并解析类
    					this.scriptClass = getGroovyClassLoader().parseClass(							scriptSource.getScriptAsString(), scriptSource.suggestedClassName());
    
    					if (Script.class.isAssignableFrom(this.scriptClass)) {
                              // 如果是groovy 脚本, 那么运行脚本, 将结果的类作为Bean的类型
    						Object result = executeScript(scriptSource, this.scriptClass);
    						this.scriptResultClass = (result != null ? result.getClass() : null);
    						return result;
    					}
    					else {
                              // 不是脚本, 直接返回类
    						this.scriptResultClass = this.scriptClass;
    					}
    
    	protected Object executeScript(ScriptSource scriptSource, Class<?> scriptClass) throws ScriptCompilationException {
    		try {
    			GroovyObject goo = (GroovyObject) ReflectionUtils.accessibleConstructor(scriptClass).newInstance();
    
                // GroovyObjectCustomizer 是一个回调,Spring 在创建一个 Groovy bean 之后会调用它。可以对一个 Groovy bean 应用附加的逻辑,或者执行元编程
    			if (this.groovyObjectCustomizer != null) {
    				this.groovyObjectCustomizer.customize(goo);
    			}
    
    			if (goo instanceof Script) {
    				// A Groovy script, probably creating an instance: let's execute it.
    				return ((Script) goo).run();
    			}
    			else {
    				// An instance of the scripted class: let's return it as-is.
    				return goo;
    			}
    		}
    		catch (NoSuchMethodException ex) {
                // ...
    	}
    

    最终在ScriptFactoryPostProcessor中, scriptBeanFactory保存了所有通过脚本创建的bean, scriptSourceCache缓存了所有的脚本信息

    	final DefaultListableBeanFactory scriptBeanFactory = new DefaultListableBeanFactory();
    
    	/** Map from bean name String to ScriptSource object */
    	private final Map<String, ScriptSource> scriptSourceCache = new HashMap<String, ScriptSource>();
    
    • refresh参数
    <lang:groovy id="refresh"  refresh-check-delay="1000"
                     script-source="classpath:script/RefreshBean.groovy">
        </lang:groovy>
    

    创建的是JdkDynamicAopProxy代理对象, 在每一次调用这个代理对象的方法的时候, 都回去校验被代理对象是否需要刷新, 通过比对脚本文件的最后更新时间和设定的更新时间间隔, 如果需要刷新则重新加载这个groovy文件, 并编译, 然后创建一个新的bean并注册进行替换

    3.内联方式配置

    inline script标签, 从配置中读取源代码

       <lang:groovy id="inline">
            <lang:inline-script> 
                <![CDATA[
                class InlineClass {
                    // xxxxx ...
                }
                ]]>
            </lang:inline-script>
        </lang:groovy>
    

    综上, 扩展一下, 脱离xml配置, 可以从数据库中定时加载groovy代码, 构建/更新/删除BeanDefinition


    Groovy运行沙盒

    沙盒原理也叫沙箱,英文sandbox。在计算机领域指一种虚拟技术,且多用于计算机安全技术。安全软件可以先让它在沙盒中运行,如果含有恶意行为,则禁止程序的进一步运行,而这不会对系统造成任何危害。

    举个例子:

    docker容器可以理解为在沙盒中运行的进程。这个沙盒包含了该进程运行所必须的资源。不同的容器之间相互隔离。CGroup实现资源控制, Namespace实现访问隔离, rootfs实现文件系统隔离。


    对于嵌入Groovy的Java系统, 如果暴露接口, 可能存在的隐患有

    • 通过Java的Runtime.getRuntime().exec()方法执行shell, 操作服务器…

    • 执行System.exit(0)

    • dump 内存中的Class, 修改内存中的缓存数据

    ElasticSearch Groovy 脚本 远程代码执行漏洞


    Groovy提供了编译自定义器(Compilation customizers), 无论你使用 groovyc 还是采用 GroovyShell 来编译类,要想执行脚本,实际上都会使用到编译器配置compiler configuration)信息。这种配置信息保存了源编码或类路径这样的信息,而且还用于执行更多的操作,比如默认添加导入,显式使用 AST(语法树) 转换,或者禁止全局 AST 转换, 编译自定义器的目标在于使这些常见任务易于实现。CompilerConfiguration 类就是切入点。


    groovy sandbox的实现 -> https://github.com/jenkinsci/groovy-sandbox

    实现过程:

    groovy-sandbox实现了一个SandboxTransformer, 扩展自CompilationCustomizer, 在Groovy代码编译时进行转换. 脚本转换后, 让脚本执行的每一步都会被拦截, 调用Checker进行检查

    可拦截所有内容,包括

    • 方法调用(实例方法和静态方法)
    • 对象分配(即除了“this(…)”和“super(…)”之外的构造函数调用
    • 属性访问(例如,z = foo.bar,z = foo。“bar”)和赋值(例如,foo.bar = z,foo。“bar”= z)
    • 数组访问和赋值

    当然, 执行性能也会受到一些的影响

    示例: Jenkins Pipline支持在Groovy沙盒中执行Groovy脚本
    image.png


    其他:

    Groovy元编程 原文 译文

    Groovy的ClassLoader体系

    展开全文
  • Groovy脚本基础全攻略

    万次阅读 多人点赞 2017-10-13 14:13:07
    点我开始Android技术交流】1 背景Groovy脚本基于Java且拓展了Java,所以从某种程度来说掌握Java是学习Groovy的前提,故本文适用于不熟悉Groovy却想快速得到Groovy核心基础干货的Java开发者(注意是Java),因为我的...

    【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

    1 背景

    Groovy脚本基于Java且拓展了Java,所以从某种程度来说掌握Java是学习Groovy的前提,故本文适用于不熟悉Groovy却想快速得到Groovy核心基础干货的Java开发者(注意是Java),因为我的目的不是深入学习Groovy语言,所以本文基本都是靠代码来解释,这样最直观,同时也够干货基础入门Groovy的特点和结构。

    这里写图片描述

    开始介绍前先给一个大法,《官方权威指南》英文好的可以直接略过本文后续内容,我需要的只是Groovy皮毛;再次向Groovy的标志致敬,左手一个Java,右手一个Groovy,不好意思,我技术水平太Low了(T–T__《琅琊榜》看多了!!!)。

    这里写图片描述

    Groovy是一种动态语言,它和Java类似(算是Java的升级版,但是又具备脚本语言的特点),都在Java虚拟机中运行。当运行Groovy脚本时它会先被编译成Java类字节码,然后通过JVM虚拟机执行这个Java字节码类。

    快速安装指南:

    安装Groovy在各种Bash下都是通用的,具体如下命令就可搞定:

    $ curl -s get.sdkman.io | bash
    $ source "$HOME/.sdkman/bin/sdkman-init.sh"
    $ sdk install groovy
    $ groovy -version
    //至此就可以享用了!

    我们在写Groovy代码时可以直接使用自己喜欢的文本编辑器编辑OK以后以.groovy后缀保存,然后在终端执行如下命令即可运行:

    $ groovy ./TestFile.groovy

    或者我们可以通过groovyConsole来进行groovy代码开发运行(由于不需要特别深入学习使用Groovy,所以个人非常喜欢这种模式的开发运行),如下图:

    这里写图片描述

    再或者我们还可以使用Intellij IDEA等工具安装groovy插件进行groovy开发,这里不再一一叙述了(配置环境点我),直接给出一个读取指定文件内容打印的例子,如下:

    这里写图片描述

    OK,有了上面这些简单粗暴的基础和环境之后那我们快速开战吧。

    【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

    2 语法基础

    这里开始我们就来快速简单粗暴的了解一下Groovy语法,其实和Java类似,但也有些区别,下面我们一步一步来看吧,切记对比学习,这才是秘笈。

    2-1 注释

    Groovy的单行注释、多行注释、文档注释基本都和Java一样,没啥特殊的,不再细说。只有一种特殊的单行注释需要留意一下即可。如下:

    #!/usr/bin/env groovy
    println "Hello from the shebang line"

    这种注释通常是用来给UNIX系统声明允许脚本运行的类型的,一般都是固定写法,没啥讲究的。

    2-2 关键字

    Groovy有如下一些关键字,我们些代码命名时要注意:

    as、assert、break、case、catch、class、const、continue、def、default、do、else、enum、extends、false、finally、for、goto、if、implements、import、in、instanceof、interface、new、null、package、return、super、switch、this、throw、throws、trait、true、try、while

    这玩意和其他语言一样,没啥特殊的,自行脑补。

    2-3 标识符

    对于Groovy的标示符和Java还是有些共同点和区别的,特别是引用标示符的区别,具体可以往下看。

    2-3-1 普通标识符

    普通标识符定义和C语言类似,只能以字母、美元符、下划线开始,不能以数字开头。如下例子:

    //正确
    def name
    def $name
    def name_type
    def foo.assert
    //错误
    def 5type
    def a+b

    2-3-2 引用标识符

    引用标识符出现在点后的表达式中,我们可以如下一样使用:

    def map = [:]
    //引用标示符中出现空格也是对的
    map."an identifier with a space and double quotes" = "ALLOWED"
    //引用标示符中出现横线也是对的
    map.'with-dash-signs-and-single-quotes' = "ALLOWED"
    
    assert map."an identifier with a space and double quotes" == "ALLOWED"
    assert map.'with-dash-signs-and-single-quotes' == "ALLOWED"

    当然了,Groovy的所有字符串都可以当作引用标示符定义,如下:

    //如下类型字符串作为引用标识符都是对的
    map.'single quote'
    map."double quote"
    map.'''triple single quote'''
    map."""triple double quote"""
    map./slashy string/
    map.$/dollar slashy string/$
    
    //稍微特殊的GString,也是对的
    def firstname = "Homer"
    map."Simson-${firstname}" = "Homer Simson"
    
    assert map.'Simson-Homer' == "Homer Simson"

    2-4 字符及字符串

    Groovy有java.lang.String和groovy.lang.GString两中字符串对象类型,具体如下细说。

    2-4-1 单引号字符串

    单引号字符串是java.lang.String类型的,不支持站位符插值操作,譬如:

    def name = 'Test Groovy!'
    def body = 'Test $name'
    
    assert name == 'Test Groovy!'
    assert body == 'Test $name'		//不会替换$name站位符

    Groovy的字符串可以通过”+“直接拼接,譬如:

    assert 'ab' == 'a' + 'b'

    其中涉及转义字符规则同Java,只用特殊注意”’“的转义即可。

    2-4-2 三重单引号字符串

    三重单引号字符串是java.lang.String类型的,不支持站位符插值操作,可以标示多行字符串,譬如:

    def aMultilineString = '''line one
    line two
    line three'''

    三重单引号字符串允许字符串的内容在多行出现,新的行被转换为“\n”,其他所有的空白字符都被完整的按照文本原样保留;字符开头添加“/”表示字符内容不转义反斜杠“\”,只有在反斜杠接下来是一个字符u的时候才需要进行转义,因为\u表示一个unicode转义。如下:

    def strippedFirstNewline = '''\
    line one
    line two
    line three
    '''
    
    assert !strippedFirstNewline.startsWith('\n')

    2-4-3 双引号字符串

    双引号字符串支持站位插值操作,如果双引号字符串中不包含站位符则是java.lang.String类型的,如果双引号字符串中包含站位符则是groovy.lang.GString类型的。

    对于插值占位符我们可以用${}或者$来标示,${}用于一般替代字串或者表达式,$主要用于A.B的形式中,具体如下例子:

    def name = 'Guillaume' // a plain string
    def greeting = "Hello ${name}"
    assert greeting.toString() == 'Hello Guillaume'
    
    def sum = "The sum of 2 and 3 equals ${2 + 3}"
    assert sum.toString() == 'The sum of 2 and 3 equals 5'
    
    def person = [name: 'Guillaume', age: 36]
    assert "$person.name is $person.age years old" == 'Guillaume is 36 years old'

    特别注意,$只对A.B等有效,如果表达式包含括号(像方法调用)、大括号、闭包等符号则是无效的。譬如:

    def number = 3.14
    shouldFail(MissingPropertyException) {
        println "$number.toString()"
    }
    
    //该代码运行抛出groovy.lang.MissingPropertyException异常,因为Groovy认为去寻找number的名为toString的属性,所以异常

    注意,在表达式中访问属性前必须保证属性已经定义好(值为空也可以),如果使用了未定义的属性会抛出groovy.lang.MissingPropertyException异常。 GString还支持延迟运算,譬如在GString中使用闭包,闭包在调用GString的toString()方法时被延迟执行;闭包中可以有0或1个参数,若指定一个参数,则参数会被传入一个Writer对象,我们可以利用这个Writer对象来写入字符,若没有参数,闭包返回值的toString()方法被调用。譬如:

    //无参数闭包
    def sParameterLessClosure = "1 + 2 == ${-> 3}" 
    assert sParameterLessClosure == '1 + 2 == 3'
    //一个参数闭包
    def sOneParamClosure = "1 + 2 == ${ w -> w << 3}" 
    assert sOneParamClosure == '1 + 2 == 3'

    上面了解了GString的推迟运算特性,下面我们再来看一个牛逼的特性,如下:

    def number = 1 
    def eagerGString = "value == ${number}"
    def lazyGString = "value == ${ -> number }"
    
    assert eagerGString == "value == 1" 
    assert lazyGString ==  "value == 1" 
    
    number = 2 
    assert eagerGString == "value == 1" 
    assert lazyGString ==  "value == 2" 

    可以看见,eagerGString是普通的双引号插值站位替换,lazyGString是双引号闭包插值替换,我们可以发现在number变为2以后他们的运算结果就有了差异。可以明显推理到结论,一个普通插值表达式值替换实际是在GString创建的时刻,一个包含闭包的表达式由于延迟运算调运toString()方法,所以会产生一个新的字符串值。

    当然了,GString和String即使字符串一样他们的HashCode也不会一样,譬如:

    assert "one: ${1}".hashCode() != "one: 1".hashCode()

    由于相同字符串的String与GString的HashCode不同,所以我们一定要避免使用GString作为MAP的key,譬如:

    def key = "a"
    def m = ["${key}": "letter ${key}"]     
    
    assert m["a"] == null   //由于key的HashCode不同,所以取不到

    其中涉及转义字符规则同Java,只用特殊注意””“的转义即可。

    2-4-4 多重双引号字符串

    多重双引号字符串也支持站位插值操作,我们要特别注意在多重双引号字符串中的单引号和双引号转换问题。譬如:

    def name = 'Groovy'
    def template = """
        Dear Mr ${name},
    
        You're the winner of the lottery!
    
        Yours sincerly,
    
        Dave
    """
    
    assert template.toString().contains('Groovy')

    2-4-5 斜线字符串

    斜线字符串其实和双引号字符串很类似,通常用在正则表达式中,下面我们看几个例子,如下:

    //普通使用
    def fooPattern = /.*foo.*/
    assert fooPattern == '.*foo.*'
    //含转义字符使用
    def escapeSlash = /The character \/ is a forward slash/
    assert escapeSlash == 'The character / is a forward slash'
    //多行支持
    def multilineSlashy = /one
        two
        three/
    
    assert multilineSlashy.contains('\n')
    //含站位符使用支持
    def color = 'blue'
    def interpolatedSlashy = /a ${color} car/
    
    assert interpolatedSlashy == 'a blue car'

    特别注意,一个空的斜线字符串会被Groovy解析器解析为一注释。

    2-4-6 字符Characters

    不像Java,Groovy没有明确的Characters。但是我们可以有如下三种不同的方式来将字符串作为字符处理,譬如:

    char c1 = 'A' 
    assert c1 instanceof Character
    
    def c2 = 'B' as char 
    assert c2 instanceof Character
    
    def c3 = (char)'C' 
    assert c3 instanceof Character

    2-5 数字Numbers

    Groovy支持各种类型的整型和数值类型,通常支持Java支持的那些,下面我们仔细来说说。

    2-5-1 整型

    Groovy像Java一样支持如下一些整型,byte、char、short、int、long、java.lang.BigInteger。我们在使用中可以像下面例子一样:

    // primitive types
    byte  b = 1
    char  c = 2
    short s = 3
    int   i = 4
    long  l = 5
    
    // infinite precision
    BigInteger bi =  6
    
    
    int xInt = 077
    assert xInt == 63
    
    int xInt = 0x77
    assert xInt == 119
    
    int xInt = 0b10101111
    assert xInt == 175

    2-5-2 浮点型

    Groovy像Java一样支持如下一些浮点型,float、double、java.lang.BigDecimal。我们在使用中可以像下面例子一样:

    // primitive types
    float  f = 1.234
    double d = 2.345
    
    // infinite precision
    BigDecimal bd =  3.456
    
    
    assert 1e3  ==  1_000.0
    assert 2E4  == 20_000.0
    assert 3e+1 ==     30.0
    assert 4E-2 ==      0.04

    2-6 Booleans类型

    Boolean类型没啥解释的,和其他语言一样,就两个值,如下:

    def myBooleanVariable = true
    boolean untypedBooleanVar = false
    booleanField = true

    比较简单,没啥特例,自行脑补。

    2-7 Lists类型

    Groovy同样支持java.util.List类型,在Groovy中同样允许向列表中增加或者删除对象,允许在运行时改变列表的大小,保存在列表中的对象不受类型的限制;此外还可以通过超出列表范围的数来索引列表。如下例子:

    //使用动态List
    def numbers = [1, 2, 3]         
    assert numbers instanceof List  
    assert numbers.size() == 3
    
    //List中存储任意类型
    def heterogeneous = [1, "a", true]
    
    //判断List默认类型
    def arrayList = [1, 2, 3]
    assert arrayList instanceof java.util.ArrayList
    
    //使用as强转类型
    def linkedList = [2, 3, 4] as LinkedList    
    assert linkedList instanceof java.util.LinkedList
    
    //定义指定类型List
    LinkedList otherLinked = [3, 4, 5]          
    assert otherLinked instanceof java.util.LinkedList
    
    //定义List使用
    def letters = ['a', 'b', 'c', 'd']
    //判断item值
    assert letters[0] == 'a'     
    assert letters[1] == 'b'
    //负数下标则从右向左index
    assert letters[-1] == 'd'    
    assert letters[-2] == 'c'
    //指定item赋值判断
    letters[2] = 'C'             
    assert letters[2] == 'C'
    //给List追加item
    letters << 'e'               
    assert letters[ 4] == 'e'
    assert letters[-1] == 'e'
    //获取一段List子集
    assert letters[1, 3] == ['b', 'd']         
    assert letters[2..4] == ['C', 'd', 'e'] 
    
    //多维List支持
    def multi = [[0, 1], [2, 3]]     
    assert multi[1][0] == 2 

    2-8 Arrays类型

    Groovy中数组和Java类似,具体如下:

    //定义初始化String数组
    String[] arrStr = ['Ananas', 'Banana', 'Kiwi']  
    assert arrStr instanceof String[]    
    assert !(arrStr instanceof List)
    
    //使用def定义初始化int数组
    def numArr = [1, 2, 3] as int[]      
    assert numArr instanceof int[]       
    assert numArr.size() == 3
    
    //声明定义多维数组指明宽度
    def matrix3 = new Integer[3][3]         
    assert matrix3.size() == 3
    
    //声明多维数组不指定宽度
    Integer[][] matrix2                     
    matrix2 = [[1, 2], [3, 4]]
    assert matrix2 instanceof Integer[][]
    
    //数组的元素使用及赋值操作
    String[] names = ['Cédric', 'Guillaume', 'Jochen', 'Paul']
    assert names[0] == 'Cédric'     
    names[2] = 'Blackdrag'          
    assert names[2] == 'Blackdrag'

    2-9 Maps类型

    Map是“键-值”对的集合,在Groovy中键key不一定是String,可以是任何对象(实际上Groovy中的Map就是java.util.Linke dHashMap)。如下:

    //定义一个Map
    def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']   
    //获取一些指定key的value进行判断操作
    assert colors['red'] == '#FF0000'    
    assert colors.green  == '#00FF00'
    //给指定key的对赋值value操作与判断    
    colors['pink'] = '#FF00FF'           
    colors.yellow  = '#FFFF00'           
    assert colors.pink == '#FF00FF'
    assert colors['yellow'] == '#FFFF00'
    //判断Map的类型
    assert colors instanceof java.util.LinkedHashMap
    //访问Map中不存在的key为null
    assert colors.unknown == null
    
    //定义key类型为数字的Map
    def numbers = [1: 'one', 2: 'two']
    assert numbers[1] == 'one'

    对于Map需要特别注意一种情况,如下:

    //把一个定义的变量作为Map的key,访问Map的该key是失败的
    def key = 'name'
    def person = [key: 'Guillaume']      
    assert !person.containsKey('name')   
    assert person.containsKey('key') 
    
    //把一个定义的变量作为Map的key的正确写法---添加括弧,访问Map的该key是成功的
    person = [(key): 'Guillaume']        
    assert person.containsKey('name')    
    assert !person.containsKey('key') 

    【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

    3 运算符

    关于Groovy的运算符介绍类似于上面一样,我们重点突出与Java的不同点,相同点自行脑补。

    Groovy支持**次方运算符,如下:

    assert  2 ** 3 == 8
    
    def f = 3
    f **= 2
    assert f == 9

    Groovy非运算符如下:

    assert (!true)    == false                      
    assert (!'foo')   == false                      
    assert (!'')      == true 

    Groovy支持?.安全占位符,这个运算符主要用于避免空指针异常,譬如:

    def person = Person.find { it.id == 123 }    
    def name = person?.name                      
    assert name == null  

    Groovy支持.@直接域访问操作符,因为Groovy自动支持属性getter方法,但有时候我们有一个自己写的特殊getter方法,当不想调用这个特殊的getter方法则可以用直接域访问操作符。如下:

    class User {
        public final String name                 
        User(String name) { this.name = name}
        String getName() { "Name: $name" }       
    }
    def user = new User('Bob')
    
    assert user.name == 'Name: Bob'
    assert user.@name == 'Bob'  

    Groovy支持.&方法指针操作符,因为闭包可以被作为一个方法的参数,如果想让一个方法作为另一个方法的参数则可以将一个方法当成一个闭包作为另一个方法的参数。如下:

        def list = ['a','b','c']  
        //常规写法 
        list.each{  
            println it  
        }  
    
        String printName(name){  
            println name  
        }  
    
        //方法指针操作符写法
        list.each(this.&printName)  

    Groovy支持将?:三目运算符简化为二目,如下:

    displayName = user.name ? user.name : 'Anonymous'   
    displayName = user.name ?: 'Anonymous' 

    Groovy支持*.展开运算符,一个集合使用展开运算符可以得到一个元素为原集合各个元素执行后面指定方法所得值的集合,如下:

    cars = [
       new Car(make: 'Peugeot', model: '508'),
       null,                                              
       new Car(make: 'Renault', model: 'Clio')]
    assert cars*.make == ['Peugeot', null, 'Renault']     
    assert null*.make == null 

    关于Groovy的其他运算符就不多说,类比Java吧。

    【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

    4 程序结构

    这里主要讨论Groovy的代码组成结构,具体如下细则。

    4-1 包名

    包名的定义和作用及含义完全和Java一样,不再介绍,如下:

    // defining a package named com.yoursite
    package com.yoursite

    4-2 Imports引入

    常规的imports导包操作和Java一样,如下:

    //例1:
    import groovy.xml.MarkupBuilder
    
    // using the imported class to create an object
    def xml = new MarkupBuilder()
    assert xml != null
    
    //例2:
    import groovy.xml.*
    
    def markupBuilder = new MarkupBuilder()
    assert markupBuilder != null
    assert new StreamingMarkupBuilder() != null
    
    //例3:
    import static Boolean.FALSE
    
    assert !FALSE
    
    //例4:特殊的,相当于用as取别名
    import static Calendar.getInstance as now
    
    assert now().class == Calendar.getInstance().class

    不过要特别注意,Groovy与Java类似,已经帮我们默认导入了一些常用的包,所以在我们使用这些包的类时就不用再像上面那样导入了,如下是自动导入的包列表:

    import java.lang.*
    import java.util.*
    import java.io.*
    import java.net.*
    import groovy.lang.*
    import groovy.util.*
    import java.math.BigInteger
    import java.math.BigDecimal

    4-3 脚本与类(脚本的实质)

    相对于传统的Java类,一个包含main方法的Groovy类可以如下书写:

    class Main {                                    
        static void main(String... args) {          
            println 'Groovy world!'                 
        }
    }

    和Java一样,程序会从这个类的main方法开始执行,这是Groovy代码的一种写法,实际上执行Groovy代码完全可以不需要类或main方法,所以更简单的写法如下:

    println 'Groovy world!'

    上面这两中写法其实是一样的,具体我们可以通过如下命令进行编译为class文件:

    groovyc demo.groovy //编译Groovy源码为class

    我们使用反编译工具可以查看到这个demo.groovy类源码如下:

    import org.codehaus.groovy.runtime.InvokerHelper
    class Main extends Script {                     
        def run() {                                 
            println 'Groovy world!'                 
        }
        static void main(String[] args) {           
            InvokerHelper.runScript(Main, args)     
        }
    }

    可以看见,上面我们写的groovy文件编译后的class其实是Java类,该类从Script类派生而来(查阅API);可以发现,每个脚本都会生成一个static main方法,我们执行groovy脚本的实质其实是执行的这个Java类的main方法,脚本源码里所有代码都被放到了run方法中,脚本中定义的方法(该例暂无)都会被定义在Main类中。

    通过上面可以发现,Groovy的实质就是Java的class,也就是说他一定会和Java一样存在变量作用域!对哦,前面我们解释变量时竟然没说到这个东东,这里说下吧。看下面例子:

    //单个Groovy源码文件,运行会报错找不到num变量
    def num = 1 
    def printNum(){  
        println num  
    }
    
    //单个Groovy源码文件,运行会报错找不到num变量
    int num = 1 
    def printNum(){  
        println num  
    }  
    
    //单个Groovy源码文件,运行OK成功
    num = 1 
    def printNum(){  
        println num  
    }  

    上面的例子可以发现,我们如果想要在Groovy的方法中使用Groovy的变量则不能有修饰符。然而,如果我们想在B.groovy文件访问A.groovy文件的num变量咋办呢,我们可以使用Field注解,具体操作如下:

    import groovy.transform.Field;
    @Field num = 1

    哈哈,这就是Groovy的变量作用域了,如果你想知道上面这些写法为啥出错,很简单,自己动手整成Java源码相信你一定可以看懂为啥鸟。

    【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

    5 闭包

    Groovy的闭包(closure)是一个非常重要的概念,闭包是可以用作方法参数的代码块,Groovy的闭包更象是一个代码块或者方法指针,代码在某处被定义然后在其后的调用处执行。

    5-1 语法

    定义一个闭包:

    { [closureParameters -> ] statements }
    
    //[closureparameters -> ]是可选的逗号分隔的参数列表,参数类似于方法的参数列表,这些参数可以是类型化或非类型化的。

    如下给出几个有效的闭包定义例子:

    //最基本的闭包
    { item++ }                                          
    //使用->将参数与代码分离
    { -> item++ }                                       
    //使用隐含参数it(后面有介绍)
    { println it }                                      
    //使用明确的参数it替代
    { it -> println it }                                
    //使用显示的名为参数
    { name -> println name }                            
    //接受两个参数的闭包
    { String x, int y ->                                
        println "hey ${x} the value is ${y}"
    }
    //包含一个参数多个语句的闭包
    { reader ->                                         
        def line = reader.readLine()
        line.trim()
    }

    闭包对象:

    一个闭包其实就是一个groovy.lang.Closure类型的实例,如下:

    //定义一个Closure类型的闭包
    def listener = { e -> println "Clicked on $e.source" }      
    assert listener instanceof Closure
    //定义直接指定为Closure类型的闭包
    Closure callback = { println 'Done!' }                      
    Closure<Boolean> isTextFile = {
        File it -> it.name.endsWith('.txt')                     
    }

    调运闭包:

    其实闭包和C语言的函数指针非常像,我们定义好闭包后调用的方法有如下两种形式:

    • 闭包对象.call(参数)

    • 闭包对象(参数)

    如下给出例子:

    def code = { 123 }
    assert code() == 123
    assert code.call() == 123
    
    def isOdd = { int i-> i%2 == 1 }                            
    assert isOdd(3) == true                                     
    assert isOdd.call(2) == false

    特别注意,如果闭包没定义参数则默认隐含一个名为it的参数,如下例子:

    def isEven = { it%2 == 0 }                                  
    assert isEven(3) == false                                   
    assert isEven.call(2) == true 

    5-2 参数

    普通参数:

    一个闭包的普通参数定义必须遵循如下一些原则:

    • 参数类型可选
    • 参数名字
    • 可选的参数默认值
    • 参数必须用逗号分隔

    如下是一些例子:

    def closureWithOneArg = { str -> str.toUpperCase() }
    assert closureWithOneArg('groovy') == 'GROOVY'
    
    def closureWithOneArgAndExplicitType = { String str -> str.toUpperCase() }
    assert closureWithOneArgAndExplicitType('groovy') == 'GROOVY'
    
    def closureWithTwoArgs = { a,b -> a+b }
    assert closureWithTwoArgs(1,2) == 3
    
    def closureWithTwoArgsAndExplicitTypes = { int a, int b -> a+b }
    assert closureWithTwoArgsAndExplicitTypes(1,2) == 3
    
    def closureWithTwoArgsAndOptionalTypes = { a, int b -> a+b }
    assert closureWithTwoArgsAndOptionalTypes(1,2) == 3
    
    def closureWithTwoArgAndDefaultValue = { int a, int b=2 -> a+b }
    assert closureWithTwoArgAndDefaultValue(1) == 3

    隐含参数:

    当一个闭包没有显式定义一个参数列表时,闭包总是有一个隐式的it参数。如下:

    def greeting = { "Hello, $it!" }
    assert greeting('Patrick') == 'Hello, Patrick!'

    上面的类似下面这个例子:

    def greeting = { it -> "Hello, $it!" }
    assert greeting('Patrick') == 'Hello, Patrick!'

    当然啦,如果你想声明一个不接受任何参数的闭包,且必须限定为没有参数的调用,那么你必须将它声明为一个空的参数列表,如下:

    def magicNumber = { -> 42 }
    // this call will fail because the closure doesn't accept any argument
    magicNumber(11)

    可变长参数:

    Groovy的闭包支持最后一个参数为不定长可变长度的参数,具体用法如下:

    def concat1 = { String... args -> args.join('') }           
    assert concat1('abc','def') == 'abcdef'                     
    def concat2 = { String[] args -> args.join('') }            
    assert concat2('abc', 'def') == 'abcdef'
    
    def multiConcat = { int n, String... args ->                
        args.join('')*n
    }
    assert multiConcat(2, 'abc','def') == 'abcdefabcdef'

    5-3 闭包省略调运

    很多方法的最后一个参数都是一个闭包,我们可以在这样的方法调运时进行略写括弧。比如:

    def debugClosure(int num, String str, Closure closure){  
          //dosomething  
    }  
    
    debugClosure(1, "groovy", {  
       println"hello groovy!"  
    })

    可以看见,当闭包作为闭包或方法的最后一个参数时我们可以将闭包从参数圆括号中提取出来接在最后,如果闭包是唯一的一个参数,则闭包或方法参数所在的圆括号也可以省略;对于有多个闭包参数的,只要是在参数声明最后的,均可以按上述方式省略。

    【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

    6 GDK(Groovy Development Kit)

    Groovy除了可以直接使用Java的JDK以外还有自己的一套GDK,其实也就是对JDK的一些类的二次封装罢了;一样,这是GDK官方API文档,写代码中请自行查阅。

    6-1 I/O操作

    Groovy提供了很多IO操作的方法,你可以使用Java的那写IO方法,但是没有Groovy的GDK提供的简单牛逼。

    读文件操作:

    我们先来看一个例子:

    
    //读文件打印脚本
    new File('/home/temp', 'haiku.txt').eachLine { line ->
        println line
    }
    
    //读文件打印及打印行号脚本
    new File(baseDir, 'haiku.txt').eachLine { line, nb ->
        println "Line $nb: $line"
    }

    可以看见,这是一个读文件打印每行的脚本,eachLine方法是GDK中File的方法,eachLine的参数是一个闭包,这里采用了简写省略括弧。

    当然了,有时候你可能更加喜欢用Reader来操作,使用Reader时即使抛出异常也会自动关闭IO。如下:

    def count = 0, MAXSIZE = 3
    new File(baseDir,"haiku.txt").withReader { reader ->
        while (reader.readLine()) {
            if (++count > MAXSIZE) {
                throw new RuntimeException('Haiku should only have 3 verses')
            }
        }
    }

    接着我们再看几个关于读文件的操作使用,如下:

    //把读到的文件行内容全部存入List列表中
    def list = new File(baseDir, 'haiku.txt').collect {it}
    //把读到的文件行内容全部存入String数组列表中
    def array = new File(baseDir, 'haiku.txt') as String[]
    //把读到的文件内容全部转存为byte数组
    byte[] contents = file.bytes
    
    //把读到的文件转为InputStream,切记此方式需要手动关闭流
    def is = new File(baseDir,'haiku.txt').newInputStream()
    // do something ...
    is.close()
    
    //把读到的文件以InputStream闭包操作,此方式不需要手动关闭流
    new File(baseDir,'haiku.txt').withInputStream { stream ->
        // do something ...
    }

    上面介绍了一些常用的文件读操作,其它的具体参见API和GDK吧。

    写文件操作:

    有了上面的读操作,接下来直接看几个写操作的例子得了,如下:

    //向一个文件以utf-8编码写三行文字
    new File(baseDir,'haiku.txt').withWriter('utf-8') { writer ->
        writer.writeLine 'Into the ancient pond'
        writer.writeLine 'A frog jumps'
        writer.writeLine 'Water’s sound!'
    }
    //上面的写法可以直接替换为此写法
    new File(baseDir,'haiku.txt') << '''Into the ancient pond
    A frog jumps
    Water’s sound!'''
    //直接以byte数组形式写入文件
    file.bytes = [66,22,11]
    //类似上面读操作,可以使用OutputStream进行输出流操作,记得手动关闭
    def os = new File(baseDir,'data.bin').newOutputStream()
    // do something ...
    os.close()
    //类似上面读操作,可以使用OutputStream闭包进行输出流操作,不用手动关闭
    new File(baseDir,'data.bin').withOutputStream { stream ->
        // do something ...
    }

    上面介绍了一些常用的文件写操作,其它的具体参见API和GDK吧。

    文件树操作:

    在脚本环境中,遍历一个文件树是很常见的需求,Groovy提供了多种方法来满足这个需求。如下:

    //遍历所有指定路径下文件名打印
    dir.eachFile { file ->                      
        println file.name
    }
    //遍历所有指定路径下符合正则匹配的文件名打印
    dir.eachFileMatch(~/.*\.txt/) { file ->     
        println file.name
    }
    //深度遍历打印名字
    dir.eachFileRecurse { file ->                      
        println file.name
    }
    //深度遍历打印名字,只包含文件类型
    dir.eachFileRecurse(FileType.FILES) { file ->      
        println file.name
    }
    //允许设置特殊标记规则的遍历操作
    dir.traverse { file ->
        if (file.directory && file.name=='bin') {
            FileVisitResult.TERMINATE                   
        } else {
            println file.name
            FileVisitResult.CONTINUE                    
        }
    }

    执行外部程序:

    Groovy提供一种简单方式来处理执行外部命令行后的输出流操作。如下:

    def process = "ls -l".execute()             
    println "Found text ${process.text}"

    execute方法返回一个java.lang.Process对象,支持in、out、err的信息反馈。在看一个例子,如下:

    def process = "ls -l".execute()             
    process.in.eachLine { line ->               
        println line                            
    }

    上面使用闭包操作打印出执行命令行的输入流信息。

    6-2 有用的工具类操作

    ConfigSlurper配置:

    ConfigSlurper是一个配置管理文件读取工具类,类似于Java的*.properties文件,如下:

    def config = new ConfigSlurper().parse('''
        app.date = new Date()  
        app.age  = 42
        app {                  
            name = "Test${42}"
        }
    ''')
    
    assert config.app.date instanceof Date
    assert config.app.age == 42
    assert config.app.name == 'Test42'

    上面介绍了一些常用的属性配置操作,其它的具体参见API和GDK吧。

    Expando扩展:

    def expando = new Expando()
    expando.toString = { -> 'John' }
    expando.say = { String s -> "John says: ${s}" }
    
    assert expando as String == 'John'
    assert expando.say('Hi') == 'John says: Hi'

    上面介绍了一些常用的拓展操作,其它的具体参见API和GDK吧。

    6-2 其他操作

    还有很多其他操作,这里就不一一列举,详情参考官方文档即可,譬如JSON处理、XML解析啥玩意的,自行需求摸索吧。

    【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

    7 DSL(Domain Specific Languages)领域相关语言

    这个就不特殊说明了,只在这里提一下,因为我们前边很多地方已经用过它了,加上我们只是干货基础掌握,所以不做深入探讨。

    DSL是一种特定领域的语言(功能领域、业务领域),Groovy是通用的编程语言,所以不是DSL,但是Groovy却对编写全新的DSL提供了很好的支持,这些支持来自于Groovy自身语法的特性,如下:

    • Groovy不需用定义CLASS类就可以直接执行脚本;

    • Groovy语法省略括弧和语句结尾分号等操作;

    所以说这个基础入门没必要特别深入理解,简单的前面都用过了,理解DSL作用即可,点到为止,详情参考官方文档。

    【工匠若水 http://blog.csdn.net/yanbober 转载请注明出处。点我开始Android技术交流

    8 Groovy脚本基础总结

    其实没啥总结的,Groovy其实可以当做Java来看待,只是它提供的支持比Java还好而已,在学习Groovy是一定要和Java进行对比学习,这样才能速成基础。

    这里写图片描述

    展开全文
  • Gradle从入门到实战 - Groovy基础

    万次阅读 多人点赞 2018-10-01 19:02:01
    前言 Android方向的第一期文章,会专注于Gradle系列,名字叫做『 Gradle从入门到实战』,计划有如下几个课程: Groovy基础 ...为什么是Groovy基础呢,因为玩转Gradle并不需要学习Groovy的全部...
  • Groovy&Gradle总结

    2019-01-09 10:12:50
    欢迎大家加入QQ群一起讨论: 489873144(android格调小窝) 我的github地址:https://github.com/jeasonlzy 0x01 Groovy 概述 Groovy 是一个基于 JVM ...
  • Gradle详解+Groovy

    万次阅读 2016-07-09 18:34:38
    Gradle是当前非常“劲爆”的构建工具。本篇文章就是专为讲解Gradle而来。介绍Gradle之前,先说点题外话。 一、题外话 ...说实话,我在索尼工作的时候,就见过Gradle。但是当时我一直不知道这是什么东西。...
  • Groovy基础:1: 简介

    千次阅读 2019-05-12 09:53:45
    Apache Groovy是一个功能强大的动态编程语言,靠着其简洁、与Java非常相似以及易于学习的语法,基于Java平台的Groovy关注于提高开发者的生产性。它可以和任何Java语言进行无缝集成,支持DSL,提供运行阶段和编译阶段...
  • Groovy入门教程

    万次阅读 多人点赞 2010-07-18 14:29:00
    Groovy入门教程kmyhy@126....作为跑在JVM中的另一种语言,groovy语法与 Java 语言的语法很相似。同时,Groovy 抛弃了java烦琐的文法。同样的语句,使用groovy能在最大限度上减少你的击键次数——这确实是“懒惰程序员
  • Groovy 使用完全解析

    万次阅读 多人点赞 2017-10-20 10:17:01
    概念Groovy是一种动态语言,它和Java类似(算是Java的升级版,但是又具备脚本语言的特点),都在Java虚拟机中运行。当运行Groovy脚本时它会先被编译成Java类字节码,然后通过JVM虚拟机执行这个Java字节码类。Groov
  • Groovy系列目录

    万次阅读 2009-06-10 08:15:00
    --CTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dt-->前言及资源前言写在Groovy/Grails栏目开通的话资源2G资源IDEGroovy与IDEGroovy的Eclipse插件的安装
  • 利用IntelliJ IDEA创建第一个Groovy工程

    万次阅读 2016-11-06 23:29:18
    因为某些原因,需要学习一下Groovy。关于Groovy的入门教程请看这篇文章http://www.ibm.com/developerworks/cn/education/java/j-groovy/j-groovy.html有点老,入门还不错。OK,下面来介绍如何创建一个Groovy工程。...
  • IntelliJ IDEA 关联了后缀为groovy的文件但是没有配置Groovy的library。 1、病因一之解决方法 病因:本项目不需要用的Groovy但是关联了groovy了文件 方子:那直接去掉后缀为groovy的关联即可 结果:良好...
  • 在app的build.gradle中的android部分添加如下代码块即可   Plain Text code? 1 2 3 4 lintOptions {  checkReleaseBuilds false  abortOnError false ... ...
  • Groovy 脚本的多种运行方法

    万次阅读 2015-05-25 11:00:46
    groovyConsole 图形交互控制台groovysh shell命令交互通过IDE运行Groovy脚本用命令行执行Groovy脚本用Groovy创建Unix脚本 Groovy脚本是一些定义在文本文件中的语句和类。它和其他脚本语言的使用类似,它有多种方式...
  • 在eclipse中安装groovy插件详细步骤

    万次阅读 多人点赞 2017-06-07 16:02:59
    为了方便,将groovy插件集成到eclipse中使用,安装步骤如下:step 1:检查自己的eclipse版本:在help->About Eclipse中查看: step 2:进入 https://github.com/groovy/groovy-eclipse/wiki查找和自己eclipse对应...
  • Groovy学习记录-------Groovy安装/配置

    万次阅读 2017-08-20 13:00:57
    一:Groovy SDK下载Groovy SDK官网下载地址: http://www.groovy-lang.org/download.html 每个版本有五个选项可供下载,依次为: binary:二进制包 source:源文件 documentation:文档 SDK bundle:SDK包,...
  • IDEA里面为项目添加编写Groovy支持

    万次阅读 2016-01-06 11:54:56
    Groovy 是在 java平台上的、 具有像 Python , Ruby 和 Smalltalk 语言特性的灵活动态语言, groovy 保证了这些特性象 java 语法一样被 java 开发者使用;
  • File-Setting-Complier 把!?*.groovy;删除保存即可
1 2 3 4 5 ... 20
收藏数 59,542
精华内容 23,816
关键字:

groovy