通过 Groovy 进行循环

同大多数脚本语言一样,Groovy 经常被宣传为生产力更高 的 Java 语言替代品。

更好、更短的循环

下面这种方法可以更好地感受 Groovy 缺乏类型的好处:首先,用与创建 HelloWorld 相同的方式创建一个 Groovy 类,将这个类称为 MethodMadness,并删除自动生成的类体:将要定义一个独立的 repeat 函数。现在在控制台中输入以下代码:

def repeat(val){for(i = 0; i < 5; i++){println val}
}

从 Java 的角度来看,这个小函数看起来可能有些怪(实际上,它很像 JavaScript)。但它就是 Java 代码,只不过是用 Groovy 的样式编写的。

深入方法

repeat 函数接受一个变量 val。请注意参数不需要 def。方法体本质上就是一个 for 循环。
调用

repeat("hello world")

输出 “hello world” 五次。请注意,for 循环中省略了 int。没有变量类型的 for 循环要比标准的 Java 代码短些。现在看看如果在代码里加入范围会出现什么情况;

Groovy 中的范围

范围 是一系列的值。e.g. “0..4” 表明包含 整数 0、1、2、3、4。Groovy 还支持排除范围,“0..<4” 表示 0、1、2、3。还可以创建字符范围:“a..e” 相当于 a、b、c、d、e。“a..

循环范围

范围为循环带来了很大的方便。例如,前面从 0 递增到 4 的 for 循环如下所示:

for(i = 0; i < 5; i++)

范围可以将这个 for 循环变得更简洁,更易阅读:

def repeat(val){for(i in 0..5){println val}
}

设置范围

如果运行这个示例,可能会注意到一个小问题:“Hello World” 输出了六次而不是五次。这个问题有三种解决方法:
- 将包含的范围限制到 4:

for(i in 0..4)
  • 从 1 而不是 0 开始:
def repeat(val){for(i in 1..5){println val}
}
  • 将范围由包含改为排除:
def repeat(val){for(i in 0..<5){println val}
}

默认参数值

现在已经成功地使用 Groovy 的范围表达式缩短了 repeat 函数。但这个函数依然有些限制。如果想重复 “Hello World” 八次该怎么办?如果想对不同的值重复不同次数 – e.g. “Hello World” 重复八次,“Goodbye Sunshine” 重复两次,这时该怎么办?

每次调用 repeat 时都要指定需要的重复次数的做法已经过时了,特别是在已经适应了默认行为(重复五次)的时候。
Groovy 支持默认参数值,可以在函数或方法的正式定义中指定参数的默认值。调用函数的程序可以选择省略参数,使用默认值。

更加复杂的参数值

使用前面的 repeat 函数时,如果希望调用程序能够指定重复值, 可以:

def repeat(val, repeat=5){for(i in 0..<repeat){println val}
}

调用该函数:

repeat("Hello World", 2)
repeat("Goodbye sunshine", 4)
repeat("foo")

输出 “Hello World” 两次,“Goodbye sunshine” 四次,“foo” 五次(默认次数)


Groovy 集合

内置的 集合 – 回想一下在 Java 编程中是如何使用集合的 — 导入 java.util 类,初始化集合,将项加入集合。

而 Groovy 可以直接在语言内使用集合。在 Groovy 中,不需要导入专门的类,也不需要初始化对象。集合是语言本身的本地成员。Groovy 也使集合(或者列表)的操作变得非常容易,为增加和删除项提供了直观的帮助。

可以将范围当作集合

范围表达式 “0..4” 代表数字的集合— 0、1、2、3 和 4。为了验证这一点, 创建一个新类,将其命名为 Ranger。保留类定义和 main 方法定义。

def range = 0..4
println range.class
assert range instanceof List

注意, assert 命令用来证明范围是 java.util.List 的实例。接着运行这个代码,证实该范围现在是类型 List 的集合。

丰富的支持

Groovy 的集合支持相当丰富,美妙之处就在于,在 Groovy 的魔法背后,一切都是标准的 Java 对象。每个 Groovy 集合都是 java.util.Collection 或 java.util.Map 的实例。

Groovy 的语法提供了本地列表和映射; e.g. 将以下两行代码添加到 Ranger 类中

