Groovy シリーズ 2 Groovy GDK

        

目次

Groovy の収集メソッド

sort メソッドはコレクションを並べ替えます

findAll 対象となるすべての要素をクエリします

収集すると新しいリストが返されます

inject 強力な蓄積機能

各、各インデックス付き

find、findIndexOf クエリ修飾データ

いずれかが条件を満たすデータを判定する

すべての条件を満たすクエリ データ

reverse はコレクションを逆方向に返します

first、last、tail コレクション内の要素を検索します

ワイルドカード (*.)

GPath オブジェクト ナビゲーションの構造

IO 操作がさらに簡単になりました

.. 範囲を表します

道具

ConfigSlurper 設定支援ツール

Expando ユニバーサル拡張クラス

属性変更リスナー追加


        前回の記事ではGroovy全体について学び、Groovy全体の概念や特徴を理解しました。実践を通じて、Groovy の関連する変更点を学びました。この記事では、Groovy 開発ツールキットを一緒に学び、関連する API の学習を通じて Groovy についての理解を深めます。

Groovy の収集メソッド

        Groovy のコレクションは Java のコレクションと同じですが、違いは収集メソッドが異なることです。コレクション メソッドから学び始めます。

sort メソッドはコレクションを並べ替えます

        sort はコレクションを並べ替えます。このメソッドはパラメータとしてクロージャを受け取ることも、パラメータを受け取らないこともできます。

// 默认对集合进行正序排序
def lst = [13, 12, 15, 14];
def newlst = lst.sort();//默认排序
println newlst; 
// 结果
[12, 13, 14, 15]

// 适用闭包作为参数自定义排序
def newlist2 = lst.sort {
    a, b -> a - b ? -1 : 1
}
println newlist2; 
//  结果
[15, 14, 13, 12]

findAll 対象となるすべての要素をクエリします

        findAll は、一致するすべての要素を返します。パラメータとして 1 つのクロージャを受け取ることも、パラメータを受け取らないこともできます。

def list = [13, 12, 15, 14,0,-1];
//[13, 12, 15, 14, -1]
println(list)
println(list.findAll())

def newlst = list.findAll();
//[13, 12, 15, 14, -1]
println newlst;

// findAll 闭包作为参数返回小于 13 的所有元素
def newlst2 = list.findAll {
    value -> value < 13
};
println newlst2;
// 结果
//[12, 0, -1]

収集すると新しいリストが返されます

        collect は新しいリストを返します。このリストは引数として 1 つのクロージャを受け取ることも、引数を受け取らないこともできます。

//- collect 返回 一个新的list,它可以接收1个闭包作为参数,或者,无参数,
def list = [13, 12, 15, 14, 0, -1];
def newlst = [];
newlst = list.collect {
    it * 2
}
println newlst
// 结果
// [26, 24, 30, 28, 0, -2]

inject 強力な蓄積機能

        inject関数には、JSのreduceメソッドに似た強力な累積関数があります。このうち、inject のパラメータは none にすることも、クロージャにすることもできます。

// 以"I"方法参数设置给sum, 迭代list 将每个元素设置 elem 和 sum 拼接赋值给sum
def list = ["am", "a", "man"]
def result = list.inject("I") { sum, elem ->
    "$sum $elem"
}
println result
//结果:I am a man

// 以"2"方法参数设置给p, 迭代 [1, 2, 3] 将每个元素设置 e ,计算 p * e 结果赋值给 p
def intRes = [1, 2, 3].inject(2, {
    p, e -> p * e;
});
println(intRes)
// 结果:12

// 不仅仅可以遍历计算列表,实际的业务场景中,比如计算图书馆的库存。可以看到在计算库存的时候 def totalStore。若采用Java计算的话需要定义中间变量,并且需要写when判断逻辑。
class Library {
    private List<BookSeries> bookSeriesList;
}

class BookSeries {
    private int suitNum;
    private List<Book> books;
}

class Book {
    private String name;
    private int store;
    private double price;
}

