Gradle开发-Groovy集合&数组

作者: 未见哥哥 | 来源:发表于2018-07-01 18:46 被阅读15次

    #Groovy 集合

    • 列表集合的定义和元素的操作;
    • 数组的定义和元素的操作;
    • 键值对集合的定义和元素的操作;
    • 范围 Rnnge 的定义和元素的操作;
    • 闭包参数的确定;
    • 总结;

    ##列表集合

    ### 列表集合的定义

    • 定义一个列表集合的方式有点像 Java 中的定义数组一样。
    • 默认的类型就是 ArrayList 。
    • 集合元素可以接收任意的数据类型。
    //定义一个集合
    //1. 在 Groovy 中定义的集合默认就是对应于 Java 中 ArrayList 集合
    def list = [1, 2, 3]
    println list.class//class java.util.ArrayList
    
    assert list instanceof List
    
    //2. 在集合中可以介绍任意类型的数据,例如当前传入的是数字,字符串,boolean值
    def list2 = [1, "groovy", true]
    

    疑问:假如我想定义一个 LinkedList集合,我该如何去指定一个集合的类型呢?

    • 通过 as 关键字来指定。
    • 通过强类型来定义你想要的类型。
    //3. 指定集合的类型有两种方式
    //方式1 通过 as 操作符来指定
    //方式2 通过强类型定义的方式来指定
    
    def list3 = [1, 2, 3] as LinkedList
    //println list3.class//class java.util.LinkedList
    LinkedList list4 = [4, 5, 6]
    //println list4.class//class java.util.LinkedList
    

    ### 列表集合元素的操作

    在定义好集合之后,我们就可以要操作集合的元素了。

    #### 根据角标获取元素的值

    • 获取指定角标下的元素

    可以通过角标访问集合指定位置的元素,正数角标是从0位置左往右算起,负数角标是从0位置往反方向算。
    下面的代码片段中出现的负数角标,就有别于 JAVA ,因为在 JAVA 中出现负数角标,基本就会报异常了。
    0 就是第一个位置的元素,-1就是最后一个位置的元素,一次类推即可。

    //获取单个元素
    def list5 = [1, 2, 3, 4, 5]
    assert 2 == list5[1]
    assert 5 == list5[-1]
    
    //获取多个元素
    //list[index1,index2,indexn]获取指定位置的元素,如果角标不存在,那么对应的值就返回null
    println list5[1,3,0].toListString()//[2, 4, 1]
    
    //println list5[1,9].toListString()//[2, null]
    
    • 获取指定范围的元素

    list[index1..index2]取出指定范围的元素

    def list5 = [1, 2, 3, 4, 5]
    //取出指定范围的元素集合
    println list5[1..3].toListString()//[2, 3,4]
    

    #### 添加元素到集合

    在列表集合中添加元素的方式有以下三种

    • list.add()
    • leftShift
    • <<
    def list5 = [1, 2, 3, 4, 5]
    
    list5.add(2)
    list5.leftShift 2
    //括号是可以省略的
    list5.leftShift(2)
    //leftshift可以使用操作符<<表示
    list5 << 2
    

    #### 移除集合中的元素

    def list = [2, 1, 8, -9, 6, 3, 5, 0]
    //移除的是角标为2的元素
    list.remove(2)
    //移除元素为2
    list.remove((Object) 2)
    list.removeLast()
    

    #### 元素的遍历

    Groovy 中使用 each 来遍历集合。

    在遍历时,可以选择是否带有角标来选择不同的遍历方法。

    def list = [2, 1, 8, -9, 6, 3, 5, 0]
    
    //不带有角标的遍历,类似于 java 中的 foreach
    list.each {print it+"  "}//2  1  8  -9  6  3  5  0
    
    //带有角标的遍历,类似于普通的for循环
    list.eachWithIndex { int value, int index ->
        println "value is ${value} and index is ${index}"
    }
    

    #### 查找元素

    Groovy 中提供了 findfindAlleveryany 相关的 API 来查找结合的元素。

    //(1)find 找到第一个符合条件的值
    def findList = [2, 1, 8, -9, 6, 3, 5, 0]
    
    //找到第一个元素的偶数的元素
    println findList.find {it->it%2==0}
    
    //(2)findAll 查找所有偶数的值
    println findList.findAll {it->it%2==0}//[2, 8,6, 0]
    
    //(3)any 只有一个符合条件就返回true,否则返回false
    def result = findList.any { it -> it == 8 }
    println result
    
    //(4)every 集合中每一元素都是偶数就返回true
    println findList.every {it->it%2==0 }
    

    #### 计数

    Groovy 中提供 count 方法来计数

    def findList = [2, 1, 8, -9, 6, 3, 5, 0]
    //凡是奇数就累积,返回符合条件的元素个数
    println findList.count { it -> it % 2 == 1 }
    

    #### 最大值和最小值

    Groovy 中提供了 min()max()方法可以获取集合的最小最大值,当前也可以使用其重载带有闭包参数的方法,来自定义规则获取最大值,下面演示的就是最小值的获取,最大值是一样的,

    def findList = [2, 1, 8, -9, 6, 3, 5, 0]
    //min() 查看最小值
    println findList.min()
    //通过闭包修改对应的最小值
    //将每一个元素取绝对值,然后找到一个最小值返回
    println findList.min{Math.abs(it)}
    

    #### 集合元素比较器

    def sortList = [9, -8, 2, 0, 4, -1]
    
    //定义比较器
    //Comparator comparator = { a, b -> a == b ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1 }
    
    //方式1 自定义排序方式
    Collections.sort(sortList, new Comparator<Integer>() {
        @Override
        int compare(Integer a, Integer b) {
            return a == b ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1
        }
    })
    
    //方式2
    sortList.sort()//自然顺序排序
    println sortList.toListString()
    
    //方式3
    sortList.sort(comparator)
    //println sortList.toListString()//[0, -1, 2, 4, -8, 9]
    
    
    def sortList2 = ["java", "Groovy", "c", "c++"]
    
    sortList2.sort {
        it -> it.size()
    }
    println sortList2.toListString()//[c, c++, java, Groovy]
    

    ## 数组

    ### 数组的定义

    因为 Groovy中使用[] 表示就是一个 List 集合,如果要定义 Array ,那么就必须要强制指定为一个数组类型。

    • 使用强类型定义。
    • 使用 as 关键字定义数组
    //使用强类型定义
    String[] arr1 = ["Java", "Groovy", "Android"]
    
    assert arr1 instanceof String[]
    
    //使用 as 关键字定义数组
    def arr2 = ["Java", "Groovy", "Android"] as String[]
    
    assert arr2 instanceof String[]
    
    
    //定义多维数组
    def arr3 = new int[3][4]
    
    //println arr3.class
    
    assert arr3.length == 3
    
    assert arr3.size() == 3
    

    ### 数组元素的操作

    数组的操作基本上和 Java 是一样的,这里就贴代码了。

    ## 键值对集合 Map

    ### Map 集合的定义

    • Map 集合的定义有别于 Java 的定义方式,格式如下

    def map = [key1:value1,key2:value2,...]

    • Groovy 中定义的 Map 默认类型是 java.util.LinkedHashMap
    def map1 =[name:"六号表哥",age:26]
    
    println map1.getClass()//class java.util.LinkedHashMap
    

    ### Map 集合元素的操作

    #### 获取元素值

    Map 集合中指定 key 下的值有有两种方式:

    • map.get(key)
    • map[key]
    • map.key
    
    def map1 =[name:"六号表哥",age:26]
    
    println "the name is ${map1['name']} and age is ${map1['age']}"//the name is 六号表哥 and age is 26
    println "the name is ${map1.name} and age is ${map1.age}"//the name is 六号表哥 and age is 26
    
    
    //获取一个不存的key对应值,那么会得到null
    println map1.top//null
    
    • 使用数字作为 key
    def map2 =[1:"java",2:"c"]
    println map2.get(1)//java
    println map2[1]//java
    //println map2.1//编译不过
    
    • 关于 map 的 key 需要注意的点

    如果 map 中的可以为一个单词,Groovy 为将它会自动转化为字符串。

    def key = 'name'
    //这里传入的key并不是上面定义的key变量,groovy会将其进行转化为'key'字符串作为map的key。
    def map3 = [key:"六号表哥"]
    
    println map3.key//六号表哥
    //这里的key是上面的变量key,因此取出来的值为null
    println map3[key]//null;
    
    println map3.containsKey('name')//false
    println map3.containsKey('key')//true
    

    那如果我如果要将一个字符串变量作为 map 中的 key ,那么就要将使用(key变量)表示。

    def key = 'name'
    def map4 = [(key):"六号表哥"]
    
    println map4.containsKey('name')//true
    println map4.containsKey('key')//false
    

    #### 添加元素

    def map1 =[name:"六号表哥",age:26]
    map1.level = 'middle'
    //the name is 六号表哥 and age is 25 and level is middle
    println "the name is ${map1['name']} and age is ${map1['age']} and level is ${map1['level']}"
    

    #### 修改集合元素

    def map1 =[name:"六号表哥",age:26]
    map1['age'] = 25
    
    println "the name is ${map1['name']} and age is ${map1['age']}"//the name is 六号表哥 and age is 25
    

    #### Map 遍历

    List 集合一样,Map 集合的遍历也是使用 each 方法来实现。

    
    //不带角标的遍历
    def map = [name: "六号表哥", age: 26]
    
    map.each { key, value ->
        println key + "-" + value
    }
    
    //带有角标的遍历
    map.eachWithIndex { Map.Entry entry, int i ->
    
        //name-六号表哥 index = 0
        //age-26 index = 1
        println entry.key + "-" + entry.value + " index = " + i//age-26 index = 1
    }
    

    #### 查找

    Groovy 中提供了 findfindAlleveryany 相关的 API 来查找结合的元素。

    • find
    def mapFindResult = map.find { key, value ->
    
        if (key.equals('age') && value == 26) {
            return map[key]
        }
        return null
    }
    
    println "查找结果:${mapFindResult}"//查找结果:age=26
    
    
    def mapFindResult2 = map.find { Map.Entry  entry ->
    
        if (entry.key.equals('age') && entry.value == 26) {
            return map[entry.key]
        }
        return null
    }
    println "查找结果:${mapFindResult2}"//查找结果:age=26
    
    
    • findAll
    def map2 = [1:[name: "六号表哥", age: 26],
                2:[name: "Koobe", age: 23],
                3:[name: "Jerry", age: 26], 
                4:[name: "Kai", age: 22],
                5:[name: "kimi", age: 18]
    ]
    
    println map2.findAll {key, person ->
    
        if (person.age > 18) {
            return true
        }
        return false
    }.toMapString()
    //[1:[name:六号表哥, age:26], 2:[name:Koobe, age:23], 3:[name:Jerry, age:26], 4:[name:Kai, age:22]]
    
    
    map2.findAll {key, person ->
    
        if (person.age > 18) {
            return true
        }
        return false
        //collect 过滤
    }.collect {key,value->
    
        print  value.name+" "//六号表哥 Koobe Jerry Kai 
    }
    
    
    • every
    //判断是否所有的人都是成年的
    println map2.every {key, person ->
    
        if (person.age > 18) {
            return true
        }
        return false
    }//false
    
    • any
    //查找是否有未成年的人
    println map2 {key, person ->
    
        if (person.age <18) {
            return true
        }
        return false
    }//false
    

    #### 排序

    println map2.sort {
       Map.Entry element1,  Map.Entry element2 ->
    
            if (element1.value.age == element2.value.age) {
                return 0;
            } else if (element1.value.age > element2.value.age) {
                return 1
            } else {
                return -1
            }
    }.toMapStrin
    

    ## 范围 Rnnge

    ### 范围Rnnge的定义

    使用 range 定义一个整型范围

    def range = 1..10
    

    ### Range 元素的操作

    //起始位置
    println range.from//1
    //结束位置
    println range.to//10
    //第一个元素
    println range[0]//1
    //遍历1
    range.each {
        println it
    }
    //遍历2
    for (i in range) {
        println(i)
    }
    
    
    //在switch中使用range
    Number num = 20
    switch (num) {
        //range 1..17)
        case 1..<18:
            result = "未成年"
            break
        case 18..100:
            result = "成年"
            break
        default:
            result = "unknow"
            break
    }
    
    println result//成年
    

    ## 闭包参数的确定

    在上面的很多示例代码中,我们使用了很多闭包,但是大家肯定有一个疑问,那就是闭包的参数个数及其参数类型是怎么确定的呢?

    其实这个貌似也挺简单的,我们只要跟进去源码,查看 Closure.call(参数..)的调用处,就可以知道具体的参数类型和个数拉,下面以一个简单的示例来演示一下:

    ### 跟踪源码确定闭包

    下面我们以上面的findList.any{...}作为演示

    • 调用 any 方法,传入闭包
    def result = findList.any { it -> it == 8 }
    
    • any 方法源码
    //找到闭包:predicate 
    public static <T> boolean any(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure predicate) {
        return any(self.iterator(), predicate);
    }
    
    • 进入 any 的重载方法
     public static <T> boolean any(Iterator<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure predicate) {
        //闭包被传入 BooleanClosureWrapper 中
         BooleanClosureWrapper bcw = new BooleanClosureWrapper(predicate);
         while (self.hasNext()) {
             //传递一个参数,类型为集合元素的类型
             if (bcw.call(self.next())) return true;
         }
         return false;
     }
    
    • 进入 BooleanClosureWrapper 源码看看怎么使用 predicate 闭包的

    在上面通过 BooleanClosureWrapper.call() 方法调用时就已经知道参数的个数和类型了,下面这段代码的注释就可以知道其实就使用于调用 closure.call 方法。

    /**
     * normal closure call
     */
    public boolean call(Object... args) {
        return bmi.invoke(wrapped, args);
    }
    

    到这里,这个流程就是确定具体的闭包的参数个数和参数类型了,我不清楚这样对不对,反正我平时就这样去确定的。不过为了确保没问题的,可以在官网查看具体的 API 就可以知道闭包的参数和类型咯。

    ### 查阅 API 确定闭包参数

    查找 any 方法
    • 官方示例
    官方示例

    ## 总结

    上面主要演示了Groovy中集合和数组的定义和使用,在上面的示例代码中,很多只是演示了与Java差异的部分,相同部分就没有花时间去做了。以上的示例代码只是用来演示Groovy语法,并没有实际用途。

    ## 参考

    「记录于2018-07-01下午」

    相关文章

      网友评论

        本文标题:Gradle开发-Groovy集合&数组

        本文链接:https://www.haomeiwen.com/subject/zblhuftx.html