def coll = ["Groovy", "Java", "Ruby"]
assert coll instanceof Collection
assert coll instanceof ArrayList

coll 对象看起来很像 Java 语言中的数组。实际上,它是一个 Collection。
要在普通的 Java 代码中得到集合的相同实例,必须执行以下操作:

Collection<String> coll = new ArrayList<String>();
coll.add("Groovy");
coll.add("Java");
coll.add("Ruby");

在 Java 代码中,必须使用 add() 方法向 ArrayList 实例添加项。

添加项

Groovy 提供了许多方法可以将项添加到列表 — 可以使用 add() 方法(因为底层的集合是一个普通的 ArrayList 类型),但是还有许多快捷方式可以使用。

e.g. 下面的每一行代码都会向底层集合加入一些项:

coll.add("Python")
coll << "Smalltalk"
coll[5] = "Perl"

注意,Groovy 支持操作符重载 << 操作符被重载,以支持向集合添加项。还可以通过位置参数直接添加项。在这个示例中,由于集合中只有四个项,所以 [5] 操作符将 “Perl” 放在最后。请自行输出这个集合并查看效果。

检索非常轻松

如果需要从集合中得到某个特定项,可以通过像上面那样的位置参数获取项。e.g.如果想得到第二个项 “Java”,可以编写下面这样的代码(请记住集合和数组都是从 0 开始):

assert coll[1] == "Java"

Groovy 还允许在集合中增加或去掉集合

def numbers = [1,2,3,4]
assert numbers + 5 == [1,2,3,4,5]
assert numbers - [2,3] == [1,4]

注意,在上面的代码中, 实际上创建了新的 集合实例,由最后一行可以看出

魔法方法

Groovy 还为集合添加了其他一些方便的功能; e.g. 可以在集合实例上调用特殊的方法:

def numbers = [1,2,3,4]
assert numbers.join(",") == "1,2,3,4"
assert [1,2,3,4,3].count(3) == 2

join() 和 count() 只是在任何项列表上都可以调用的众多方便方法中的两个。分布操作符(spread operator) 是个特别方便的工具,使用这个工具不用在集合上迭代,就能够调用集合的每个项上的方法。

假设有一个 String 列表,想将列表中的项目全部变成大写:

assert ["JAVA", "GROOVY"] == ["Java", "Groovy"]*.toUpperCase()

注意 *. 标记。对于以上列表中的每个值,都会调用 toUpperCase(),生成的集合中每个 String 实例都是大写的。


Groovy 映射

除了丰富的列表处理功能,Groovy 还提供了坚固的映射机制。同列表一样,映射也是本地数据结构。而且 Groovy 中的任何映射机制在幕后都是 java.util.Map 的实例。

Java 语言中的映射

Java 语言中的映射是名称-值对的集合。所以,要用 Java 代码创建典型的映射,必须像下面这样操作:

Map<String, String>map = new HashMap<String, String>();
map.put("name", "Andy");
map.put("VPN-#","45");

HashMap 实例容纳两个名称-值对,每一个都是 String 的实例。

通过 Groovy 进行映射

Groovy 使得处理映射的操作像处理列表一样简单 — e.g. 可以用 Groovy 将上面的 Java 映射写成

def hash = [name:"Andy", "VPN-#":45]

注意,Groovy 映射中的键不必是 String。示例中,name 看起来像一个变量,但是在幕后,Groovy 会将它变成 String。

全都是 Java

创建一个新类 Mapper 并加入上面的代码。然后添加以下代码,以证实底层的代码是真正的 Java 代码:

assert hash.getClass() == java.util.LinkedHashMap

Groovy 使用了 Java 的 LinkedHashMap 类型,这意味着可以使用标准的 Java 一样语句对 hash 中的项执行 put 和 get 操作。

hash.put("id", 23)
assert hash.get("name") == "Andy"

有 groovy 特色的映射

Groovy 给任何语句都施加了魔法,所以可以用 . 符号将项放入映射中。如果想将新的名称-值对加入映射(e.g. dob 和 “01/29/76”),可以像下面这样操作:

hash.dob = "01/29/76"

. 符号还可以用来获取项。e.g. 使用以下方法可以获取 dob 的值:

assert hash.dob == "01/29/76"