def library = new Library(
        bookSeriesList: [
                new BookSeries(suitNum: 1, books: [
                        new Book(name: "水浒传(上)", store: 1, price: 100.00),
                        new Book(name: "水浒传(中)", store: 2, price: 120.00),
                        new Book(name: "水浒传(下)", store: 3, price: 150.00),
                ]),

                new BookSeries(suitNum: 2, books: [
                        new Book(name: "三国演义(上)", store: 4, price: 100.00),
                        new Book(name: "三国演义(中)", store: 5, price: 120.00),
                        new Book(name: "三国演义(下)", store: 6, price: 150.00),
                ]),

                new BookSeries(suitNum: 3, books: [
                        new Book(name: "西游记(上)", store: 7, price: 100.00),
                        new Book(name: "西游记(中)", store: 8, price: 120.00),
                        new Book(name: "西游记(下)", store: 9, price: 150.00),
                ]),

                new BookSeries(suitNum: 4, books: [
                        new Book(name: "红楼梦(上)", store: 10, price: 100.00),
                        new Book(name: "红楼梦(中)", store: 11, price: 120.00),
                        new Book(name: "红楼梦(下)", store: 12, price: 150.00),
                ]),

                new BookSeries(suitNum: 0, books: [
                        new Book(name: "大秦帝国(上)", store: 10, price: 100.00),
                        new Book(name: "大秦帝国(中)", store: 10, price: 120.00),
                        new Book(name: "大秦帝国(下)", store: 10, price: 150.00),
                ]),
        ]
)
when: "统计图书馆丛书总库存"
def totalStore = library.bookSeriesList.inject(0) { libraryTotalStore, bookSeries ->
    libraryTotalStore + (bookSeries.suitNum > 0 ? bookSeries.books.store.sum() * bookSeries.suitNum : 0)
}
println totalStore

各、各インデックス付き

        each の通常の反復メソッド、eachWithIndex の使用法は each と同じです。唯一の違いは、eachWithIndex によって渡されるクロージャーに 2 つのパラメーター (1 つ目は値、2 つ目はインデックス) があることです。

def list = ["a", "b", "c"]

list.eachWithIndex {
    String v, int index ->
        println v;
        println index
}
//结果:
a
0
b
1
c
2

find、findIndexOf クエリ修飾データ

//- find 返回第一个符合条件的元素,它可以接收1个闭包作为条件参数,或者无参数。
// 没有设置参数,默认返回第一个
def list = ["a", "b", "c"]
def str = list.find();
println(str)

// 设置闭包参数,默认符合条件的那个
str = list.find({e -> e == "b"})
println(str)
// 设置闭包参数,闭包参数使用默认的关键字 it
str = list.find({it == "b"})
println(str)

//- findIndexOf 返回指定元素的索引值。它可以接收1个闭包作为条件参数。
index = list.findIndexOf({it == "b"})
println(index)

//结果:
a
b
b
1

いずれかが条件を満たすデータを判定する

//- any 返回boolean值。只要有任意一个符合条件就返回true,它可以接收1个闭包作为条件参数,或者无参数。
def list = ["a", "b", "c"]
def result = list.any();
println(result)
result = list.any({it == "e"});
println(result)

//结果 
true
false

すべての条件を満たすクエリ データ

//- every 返回boolean值,只有所有符合条件才返回true,它可以接收1个闭包作为条件参数,或者无参数。
def list = ["a", "b", "c"]
def result = list.every();
println(result)
result = list.every({it == "a" || it == "b" || it == "c"});
println(result)
result = list.every({it == "a"});
println(result)
result = list.every({it == "e"});
println(result)

// 结果:
true
true
false
false

reverse はコレクションを逆方向に返します

//- reverse, 它将原list倒序,返回新list。无参数
def list = ["a", "b", "c"]
list = list.reverse();
println(list)

//结果:
[c, b, a]

first、last、tail コレクション内の要素を検索します

//- first 返回原list的第一个元素,无参数
def list = ["a", "b", "c"]
def result = list.first();
println(result)

//- last 返回原list的最后一个元素,无参数
result = list.last();
println(result)

