Groovy记录

官方文档

相关记录

  • keywords
    asdeftraitin

  • String

    • Single quoted string:
      'a single quoted string'
    • Triple single quoted string:
      '''a triple single quoted string'''
    • Double quoted string:
      "a double quoted string"
      def name = 'Guillaume' // a plain string
      def greeting = "Hello ${name}"
      
    • Triple double quoted string
      def name = 'Groovy'
      def template = """
          Dear Mr ${name},
          You're the winner of the lottery!
          Yours sincerly,
          Dave
      """
      assert template.toString().contains('Groovy')
      
  • Numbers Underscore in literals

    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
    
  • Lists

    def letters = ['a', 'b', 'c', 'd']
    assert letters[0] == 'a'     
    assert letters[1] == 'b'
    
    assert letters[-1] == 'd'    //神奇吧!从后往前取,用负数!
    assert letters[-2] == 'c'
    
  • Arrays

    String[] arrStr = ['Ananas', 'Banana', 'Kiwi']  
    def numArr = [1, 2, 3] as int[]   
    
  • Maps

    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 
    
  • Method pointer operator

    def str = 'example of method reference'            
    def fun = str.&toUpperCase                         
    def upper = fun()                                  
    assert upper == str.toUpperCase() 
    

    它可以作为Closure参数:

    def transform(List elements, Closure action) {                    
        def result = []
        elements.each {
            result << action(it)
        }
        result
    }
    String describe(Person p) {                                       
        "$p.name is $p.age"
    }
    def action = this.&describe                                       
    def list = [
        new Person(name: 'Bob',   age: 42),
        new Person(name: 'Julia', age: 35)]                           
    assert transform(list, action) == ['Bob is 42', 'Julia is 35'] 
    
  • Spread operator

    class Car {
        String make
        String model
    }
    def cars = [
           new Car(make: 'Peugeot', model: '508'),
           new Car(make: 'Renault', model: 'Clio')]       
    def makes = cars*.make                                
    assert makes == ['Peugeot', 'Renault']  
    
  • Range operator

    def range = 0..5                                    
    assert (0..5).collect() == [0, 1, 2, 3, 4, 5]       
    assert (0..<5).collect() == [0, 1, 2, 3, 4]         
    assert (0..5) instanceof List                       
    assert (0..5).size() == 6    
    
  • Spaceship operator

    assert (1 <=> 1) == 0
    assert (1 <=> 2) == -1
    assert (2 <=> 1) == 1
    assert ('a' <=> 'z') == -1
    
  • Membership operator

    def list = ['Grace','Rob','Emmy']
    assert ('Emmy' in list)     
    
  • Identity operator
    In Groovy, using == to test equality is different from using the same operator in Java. In Groovy, it is calling equals. If you want to compare reference equality, you should use is like in the following example:

    def list1 = ['Groovy 1.8','Groovy 2.0','Groovy 2.3']        
    def list2 = ['Groovy 1.8','Groovy 2.0','Groovy 2.3']        
    assert list1 == list2                                       
    assert !list1.is(list2) 
    
  • Coercion operator

    Integer x = 123
    String s = x as String 
    
  • Call operator

    class MyCallable {
        int call(int x) {           
            2*x
        }
    }
    
    def mc = new MyCallable()
    assert mc.call(2) == 4          
    assert mc(2) == 4
    
  • public static void main vs script
    Groovy supports both scripts and classes. Take the following code for example:
    Main.groovy

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

    This is typical code that you would find coming from Java, where code has to be embedded into a class to be executable. Groovy makes it easier, the following code is equivalent:

    println 'Groovy world!'
    
  • Script class
    A script is always compiled into a class. The Groovy compiler will compile the class for you, with the body of the script copied into a run method. The previous example is therefore compiled as if it was the following:
    Main.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)     
          }
      }
    

    You can also mix methods and code. The generated script class will carry all methods into the script class, and assemble all script bodies into the run method:

    println 'Hello'                                 
    int power(int n) { 2**n }                       
    println "2^6==${power(6)}"   
    

    This code is internally converted into:

    import org.codehaus.groovy.runtime.InvokerHelper
    class Main extends Script {
        int power(int n) { 2** n}                   
        def run() {
            println 'Hello'                         
            println "2^6==${power(6)}"              
        }
        static void main(String[] args) {
            InvokerHelper.runScript(Main, args)
        }
    }
    
  • Class
    Groovy classes are very similar to Java classes, and are compatible with Java ones at JVM level. They may have methods, fields and properties (think JavaBean properties but with less boilerplate). Classes and class members can have the same modifiers (public, protected, private, static, etc) as in Java with some minor differences at the source level which are explained shortly.

    The key differences between Groovy classes and their Java counterparts are:

    • Classes or methods with no visibility modifier are automatically public (a special annotation can be used to achieve package private visibility).

    • Fields with no visibility modifier are turned into properties automatically, which results in less verbose code, since explicit getter and setter methods aren’t needed. More on this aspect will be covered in the fields and properties section.

    • Classes do not need to have the same base name as their source file definitions but it is highly recommended in most scenarios (see also the next point about scripts).

    • One source file may contain one or more classes (but if a file contains any code not in a class, it is considered a script). Scripts are just classes with some special conventions and will have the same name as their source file (so don’t include a class definition within a script having the same name as the script source file).

  • Constructors

    class PersonConstructor {
        String name
        Integer age
    
        PersonConstructor(name, age) {          
            this.name = name
            this.age = age
        }
    }
    
    def person1 = new PersonConstructor('Marie', 1)  
    def person2 = ['Marie', 2] as PersonConstructor  
    PersonConstructor person3 = ['Marie', 3]  
    
    class PersonWOConstructor {                                  
        String name
        Integer age
    }
    
    def person4 = new PersonWOConstructor()                      
    def person5 = new PersonWOConstructor(name: 'Marie')         
    def person6 = new PersonWOConstructor(age: 1)                
    def person7 = new PersonWOConstructor(name: 'Marie', age: 2)
    
  • Method
    1.Named arguments
    Like constructors, normal methods can also be called with named arguments. They need to receive the parameters as a map. In the method body, the values can be accessed as in normal maps (map.key).

    def foo(Map args) { "${args.name}: ${args.age}" }
    foo(name: 'Marie', age: 1)
    

    2.Default arguments

    def foo(String par1, Integer par2 = 1) { [name: par1, age: par2] }
    assert foo('Marie').age == 1
    
  • Exception declaration
    Groovy automatically allows you to treat checked exceptions like unchecked exceptions. This means that you don’t need to declare any checked exceptions that a method may throw as shown in the following example which can throw a FileNotFoundException if the file isn’t found:

    def badRead() {
        new File('doesNotExist.txt').text
    }
    
    shouldFail(FileNotFoundException) {
        badRead()
    }
    
  • Fields and properties

    A field is a member of a class or a trait which has:

    • a mandatory access modifier (public, protected, or private)
    • one or more optional modifiers (static, final, synchronized)
    • an optional type
    • a mandatory name

    A property is an externally visible feature of a class. Rather than just using a public field to represent such features (which provides a more limited abstraction and would restrict refactoring possibilities), the typical convention in Java is to follow JavaBean conventions, i.e. represent the property using a combination of a private backing field and getters/setters. Groovy follows these same conventions but provides a simpler approach to defining the property. You can define a property with:

    • an absent access modifier (no public, protected or private)
    • one or more optional modifiers (static, final, synchronized)
    • an optional type
    • a mandatory name
  • Annotation member values
    However it is possible to omit value= in the declaration of the value of an annotation if the member value is the only one being set:

    @interface Page {
        String value()
        int statusCode() default 200
    }
    
    @Page(value='/home')                    
    void home() {
        // ...
    }
    
    @Page('/users')                         
    void userList() {
        // ...
    }
    
    @Page(value='error',statusCode=404)     
    void notFound() {
        // ...
    }
    
  • Closure annotation parameters
    An interesting feature of annotations in Groovy is that you can use a closure as an annotation value. Therefore annotations may be used with a wide variety of expressions and still have IDE support. For example, imagine a framework where you want to execute some methods based on environmental constraints like the JDK version or the OS. One could write the following code:

    class Tasks {
        Set result = []
        void alwaysExecuted() {
            result << 1
        }
        @OnlyIf({ jdk>=6 })
        void supportedOnlyInJDK6() {
            result << 'JDK 6'
        }
        @OnlyIf({ jdk>=7 && windows })
        void requiresJDK7AndWindows() {
            result << 'JDK 7 Windows'
        }
    }
    

    For the @OnlyIf annotation to accept a Closure as an argument, you only have to declare the value as a Class:

    @Retention(RetentionPolicy.RUNTIME)
    @interface OnlyIf {
        Class value()                    
    }
    
    class Runner {
        static <T> T run(Class<T> taskClass) {
            def tasks = taskClass.newInstance()                                         
            def params = [jdk:6, windows: false]                                        
            tasks.class.declaredMethods.each { m ->                                     
                if (Modifier.isPublic(m.modifiers) && m.parameterTypes.length == 0) {   
                    def onlyIf = m.getAnnotation(OnlyIf)                                
                    if (onlyIf) {
                        Closure cl = onlyIf.value().newInstance(tasks,tasks)            
                        cl.delegate = params                                            
                        if (cl()) {                                                     
                            m.invoke(tasks)                                             
                        }
                    } else {
                        m.invoke(tasks)                                                 
                    }
                }
            }
            tasks                                                                       
        }
    }
    
  • Traits
    Traits are a structural construct of the language which allows:

    • composition of behaviors
    • runtime implementation of interfaces
    • behavior overriding
    • compatibility with static type checking/compilation
    trait FlyingAbility {                           
            String fly() { "I'm flying!" }          
    }
    
    class Bird implements FlyingAbility {}          
    def b = new Bird()                              
    assert b.fly() == "I'm flying!"   
    