要比调用 get() 方法更具 Groovy 特色。

位置映射

可以使用假的位置语法将项放入映射,或者从映射获取项目:

assert hash["name"] == "Andy"
hash["gender"] = "male"
assert hash.gender == "male"
assert hash["gender"] == "male"

请注意,在使用 [] 语法从映射获取项时,必须将项作为 String 引用


Groovy 中的闭包

不再需要更多迭代

虽然在前几节编写了不少集合代码,但还没有实际地在集合上迭代。当然,Groovy 就是 Java,所以如果愿意,那么总是能够得到 Java 的 Iterator 实例,用它在集合上迭代,就像下面这样:

def acoll = ["Groovy", "Java", "Ruby"]for(Iterator iter = acoll.iterator(); iter.hasNext();){println iter.next()
}

实际上在 for 循环中并不需要类型声明,因为 Groovy 已经将迭代转变为任何集合的直接成员。 示例中,不必获取 Iterator 实例并直接操纵它,可以直接在集合上迭代。而且,通常放在循环构造内的行为(例如 for 循环体中 println)接下来要放在闭包内。
在深入之前,先看看如何执行这步操作。

能否看见闭包?

对于上面的代码,可以用更简洁的方式对集合进行迭代

def acoll = ["Groovy", "Java", "Ruby"]acoll.each{println it
}

注意,each 直接在 acoll 实例内调用,而 acoll 实例的类型是 ArrayList。在 each 调用之后,引入了一种新的语法 – {,然后是一些代码,然后是 }。由 {} 包围起来的代码块就是闭包。

执行代码
闭包是可执行的代码块。它们不需要名称,可以在定义之后执行。所以,在上面的示例中,包含输出 it(后面将简单解释 it)的行为的无名闭包将会在 acoll 集合类型中的每个值上被调用。
在较高层面上,{} 中的代码会执行三次:

Groovy
Java
Ruby

闭包中的 it 变量是一个关键字,指向被调用的外部集合的每个值 – 它是默认值,可以用传递给闭包的参数覆盖它。
下面的代码执行同样的操作,但使用自己的项变量:

def acoll = ["Groovy", "Java", "Ruby"]acoll.each{ value ->println value
}

示例中,用 value 代替了 Groovy 的默认 it;

迭代无处不在

闭包在 Groovy 中频繁出现,但是,通常用于在一系列值上迭代的时候。
请记住,一系列值可以用多种方式表示,不仅可以用列表表示 – e.g.可以在映射、String、JDBC Rowset、File 的行上迭代,等等。

在前面一节 “Groovy 中的映射” 中的 hash 对象上迭代,可以编写以下代码:

def hash = [name:"Andy", "VPN-#":45]
hash.each{ key, value ->println "${key} : ${value}"
}

注意,闭包允许使用多个参数 – 示例中,上面的代码包含两个参数(key 和 value)

使用 Java 代码迭代

使用典型的 Java 构造如何进行同样的迭代

Map<String, String>map = new HashMap<String, String>();
map.put("name", "Andy");
map.put("VPN-#","45");for(Iterator iter = map.entrySet().iterator(); iter.hasNext();){Map.Entry entry = (Map.Entry)iter.next();System.out.println(entry.getKey() + " : " + entry.getValue());
}

代码比 Groovy 的代码长得多; ‘如果要处理大量集合,那么显然用 Groovy 处理会更方便。

迭代总结

记住,凡是集合或一系列的内容,都可以使用下面这样的代码进行迭代。

"ITERATION".each{println it.toLowerCase()
}

闭包的更多使用方式

虽然在迭代上使用闭包的机会最多,但闭包确实还有其他用途。
因为闭包是一个代码块,所以能够作为参数进行传递(Groovy 中的函数或方法不能这样做)。闭包在调用的时候才会执行这一事实(不是在定义的时候)使得它们在某些场合上特别有用。

e.g. 通过 Eclipse 创建一个 ClosureExample 对象,并保持它提供的默认类语法。在生成的 main() 方法中,添加以下代码:

def excite = { word ->return "${word}!!"
}

这段代码是名为 excite 的闭包。这个闭包接受一个参数(名为 word),返回的 String 是 word 变量加两个感叹号。
注意在 String 实例中替换 的用法。在 String 中使用 ${value}语法将告诉 Groovy 替换 String 中的某个变量的值。可以将这个语法当成 return word + “!!” 的快捷方式。

