Are List and List the same in Groovy?

前端 未结 3 1870
無奈伤痛
無奈伤痛 2020-12-10 11:32

Question 1

Is it irrelevant whether a List (list of objects) or a List (list of Strings) is used in Groovy?

3条回答
  •  星月不相逢
    2020-12-10 12:33

    When running Groovy "normally", generics are thrown away before compilation, so only exist in the source as helpful reminders to the developer.

    However, you can use @CompileStatic or @TypeChecked to make Groovy honour these Generics and check the types of things at compilation.

    As an example, consider I have the following project structure:

    project
     |---- src
     |      |---- main
     |             |---- groovy
     |                    |---- test
     |                           |---- ListDelegate.groovy
     |                           |---- Main.groovy
     |---- build.gradle
    

    With the code:

    build.gradle

    apply plugin: 'groovy'
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        compile 'org.codehaus.groovy:groovy-all:2.2.1'
    }
    
    task( runSimple, dependsOn:'classes', type:JavaExec ) {
        main = 'test.Main'
        classpath = sourceSets.main.runtimeClasspath
    }
    

    ListDelegate.groovy

    package test
    
    class ListDelegate {
        @Delegate List numbers = []
    }
    

    Main.groovy

    package test
    
    class Main {
        static main( args ) {
            def del = new ListDelegate()
            del << 1
            del << 'tim'
            println del
        }
    }
    

    Now, running gradle runSimple gives us the output:

    :compileJava UP-TO-DATE
    :compileGroovy
    :processResources UP-TO-DATE
    :classes
    :runSimple
    [1, tim]
    
    BUILD SUCCESSFUL
    
    Total time: 6.644 secs
    

    So as you can see, the generics were thrown away, and it just worked adding Integers and Strings to out List of supposedly only Integers

    Now, if we change ListDelegate.groovy to:

    package test
    
    import groovy.transform.*
    
    @CompileStatic
    class ListDelegate {
        @Delegate List numbers = []
    }
    

    And run again:

    :compileJava UP-TO-DATE
    :compileGroovy
    :processResources UP-TO-DATE
    :classes
    :runSimple
    [1, tim]
    
    BUILD SUCCESSFUL
    
    Total time: 6.868 secs
    

    We get the same output!! This is because whilst ListDelegate is now statically compiled, our Main class is still dynamic, so still throws away generics before constructing the ListDelegate... So we can also change Main.groovy to:

    package test
    
    import groovy.transform.*
    
    @CompileStatic
    class Main {
        static main( args ) {
            def del = new ListDelegate()
            del << 1
            del << 'tim'
            println del
        }
    }
    

    And now re-running gradle runSimple give us:

    :compileJava UP-TO-DATE
    :compileGroovy
    startup failed:
    /Users/tyates/Code/Groovy/generics/src/main/groovy/test/Main.groovy: 10:
        [Static type checking] - Cannot find matching method test.ListDelegate#leftShift(java.lang.String).
        Please check if the declared type is right and if the method exists.
     @ line 10, column 9.
               del << 'tim'
               ^
    
    1 error
    
    :compileGroovy FAILED
    

    Which is, as you'd expect, failing to add a String to our declared List of Integer.

    In fact, you only need to CompileStatic the Main.groovy class and this error will be picked up, but I always like to use it where I can, not just where I need to.

提交回复
热议问题