Closures


Closure太重要了,以至于,我要把它单独拎出来。
先看看官方对它的定义:

A closure in Groovy is an open, anonymous, block of code that can take arguments, return a value and be assigned to a variable. A closure may reference variables declared in its surrounding scope. In opposition to the formal definition of a closure, Closure in the Groovy language can also contain free variables which are defined outside of its surrounding scope. While breaking the formal concept of a closure, it offers a variety of advantages which are described in this chapter.

  • Defining a closure

    { [closureParameters -> ] statements }
    

    Where [closureParameters->] is an optional comma-delimited list of parameters, and statements are 0 or more Groovy statements. The parameters look similar to a method parameter list, and these parameters may be typed or untyped.

    When a parameter list is specified, the -> character is required and serves to separate the arguments from the closure body. The statements portion consists of 0, 1, or many Groovy statements.

    { item++ }                                          
    
    { -> item++ }                                       
    
    { println 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()
    }
    
  • Closures as an object
    A closure is an instance of the groovy.lang.Closure class, making it assignable to a variable or a field as any other variable, despite being a block of code:

    def listener = { e -> println "Clicked on $e.source" }      
    assert listener instanceof Closure
    Closure callback = { println 'Done!' }                      
    Closure<Boolean> isTextFile = {
        File it -> it.name.endsWith('.txt')                     
    }
    
  • Calling a closure

    def code = { 123 }
    assert code() == 123
    assert code.call() == 123
    

    Unlike a method, a closure always returns a value when called.

  • Normal parameters
    Parameters of closures follow the same principle as parameters of regular methods:

    • an optional type
    • a name
    • an optional default value

    Parameters are separated with commas:

    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
    
  • Implicit parameter
    When a closure does not explicitly define a parameter list (using ->), a closure always defines an implicit parameter, named it.

    If you want to declare a closure which accepts no argument and must be restricted to calls without arguments, then you must declare it with an explicit empty argument list:

    def magicNumber = { -> 42 }
    
    // this call will fail because the closure doesn't accept any argument
    magicNumber(11)
    
  • Delegation strategy
    A closure actually defines 3 distinct things:

    • this corresponds to the enclosing class where the closure is defined
    • owner corresponds to the enclosing object where the closure is defined, which may be either a class or a closure
    • delegate corresponds to a third party object where methods calls or properties are resolved whenever the receiver of the message is not defined
  • this
    Closure里的this就是Closure没有this!它只是指向定义了这个Closure的外部的第一层的Class对象

  • owner
    就是拥有(定义)这个Closure的对象,可能是Class也可能是Closure

  • delegage

    class Person {
        String name
    }
    def p = new Person(name:'Igor')
    def cl = { name.toUpperCase() }                 
    cl.delegate = p                                 
    assert cl() == 'IGOR'
    

    但是,

    class Person {
        String name
        def pretty = { "My name is $name" }             
        String toString() {
            pretty()
        }
    }
    class Thing {
        String name                                     
    }
    
    def p = new Person(name: 'Sarah')
    def t = new Thing(name: 'Teapot')
    
    // Using the default strategy, the name property is resolved on the owner first
    assert p.toString() == 'My name is Sarah'     
    // so if we change the delegate to t which is an instance of Thing      
    p.pretty.delegate = t     
    // there is no change in the result: name is first resolved on the owner of   the closure                          
    assert p.toString() == 'My name is Sarah' 
    

    最后一行,为什么不变?

    因为,Closure.OWNER_FIRST is the default strategy
    首先从owner中去找,找到了name属性,ok,那就不管后面又给delegate赋了什么鬼值了

    再来一个栗子:

    class Person {
        String name
        int age
        def fetchAge = { age }
    }
    class Thing {
        String name
    }
    
    def p = new Person(name:'Jessica', age:42)
    def t = new Thing(name:'Printer')
    def cl = p.fetchAge
    cl.delegate = p
    assert cl() == 42
    cl.delegate = t
    assert cl() == 42
    cl.resolveStrategy = Closure.DELEGATE_ONLY
    cl.delegate = p
    assert cl() == 42
    cl.delegate = t
    try {
        cl()
        assert false
    } catch (MissingPropertyException ex) {
        // "age" is not defined on the delegate
    }
    
  • 在GString中使用Closure

    class Person {
        String name
        String toString() { name }
    }
    def sam = new Person(name:'Sam')
    def lucy = new Person(name:'Lucy')
    def p = sam
    // Create a GString with lazy evaluation of "p"
    def gs = "Name: ${-> p}"
    assert gs == 'Name: Sam'
    p = lucy
    assert gs == 'Name: Lucy'
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 193,968评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,682评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,254评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,074评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,964评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,055评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,484评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,170评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,433评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,512评论 2 308
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,296评论 1 325
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,184评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,545评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,150评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,437评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,630评论 2 335