延迟执行

可以通过两种方法调用闭包:直接调用或者通过 call() 方法调用。

继续使用 ClosureExample 类,在闭包定义下面添加以下两行代码:

assert "Groovy!!" == excite("Groovy")
assert "Java!!" == excite.call("Java")

两种调用方式都能工作,但是直接调用的方法更简洁。
不要忘记闭包在 Groovy 中也是一类对象 – 既可以作为参数传递,也可以放在以后执行。用普通的 Java 代码可以复制同样的行为,但是不太容易。


Groovy 中的类

在 Groovy 中可以像在 Java 代码中一样定义类。惟一的区别是,不需要使用 public 修改符,而且还可以省略方法参数的类型。这一节将介绍使用 Groovy 类能够进行的其他所有操作。

Song 类

先从用 Groovy 定义一个简单的 JavaBean 形式的类开始,这个类称为 Song。

用 Groovy 创建名为 Song 的类。为它创建一个包结构 — 创建一个包名,e.g. org.acme.groovy。
创建这个类之后,删除 Groovy 插件自动生成的 main()。

歌曲有一些属性 — 创作歌曲的艺术家、歌曲名称、风格等等。请将这些属性加入新建的 Song 类

package org.acme.groovyclass Song {def namedef artistdef genre
}

Groovy 类就是 Java 类

本教程前面说过 Groovy 编译器为用 Groovy 定义的每个类都生成标准的 Java .class。还记得如何用 Groovy 创建 HelloWorld 类、找到 .class 文件并运行它么?
也可以用新定义的 Song 类完成同样的操作。如果通过 Groovy 的 groovyc 编译器编译代码(Eclipse Groovy 插件已经这样做了),就会生成一个 Song.class 文件。

这意味着,如果想在另一个 Groovy 类或 Java 类中使用新建的 Song 类,则必须导入 它(当然,除非使用 Song 的代码与 Song 在同一个包内)

创建一个新类,名为 SongExample,将其放在另一个包结构内,假设是 org.thirdparty.lib。

package org.thirdparty.libclass SongExample {static void main(args) {}
}

类的关系

首先导入实例,并将下面的代码添加到 SongExample 的 main() 方法中。

package org.thirdparty.libimport org.acme.groovy.Songclass SongExample {static void main(args) {def sng = new Song(name:"Le Freak", artist:"Chic", genre:"Disco")}
}

Song 实例创建完成了!但是仔细看看以前定义的 Song 类的初始化代码,是否注意到什么特殊之处?应该注意到自动生成了构造函数。

类初始化

Groovy 自动提供一个构造函数,构造函数接受一个名称-值对的映射,这些名称-值对与类的属性相对应。
这是 Groovy 的一项开箱即用的功能 – 用于类中定义的任何属性,Groovy 允许将存储了大量值的映射传给构造函数。映射的这种用法很有意义,e.g. 不用初始化对象的每个属性。

也可以添加下面这样的代码:

def sng2 = new Song(name:"Kung Fu Fighting", genre:"Disco")

也可以像下面这样直接操纵类的属性:

def sng3 = new Song()
sng3.name = "Funkytown"
sng3.artist = "Lipps Inc."
sng3.setGenre("Disco")assert sng3.getArtist() == "Lipps Inc."

代码中明显可以看出,Groovy 不仅创建了一个构造函数,允许传入属性及其值的映射,还可以通过 . 语法间接地访问属性。而且,Groovy 还生成了标准的 setter 和 getter 方法

在进行属性操纵时,非常有 Groovy 特色的是:总是会调用 setter 和 getter 方法 – 即使直接通过 . 语法访问属性也是如此。

核心的灵活性

Groovy 是一种本质上就很灵活的语言。
e.g. 看看从前面的代码中将 setGenre() 方法调用的括号删除之后会怎么样,如下所示:

sng3.setGenre "Disco"
assert sng3.genre == "Disco"

在 Groovy 中,对于接受参数的方法,可以省略括号 – 在某些方面,这样做会让代码更容易阅读。

方法覆盖

可以用以下命令输出一个实例:

println sng3