//- tail 返回一个新list,这个list包含原list(除第一个元素)的所有元素,无参数
list = list.tail();
println(list)

// 结果:
a
c
[b, c]

        groupBy、tokenize、unique、max、min、count、sum などの他の関数については、将来試して練習する時間があります。

ワイルドカード (*.)

        Groovy では、Linux コマンドを使用して特定のファイル タイプのディレクトリをクエリおよび表示するときにワイルドカード (ls *.txt) を使用するのと同じように、ワイルドカード (*.) を使用して必要な情報を抽出できます。クラスを定義し、2 つの Car オブジェクトをインスタンス化し、ワイルドカードを使用して各インスタンス オブジェクトの make 属性をクエリします。

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

makes.each {
    println it
}

//结果:
Peugeot
Renault

// 创建一个1到10元素的列表,并且每个元素都乘以2
def list = (1..10)*.multiply(2)
println list

// 结果:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

// 将列表中的所有的字符串转大写
def list = ['Denver', 'Cheyenne', 'Reno', 'Sacramento']*.toUpperCase()
println(list)

// 结果:
[DENVER, CHEYENNE, RENO, SACRAMENTO]

GPath オブジェクト ナビゲーションの構造

        GPath は、Groovy コード用の強力なオブジェクト ナビゲーション構造であり、XML (および同等の) ドキュメントを記述するための標準である XPath に似た名前が選ばれています。XPath と同様、GPath の目標は、明確でコンパクトで読みやすい式を表現することです。染色メソッドも Collection の GDK メソッドにカプセル化されます。

// GPath  像XPath一样,可以轻松的访问多层的集合对象,如下我们定义一个 List<Map<String, Integer>> 类型,快速的获取他的某个健值对。
def listOfMaps = [['a': 11, 'b': 12], ['a': 21, 'b': 22], null]
println(listOfMaps.a);// [11, 21]

// 结果:
[11, 21]

// 我们看到最后一个元素是 null 无法获取到,但是我们使用通配符就可以
listOfMaps = [['a': 11, 'b': 12], ['a': 21, 'b': 22], null]
println(listOfMaps*.a)

// 结果:
[11, 21, null]

//采用Collection的GDK方法调用,可以看到是等价于 list*.a 的
def list = listOfMaps.collect { it?.a }
println(list)

  // 结果:
 [11, 21, null]

IO 操作がさらに簡単になりました

// groovy可以简单明了的进行文件读写操作
//* 写入一个文件内容:
// 创建文件,并写入
new File("book.txt").text = "lly";

//* 读取一个文件内容
println new File("book.txt").text

//* 也可以通过字节方式写入
//先手动创建data文件
byte[] data = new File("data").bytes;
//把data的数据写入book2.txt
new File("book2.txt").bytes = data;

//创建 dragons.txt.txt 写入内容后,并读取dragons.txt内容
new File('dragons.txt').eachLine { line-> println(line)   }

//* 如果需要用InputStream,Reader,OutputStream,Writer这些对象进行操作。groovy也提供类似的方法
//- 输入流InputStream操作
Properties properties = new Properties()
File propertiesFile = new File('/Users/liluyang/llyCode/groovy 2/src/main/resources/application.properties')
propertiesFile.withInputStream {
    properties.load(it)
}
println properties.lly
println properties.yangzai

// 结果:
lly
曾经的屠龙少年
如今变成了恶龙
handsome
handsome too

//- Reader操作
def lineNo = 1
def line = 1;
new File("dragons.txt").withReader { reader ->
    while ((line = reader.readLine()) != null) {
        println "第${lineNo}行内容: ${line}"
        lineNo++
    }
}

// 结果:
第1行内容: 曾经的屠龙少年
第2行内容: 如今变成了恶龙

//- OutputStream操作
// 文件复制
def srcFile = new File("dragons.txt")
def targetFile = new File("book.txt")
targetFile.withOutputStream { outputStream ->
    srcFile.withInputStream { inputStream ->
        outputStream << inputStream
    }
}

//- 写入Writer操作
//写入
new File('book.txt').withWriter('utf-8', {
    writer -> writer.writeLine 'Hello World'
});