在 Java 中这样只会输出所有对象的默认 toString() 实现,也就是类名和它的 hashcode(即 org.acme.groovy.Song@44f787)
下面来看看如何覆盖默认的 toString() 实现,让输出效果更好。

String toString(){"${name}, ${artist}, ${genre}"
}

可以省略 toString() 方法上的 public 修改符。仍然需要指定返回类型(String),以便实际地覆盖正确的方法。方法体的定义很简洁 — 但 return 语句在哪?

不需要 return

在 Groovy 中可以省略 return 语句。Groovy 默认返回方法的最后一行。所以在这个示例中,返回包含类属性的 String。

重新运行 SongExample 类,toString() 方法返回一个描述,而不是 hashcode。

特殊访问

Groovy 的自动生成功能对于一些功能来说很方便,但有些时候需要覆盖默认的行为。e.g. 假设需要覆盖 Song 类中 getGenre() 方法,让返回的 String 全部为大写形式。

提供这个新行为很容易,只要定义 getGenre() 方法即可。可以让方法的声明返回 String,也可以完全省略它(如果愿意)。
下面的操作可能是最简单的:

def getGenre(){genre.toUpperCase()
}

同以前一样,这个简单方法省略了返回类型和 return 语句。现在再次运行 SongExample 类。应该会看到一些意外的事情 —— 出现了空指针异常。

空指针安全性

在 SongExample 类中有下面的代码:

assert sng3.genre == "Disco"

结果在重新运行 SongExample 时出现了断言错误 – 这正是为什么在 Eclipse 控制台上输出了红色文字;

幸运的是,可以轻松地修复这个错误:只要在 SongExample 类中添加以下代码:

println sng2.artist.toUpperCase()

现在控制台上出现了更多的 红色文本: 出什么事了?

可恶的 null

sng2 实例没有定义 artist 值。所以,在调用 toUpperCase() 方法时就会生成 Nullpointer 异常。
幸运的是, Groovy 通过 ? 操作符提供了一个安全网 – 在方法调用前面添加一个 ? 就相当于在调用前面放了一个条件,可以防止在 null 对象上调用方法。

e.g.将 sng2.artist.toUpperCase() 行替换成 sng2.artist?.toUpperCase()。请注意,也可以省略后面的括号。(Groovy 实际上也允许在不带参数的方法上省略括号。不过,如果 Groovy 认为您要访问类的属性而不是方法,那么这样做可能会造成问题。)

重新运行 SongExample 类,您会发现 ? 操作符很有用。在示例中,没有出现可恶的异常。现在将下面的代码放在这个类内,再次运行代码。

def sng4 = new Song(name:"Thriller", artist:"Michael Jackson")
println sng4

就是 Java

注意, 虽然预期可能有异常,但是没有生成异常。即使没有定义 genre,getGenre() 方法也会调用 toUpperCase()。

还记得 Groovy 就是 Java,对吧?所以在 Song 的 toString() 中,引用了 genre 属性本身,所以不会调用 getGenre()。现在更改 toString() 方法以使用 getGenre(),然后再看看程序运行的结果。

String toString(){"${name}, ${artist}, ${getGenre()}"
}

重新运行 SongExample,出现类似的异常。请自己尝试修复这个问题;

另一个方便的小操作符

进一步扩充了 Song 类的 getGenre() 方法,以利用 Groovy 中方便的 ? 操作符

def getGenre(){genre?.toUpperCase()
}

? 操作符时刻都非常有用,可以极大地减少条件语句


对 Groovy 进行单元测试

本教程一直都强调 Groovy 只是 Java 的一个变体。可以用 Groovy 编写并使用标准的 Java 程序。为了最后一次证明这点,在结束本教程之前,将通过 JUnit 利用 Java 对 Song 类进行单元测试。

将 JUnit 加入 Eclipse 项目

需要将 JUnit 加入到 Eclipse 项目中。右键单击项目 -> Build Path -> Add Libraries
选择 JUnit 并单击 Next 按钮。选择 JUnit3 或 4 - >Finish;

设置新的测试用例

右键单击 java 源文件夹 -> New -> JUnit Test Case。定义一个包,给测试用例命名(e.g. SongTest),在 Class Under Test 部分,单击 Browse 按钮。
请注意,可以选择用 Groovy 定义的 Song 类。

单击 OK, 在 New JUnit Test Case 对话框中单击 Finish;

定义测试方法

选择使用 JUnit 4;定义了一个名为 testToString() 的测试方法

package org.acme.groovy;import org.junit.Test;public class SongTest {@Testpublic void testToString(){}
}

测试 toString

需要验证 toString() 方法是否没有问题,Song 类在同一个包内,所以第一步是创建它的实例。

在创建用于测试的 Song 实例时,请注意不能通过传给构造函数的映射完全初始化 – 而且,如果想自动完成实例的 setter 方法,可以看到每个 setter 接受的是 Object 而不是 String;

Groovy 的功劳

回忆一下,就会记得我在本教程开始的时候说过:

因为 Java 中的每个对象都扩展自 java.lang.Object,所以即使在最坏情况下,Groovy 不能确定变量的类型,Groovy 也能将变量的类型设为 Object然后问题就会迎刃而解。

在定义 Song 类时,省略了每个属性的类型。Groovy 将自然地将每个属性的类型设为 Object。所以,在标准 Java 代码中使用 Song 类时,看到的 getter 和 setter 的参数类型和返回类型全都是 Object。

修正返回类型

打开 Groovy Song 类,将 artist 属性改为 String 类型,而不是无类型

package org.acme.groovyclass Song {def nameString artistdef genreString toString(){"${name}, ${artist}, ${getGenre()}"}def getGenre(){genre?.toUpperCase()}
}

回到 JUnit 测试,在 Song 实例上使用自动完成功能;
setArtist() 方法接受一个 String,而不是Object。Groovy 再次证明了它就是 Java,而且应用了相同的规则。

始终是普通的 Java

返回来编写测试,另外请注意,默认情况下 Groovy 编译的类属性是私有的,所以不能直接在 Java 中访问它们,必须像下面这样使用 setter:

@Test
public void testToString(){Song sng = new Song();sng.setArtist("Village People");sng.setName("Y.M.C.A");sng.setGenre("Disco");Assert.assertEquals("Y.M.C.A, Village People, DISCO", sng.toString());
}

测试用例很好地演示了这样一点:用 Groovy 所做的一切都可以轻易地在 Java 程序中重用,反之亦然。用 Java 语言执行的一切操作和编写的一切代码,在 Groovy 中也都可以使用。


结束语

Groovy 就是 Java,只是缺少了过去使用的许多语法规则。
Groovy 是没有类型、没有修改符、没有 return、没有 Iterator、不需要导入集合的 Java。
简而言之,Groovy 就是丢掉了许多包袱的 Java,这些包袱可能会压垮 Java 项目。

但是在幕后,Groovy 就是 Java。

作为有趣的练习,您可以试试用 Gant 设置下一个的自动构建版本,Gant 是基于 Ant 的构建工具,使用 Groovy 来定义构建,而不是使用 XML。
当对 Groovy 更加适应时,可以试着用 Groovy on Grails 构建 Web 应用程序模块;


参考资料


—End—
—YCR—