//精简版
new File('book.txt') << '''Into the ancient pond
    A frog jumps
    Water’s sound!'''

//## 极简的URLs操作
//1.数据抓取
URL url = new URL("https://www.baidu.com/");
InputStream input = (InputStream) url.getContent();
ByteArrayOutputStream out = new ByteArrayOutputStream();

int n = 0;
byte[] arr = new byte[1024];

while (-1 != (n = input.read(arr)))
    out.write(arr, 0, n);
System.out.println(new String(out.toByteArray()));

.. 範囲を表します

        グルーヴィーに。範囲操作は、ループ、スイッチ、文字列インターセプトで使用できます。

1..10 - 包含範囲の例

1 .. <10 - 排他的な範囲の例

'a'..'x' - 範囲は文字で構成することもできます

10..1 - 範囲を降順で並べ替えることもできます

'x'..'a' - 範囲は文字で構成することもでき、降順でソートされます。

// 打印 1 到 10 数字
(1..10).each { println(it)}

// 打印 1 到 100 数字
for (def i in 1..100){
    println(i)
}

// 定义字符串,打印[0..4]范围字符串,打印 [0..4, 8..-1] 下标0到下表4的字符串范围,和下标为8到最后的字符串范围
def text = 'learning groovy'
println text[0..4]
println text[0..4, 8..-1]

// 结果:
learn
learn groovy

def list = ['hank', 'john', 'fred']
println list[0..1] //[hank, john]

// 打印数字 1 到小于 5 的数字
(1..<5).each { println(it) }

道具

ConfigSlurper 設定支援ツール

        ConfigSlurper ツールは構成ファイルを読み取るのに非常に便利で、カスタム構成ファイルをサポートしています。Groovy で文字列をカスタマイズし、構成ファイルの形式に従ってそれを読み取ります。

//- ConfigSlurper工具用于读取配置文件非常的方便
def config = new ConfigSlurper().parse('''
     app.date = new Date()
     app.age = 42
     app {
      name = "Test ${this.age}"
    }
     ''')
def properties = config.toProperties()
println(properties."app.date")
println(properties."app.age")
println(properties."app.name")

// 结果:
Sun May 28 19:04:39 CST 2023
42
Test 42

Expando ユニバーサル拡張クラス

        なぜこのように説明したかというと、このクラスは強力すぎるからです。Expando クラスは Groovy 言語の興味深いクラスであり、その機能は GroovyBean クラスに似ていますが、GroovyBean クラスよりも柔軟です。同時に、これは Map クラスに似ていますが、Map クラスよりも柔軟です。属性をカスタマイズし、値を柔軟に割り当てることができます。


//1.
def expando = new Expando()
expando.name = { -> "abc" }
expando.say = { String s -> "${expando.name} says: ${s}" }
println expando.say('hello')

//2.
def person = new Expando()
person.name = 'Alice'
person.age = 18

person.description = {
    println """
               ----------description---------
                   name: ${delegate.name}
                   age:  ${delegate.age}
               ------------------------------
             """
}
person.description()

//结果:
abc says: hello

               ----------description---------
                   name: Alice
                   age:  18
               ------------------------------

属性変更リスナー追加

        Groovy では、さまざまなコレクション オブジェクトの変更イベントをアクティブに監視し、独自の処理を行うことができます。以下では、List コレクションを例として、リスナー ObservableList を定義し、イベント処理関数をバインドします。コレクションが変更されたときに処理関数を呼び出すことができます。

def list = new ObservableList()
def printer = { e -> println e.class }
list.addPropertyChangeListener(printer)
list.add 'Harry Potter'
list.add 'Hermione Granger'
list.remove(0)

// 结果:
class groovy.util.ObservableList$ElementAddedEvent
class java.beans.PropertyChangeEvent
class groovy.util.ObservableList$ElementAddedEvent
class java.beans.PropertyChangeEvent
class groovy.util.ObservableList$ElementRemovedEvent

おすすめ

転載: blog.csdn.net/lly576403061/article/details/130921886