精通Groovy_B 循环, 范围, 集合, 映射, 闭包, 类, UT相关推荐

  1. java集合——映射表+专用集合映射表类

    [0]README 0.1) 本文描述转自 core java volume 1, 源代码为原创,旨在理解 java集合--映射表+专用集合映射表类 的相关知识: 0.2) for full sour ...

  2. 【Groovy】集合遍历 ( 使用集合的 collect 循环遍历集合并根据指定闭包规则生成新集合 | 代码示例 )

    文章目录 一.使用集合的 collect 循环遍历集合并根据指定闭包规则生成新集合 二.代码示例 一.使用集合的 collect 循环遍历集合并根据指定闭包规则生成新集合 调用集合的 collect ...

  3. 【APICloud系列|33】通过程序循环数据集合的时候闭包加入imageCache方法

    导读:一般实现的两种思路 1.通过程序循环数据集合的时候闭包加入imageCache方法. 2.通过递归数据集合实现 发现都不是我理想的效果,数据集合量较大的时候imageCache处理的时间比不用i ...

  4. Java高级-Lambda 表达式、异常处理、集合、泛型、List集合、Map集合、Collections类

    目录 Lambda 表达式 Java Lambda 表达式的优缺点 异常处理 Exception 处理及常见异常 try catch语句 try catch finally语句 throws 声明异常 ...

  5. c++怎么将两个类的方法集合成一个类的方法_一文帮你梳理 Java 集合

    集合在我们日常开发使用的次数数不胜数,ArrayList/LinkedList/HashMap/HashSet······信手拈来,抬手就拿来用,在 IDE 上龙飞凤舞,但是作为一名合格的优雅的程序猿 ...

  6. (10)Java泛型-Map集合-集合框架工具类-可变参数-静态导入

    -- 部分1.5新特性Java泛型-Map集合-集合框架工具类 泛型 概述: JDK1.5版本以后出现的新特性,用于解决安全问题,是一个类型安全机制. 对于泛型可以这样理解: 没有使用泛型时,只要是对 ...

  7. 【Groovy】集合遍历 ( 使用集合的 reverseEach 方法进行遍历 | 倒序集合迭代器 ReverseListIterator 类简介 | 代码示例 )

    文章目录 一.使用集合的 reverseEach 方法进行倒序遍历 二.倒序集合迭代器 ReverseListIterator 类简介 三.代码示例 一.使用集合的 reverseEach 方法进行倒 ...

  8. 【Groovy】集合遍历 ( 使用 for 循环遍历集合 | 使用集合的 each 方法遍历集合 | 集合的 each 方法返回值分析 )

    文章目录 一.使用 for 循环遍历集合 二.使用 each 方法遍历集合 三.集合的 each 方法返回值分析 四.完整代码示例 一.使用 for 循环遍历集合 使用 for 循环 , 遍历集合 , ...

  9. 文件映射操作类的实现

    文章目录 1 文件映射操作类的实现 1 文件映射操作类的实现 mmap_file_op.h: #ifndef QINIU_LARGEFILE_MMAPFILE_OP_H_ #define QINIU_ ...

最新文章

  1. verilog 移位运算符 说明_Verilog学习笔记基本语法篇(二)·········运算符...
  2. php报内存溢出,php为什么运行了一段时间后才报内存溢出?
  3. stm32关定时器_STM32F103ZET6的基本定时器
  4. 判断java String中是否有汉字的方法
  5. Windows 下使用 MinGW 和 CMake 进行开发
  6. HDFS 上传文件的不平衡,Balancer问题是过慢
  7. 如何区分abcd类地址_ip地址abc类怎么区分
  8. preg_match_all() 函数
  9. QTableView结构及用法
  10. C++11常见编译与链接错误解决总结
  11. QT 5.9.5的快捷键操作
  12. oracle expdp jobname,【EXPDP/IMPDP】数据泵 job_name参数的使用
  13. 【折腾系列—All In One主机】3、 iKuai软路由安装前的设置
  14. 使用脚本配置odbc mysql_LoadRunner利用ODBC编写MySql脚本
  15. Python编程快速上手让繁琐工作自动化中文高清完整版PDF带书签
  16. vivi采集php,php源码:VIVI万能小偷程序1.5 智能采集不求人(内置2条采集规则)
  17. 关于我们-找学术会议,上MeetConf!科研人都在看的学术会议网站
  18. 上海亚商投顾:沪指缩量跌0.44% 医药股全线反弹
  19. 国有企业内部审计浅议
  20. python中beautifulsoup是什么,Python Beautiful Soup简介

热门文章

  1. 【爱生活】新冠 - 风寒和风热感冒的区别及措施
  2. edk2中的fdf文件简介
  3. \xe5\x8d\xa0\xe7\x94\xa8\xe3\x80\x82,16进制乱码转化为可读字符
  4. Collections中Counter函数,namedtuple函数,defaultdict函数的使用
  5. 高考助力海报|有哪些优秀的高考助力文案?
  6. matplotlib中的imshow()绘图长宽比例失调,调整长宽比(备忘)
  7. PT_常见的连续型分布/均匀分布/指数分布/柯西分布/正态分布
  8. 100base - CX/FX/LX/SX/ZX
  9. 美国计算机专业gre314,美国东北大学计算机专业CS硕士录取
  10. android蓝牙hid 鼠标,BLE HID协议-----蓝牙鼠标代码流分析