??xml version="1.0" encoding="utf-8" standalone="yes"?>日本久久电影网,日韩国产一区二,精品一区二区三区中文字幕http://www.aygfsteel.com/ljc-java/category/49290.html模仿中成长,在创C成功Q?/description>zh-cnThu, 04 Aug 2011 07:21:25 GMTThu, 04 Aug 2011 07:21:25 GMT60实战 Groovy: for each 剖析(转蝲)http://www.aygfsteel.com/ljc-java/archive/2011/08/04/355737.htmlThu, 04 Aug 2011 03:50:00 GMThttp://www.aygfsteel.com/ljc-java/archive/2011/08/04/355737.htmlhttp://www.aygfsteel.com/ljc-java/comments/355737.htmlhttp://www.aygfsteel.com/ljc-java/archive/2011/08/04/355737.html#Feedback0http://www.aygfsteel.com/ljc-java/comments/commentRss/355737.htmlhttp://www.aygfsteel.com/ljc-java/services/trackbacks/355737.html

q代是编E的基础。您l常会遇到需要进行逐项遍历的内容,比如 List?code>File ?JDBC ResultSet。Java 语言几乎L提供了某U方法帮助您逐项遍历所需的内容,但o人沮丧的是,它ƈ没有l出一U标准方法。Groovy 的P代方法非常实用,在这一点上QGroovy ~程?Java ~程截然不同。通过一些代码示例,本文介l?Groovy 的万能的 each() ҎQ从而将 Java 语言的那些P代怪癖抛在脑后?

Java q代{略

假设您有一?Java ~程语言?java.util.List。清?1 展示了在 Java 语言中如何用编E实现P代:


清单 1. Java 列表q代
import java.util.*;  
public class ListTest{
 public static void main(String[] args){
 List<String> list = new ArrayList<String>();
 list.add("Java");
 list.add("Groovy");
 list.add("JavaScript");
 for(Iterator<String> i = list.iterator(); i.hasNext();){
 String language = i.next();
 System.out.println("I know " + language);
 }
 }
 }

׃提供了大部分集合c都可以׃n?java.lang.Iterable 接口Q您可以使用相同的方法遍?java.util.Set ?java.util.Queue?

关于本系?/h2>

Groovy 是一ƾ运行在 Java q_之上的现代编E语a。它能够与现?Java 代码无缝集成Q同时引入了闭包和元~程{出色的新特性。简而言之,Groovy cM?21 世纪?Java 语言?

如果要将新工具集成到开发工L中,最关键的是理解什么时候需要用它以及什么时候不适合使用它。Groovy 可以变得非常强大Q但前提是它被适当地应用到合适的场景中。因此, 实战 Groovy pd旨在展示 Groovy 的实际用,以及何时和如何成功应用它?

现在Q假设该语言存储?java.util.Map 中。在~译Ӟ试?Map 获取 Iterator 会导致失?— Map q没有实?Iterable 接口。幸q的是,可以调用 map.keySet() q回一?SetQ然后就可以l箋处理。这些小差异可能会媄响您的速度Q但不会妨碍您的前进。需要注意的是,List?code>Set ?Queue 实现?IterableQ但?Map 没有 — 即它们位于相同?java.util 包中?

现在假设该语a存在?String 数组中。数l是一U数据结构,而不是类。不能对 String 数组调用 .iterator()Q因此必M用稍微不同的q代{略。您再一ơ受到阻,但可以用如清单 2 所C的Ҏ解决问题Q?


清单 2. Java 数组q代
public class ArrayTest{
 public static void main(String[] args){
 String[] list = {"Java", "Groovy", "JavaScript"};
 for(int i = 0; i < list.length; i++){
 String language = list[i];
 System.out.println("I know " + language);
 }
 }
 }

但是{一?— 使用 Java 5 引入?for-each 语法怎么P它可以处理Q何实?Iterable 的类和数l,如清?3 所C:


清单 3. Java 语言?for-each q代
import java.util.*;
 public class MixedTest{
 public static void main(String[] args){
 List<String> list = new ArrayList<String>();
 list.add("Java");
 list.add("Groovy");
 list.add("JavaScript");
 for(String language: list){
 System.out.println("I know " + language);
 }
String[] list2 = {"Java", "Groovy", "JavaScript"};
 for(String language: list2){
 System.out.println("I know " + language);
 }
 }
 }

因此Q您可以使用相同的方法遍历数l和集合Q?code>Map 除外Q。但是如果语a存储?java.io.FileQ那该怎么办?如果存储?JDBC ResultSetQ或者存储在 XML 文档?code>java.util.StringTokenizer 中呢Q面Ҏ一U情况,必须使用一U稍有不同的q代{略。这样做q不是有什么特D目?— 而是因ؓ不同?API 是由不同的开发h员在不同的时期开发的 — 但事实是Q您必须了解 6 ?Java q代{略Q特别是使用q些{略的特D情c?

Eric S. Raymond 在他?The Art of Unix Programming 一书中解释? “最意外原?#8221;。他写道Q?#8220;要设计可用的接口Q最好不要设计全新的接口模型。新鲜的东西L难以入门Q会为用户带来学习的负担Q因此应当尽量减新?宏V?#8221;Groovy 对P代的态度正是采纳?Raymond 的观炏V在 Groovy 中遍历几乎Q何结构时Q您只需要?each() q一U方法?


Groovy 中的列表q代

首先Q我?清单 3 中的 List 重构?Groovy。在q里Q只需要直接对列表调用 each() Ҏq传递一个闭包,而不是将 List 转换?for 循环Q顺便提一句,q样做ƈ不是特别h面向对象的特征,不是吗)?

创徏一个名?listTest.groovy 的文件ƈd清单 4 中的代码Q?/p>
清单 4. Groovy 列表q代
def list = ["Java", "Groovy", "JavaScript"] list.each{language->   println language } 

清单 4 中的W一行是 Groovy 用于构徏 java.util.ArrayList 的便捯法。可以将 println list.class d到此脚本来验证这一炏V接下来Q只需对列表调?each()Qƈ在闭包体内输?language 变量。在闭包的开始处使用 language-> 语句命名 language 变量。如果没有提供变量名QGroovy 提供了一个默认名U?it。在命o行提C符中输?groovy listTest q行 listTest.groovy?/p>

清单 5 是经q简化的 清单 4 代码版本Q?/p>
清单 5. 使用 Groovy ?it 变量的P?/strong>
 // shorter, using the default it variable 
def list = ["Java", "Groovy", "JavaScript"]
 list.each{ println it }
 // shorter still, using an anonymous
list ["Java", "Groovy", "JavaScript"].each{ println it }

Groovy 允许您对数组?List 交替使用 each() Ҏ。ؓ了将 ArrayList 改ؓ String 数组Q必d as String[] d到行末,如清?6 所C:


清单 6. Groovy 数组q代
def list = ["Java", "Groovy", "JavaScript"] as String[] list.each{println it} 

?Groovy 中普遍?each() ҎQƈ?getter 语法非常便捷Q?code>getClass() ?class 是相同的调用Q,q您能够编写既z又富有表达性的代码。例如,假设您希望利用反显C给定类的所有公共方法。清?7 展示了这个例子:


清单 7. Groovy 反射
def s = "Hello World"
 println s
println s.class
 s.class.methods.each{println it}
 //output:
$ groovy reflectionTest.groovy
 Hello World
 class java.lang.String
 public int java.lang.String.hashCode()
 public volatile int java.lang.String.compareTo(java.lang.Object)
 public int java.lang.String.compareTo(java.lang.String)
 public boolean java.lang.String.equals(java.lang.Object) ...

脚本的最后一行调?getClass() Ҏ?code>java.lang.Class 提供了一?getMethods() ҎQ后者返回一个数l。通过这些操作串qv来ƈ?Method 的结果数l调?each()Q您只用了一行代码就完成了大量工作?

但是Q与 Java for-each 语句不同的是Q万能的 each() Ҏq不仅限?List 和数l。在 Java 语言中,故事到此l束。然而,?Groovy 中,故事才刚刚开始?

Map q代

从前文可以看刎ͼ?Java 语言中,无法直接q代 Map。在 Groovy 中,q完全不是问题,如清?8 所C:


清单 8. Groovy map q代
def map = ["Java":"server", "Groovy":"server", "JavaScript":"web"] map.each{ println it } 

要处理名U?值对Q可以用隐式的 getKey() ?getValue() ҎQ或在包的开头部分显式地命名变量Q如清单 9 所C:


清单 9. ?map 获得键和?/strong>
def map = ["Java":"server", "Groovy":"server", "JavaScript":"web"]
 map.each{
 println it.key
 println it.value
 }
map.each{k,v->
 println k
 println v
 }

可以看到QP?Map 和P代其它Q何集合一栯然?

在l研I下一个P代例子前Q应当了?Groovy 中有?Map 的另一个语法。与?Java 语言中调?map.get("Java") 不一P可以化对 map.Java 的调用,如清?10 所C:


清单 10. 获得 map ?/strong>
def map = ["Java":"server", "Groovy":"server", "JavaScript":"web"]
 //identical results
 println map.get("Java")
 println map.Java

不可否认QGroovy 针对 Map 的这U便捯法非帔RQ但q也是在?Map 使用反射时引起一些常见问题的原因。对 list.class 的调用将生成 java.util.ArrayListQ而调?map.class q回 null。这是因?map 元素的便h法覆盖了实际?getter 调用?code>Map 中的元素都不h class 键,因此调用实际会返?nullQ如清单 11 的示例所C:


清单 11. Groovy map ?null
def list = ["Java", "Groovy", "JavaScript"]
 println list.class
 // java.util.ArrayList
 def map = ["Java":"server", "Groovy":"server", "JavaScript":"web"]
 println map.class
 // null
 map.class = "I am a map element"
 println map.class
 // I am a map element
 println map.getClass()
 // class
 java.util.LinkedHashMap

q是 Groovy 比较|见的打?“最意外原?#8221; 的情况,但是׃?map 获取元素要比使用反射更加常见Q因此我可以接受q一例外?/p>


String q代

现在您已l熟?each() Ҏ了,它可以出现在所有相关的位置。假设您希望q代一?StringQƈ且是逐一q代字符Q那么马上可以?each() Ҏ。如清单 12 所C:


清单 12. String q代
def name = "Jane Smith" name.each{letter->
 println letter
 }

q提供了所有的可能性,比如使用下划U替代所有空|如清?13 所C:


清单 13. 使用下划U替代空?/strong>

def name = "Jane Smith"
 println "replace spaces"
name.each{
 if(it == " "){
 print "_"
 }else{
 print it
 }
 }
 // output Jane_Smith

当然Q在替换一个单个字母时QGroovy 提供了一个更加简z的替换Ҏ。您可以清?13 中的所有代码合qؓ一行代码:"Jane Smith".replace(" ", "_")。但是对于更复杂?String 操作Q?code>each() Ҏ是最佳选择?


Range q代

Groovy 提供了原生的 Range cdQ可以直接P代。用两个点分隔的所有内容(比如 1..10Q都是一?Range。清?14 展示了这个例子:


清单 14. Range q代
def range = 5..10 range.each{
 println it
 }
 //output: 5 6 7 8 9 10

Range 不局限于单的 Integer。考虑清单 15 在的代码Q其中P?Date ?RangeQ?


清单 15. Date q代
def today = new Date()
 def nextWeek = today + 7
 (today..nextWeek).each{
 println it
 }
//output: Thu Mar 12 04:49:35 MDT 2009
 Fri Mar 13 04:49:35 MDT 2009
Sat Mar 14 04:49:35 MDT 2009
Sun Mar 15 04:49:35 MDT 2009
Mon Mar 16 04:49:35 MDT 2009
Tue Mar 17 04:49:35 MDT 2009
Wed Mar 18 04:49:35 MDT 2009
Thu Mar 19 04:49:35 MDT 2009

可以看到Q?code>each() 准确地出现在您所期望的位|。Java 语言~Z原生?Range cdQ但是提供了一个类似地概念Q采?enum 的Ş式。毫不奇怪,在这?each() 仍然z־上用场?/p>


Enumeration cd

Java enum 是按照特定顺序保存的随意的值集合。清?16 展示?each() Ҏ如何自然地配?enumQ就好象它在处理 Range 操作W一P


清单 16. enum q代
enum DAY{
 MONDAY, TUESDAY, WEDNESDAY, THURSDAY,
 FRIDAY, SATURDAY, SUNDAY
 }
 DAY.each{
 println it
 }
 (DAY.MONDAY..DAY.FRIDAY).each{
 println it
 }

?Groovy 中,有些情况下,each() q个名称q未能表辑֮的强大功能。在下面的例子中Q将看到使用特定于所用上下文的方法对 each() Ҏq行修饰。Groovy eachRow() Ҏ是一个很好的例子?


SQL q代

在处理关pL据库表时Q经怼?“我需要针对表中的每一行执行操?#8221;。比较一下前面的例子。您很可能会?“我需要对列表中的每一U语a执行一些操?#8221;。根据这个道理,groovy.sql.Sql 对象提供了一?eachRow() ҎQ如清单 17 所C:


清单 17. ResultSet q代
import groovy.sql.*
 def sql = Sql.newInstance(
 "jdbc:derby://localhost:1527/MyDbTest;create=true",
 "username",
 "password",
 "org.apache.derby.jdbc.ClientDriver")
 println("grab a specific field")
 sql.eachRow("select name from languages"){ row ->
 println row.name
 }
 println("grab all fields")
 sql.eachRow("select * from languages"){ row ->
 println("Name: ${row.name}")
 println("Version: ${row.version}")
 println("URL: ${row.url}\n")
 }

该脚本的W一行代码实例化了一个新?Sql 对象Q设|?JDBC q接字符丌Ӏ用户名、密码和 JDBC 驱动器类。这Ӟ可以调用 eachRow() ҎQ传?SQL select 语句作ؓ一个方法参数。在闭包内部Q可以引用列名(name?code>version?code>urlQ,好像实际存?getName()?code>getVersion() ?getUrl() Ҏ一栗?

q显然要?Java 语言中的{效Ҏ更加清晰。在 Java 中,必须创徏单独?DriverManager?code>Connection?code>Statement ?JDBCResultSetQ然后必d嵌套?try/catch/finally 块中它们全部清除?

对于 Sql 对象Q您会认?each() ?eachRow() 都是一个合理的Ҏ名。但是在接下来的CZ中,我想您会认ؓ each() q个名称q不能充分表辑֮的功能?


文gq代

我从未想q用原始的 Java 代码逐行遍历 java.io.File。当我完成了所有的嵌套?BufferedReader ?FileReader 后(更别提每个流E末所有异常处理)Q我已经忘记最初的目的是什么?

清单 18 展示了?Java 语言完成的整个过E:


清单 18. Java 文gq代
import java.io.BufferedReader;
 import java.io.FileNotFoundException;
 import java.io.FileReader; import java.io.IOException;
 public class WalkFile {
 public static void main(String[] args) {
 BufferedReader br = null;
 try {
 br = new BufferedReader(new FileReader("languages.txt"));
 String line = null;
 while((line = br.readLine()) != null) {
 System.out.println("I know " + line);
 }
 }
 catch(FileNotFoundException e) {
 e.printStackTrace();
 }
 catch(IOException e) {
 e.printStackTrace();
 }
 finally {
 if(br != null) {
 try {
 br.close();
 }
catch(IOException e) {
 e.printStackTrace();
 }
 }
 }
 }
 }

清单 19 展示?Groovy 中的{效q程Q?


清单 19. Groovy 文gq代
def f = new File("languages.txt") f.eachLine{language->
 println "I know ${language}"
}

q正?Groovy 的简z性真正擅长的斚w。现在,我希望您了解Z么我?Groovy UCؓ “Java E序员的 DSL”?

注意Q我?Groovy ?Java 语言中同时处理同一?java.io.File cR如果该文g不存在,那么 Groovy 代码抛出和 Java 代码相同?FileNotFoundException 异常。区别在于,Groovy 没有已检的异常。在 try/catch/finally 块中装 eachLine() l构是我自己的爱?— 而不是一语a需求。对于一个简单的命o行脚本中Q我ƣ赏 清单 19 中的代码的简z性。如果我在运行应用服务的同时执行相同的P代,我不能对q些异常坐视不管。我在?Java 版本相同?try/catch 块中装 eachLine() 块?

File cd each() Ҏq行了一些修攏V其中之一是 splitEachLine(String separator, Closure closure)。这意味着您不仅可以逐行遍历文gQ同时还可以它分ؓ不同的标记。清?20 展示了一个例子:


清单 20. 分解文g的每一?
// languages.txt
 // notice the space between the language and the version Java 1.5 Groovy 1.6 JavaScript 1.x
 // splitTest.groovy
def f = new File("languages.txt")
 f.splitEachLine(" "){words->
 words.each{ println it
 }
 }
// output Java 1.5 Groovy 1.6 JavaScript 1.x

如果处理的是二进制文ӞGroovy q提供了一?eachByte() Ҏ?

当然QJava 语言中的 File q不L一个文?— 有时是一个目录。Groovy q提供了一?each() 修改以处理子目录?


目录q代

使用 Groovy 代替 shell 脚本Q或批处理脚本)非常ҎQ因为您能够方便地访问文件系l。要获得当前目录的目录列表,参见清单 21Q?/p>
清单 21. 目录q代
def dir = new File(".") dir.eachFile{file->
 println file
 }

eachFile() Ҏ同时q回了文件和子目录。?Java 语言?isFile() ?isDirectory() ҎQ可以完成更复杂的事情。清?22 展示了一个例子:


清单 22. 分离文g和目?/strong>
def dir = new File(".") dir.eachFile{file->
 if(file.isFile()){
 println "FILE: ${file}"
 }else if(file.isDirectory()){
 println "DIR: ${file}"
 }else{
 println "Uh, I'm not sure what it is..."
 }
 }

׃两种 Java Ҏ都返?boolean |可以在代码中d一?Java 三元操作W。清?23 展示了一个例子:


清单 23. 三元操作W?/strong>
def dir = new File(".")
 dir.eachFile{file->
 println file.isDirectory() ? "DIR: ${file}" : "FILE: ${file}"
 }

如果只对目录有兴,那么可以使用 eachDir() 而不?eachFile()。还提供?eachDirMatch() ?eachDirRecurse() Ҏ?

可以看到Q对 File 仅?each() Ҏq不能提供够的含义。典?each() Ҏ的语义保存在 File 中,但是Ҏ名更h描述性,从而提供更多有兌个高U功能的信息?


URL q代

理解了如何遍?File 后,可以使用相同的原则遍?HTTP h的响应。Groovy ?java.net.URL 提供了一个方便的Q和熟悉的)eachLine() Ҏ?

例如Q清?24 逐行遍历 ibm.com 主页?HTMLQ?


清单 24. URL q代
def url = new URL("http://www.ibm.com")
 url.eachLine{line->
 println line
 }

当然Q如果这是您的目的的话QGroovy 提供了一个只包含一行代码的解决办法Q这主要归功?toURL() ҎQ它被添加到所?StringsQ?code>"http://www.ibm.com".toURL().eachLine{ println it }?

但是Q如果希望对 HTTP 响应执行一些更有用的操作,该怎么办呢Q具体来Ԍ如果发出的请求指向一?RESTful Web 服务Q而该服务包含您要解析?XMLQ该怎么做呢Q?code>each() Ҏ在q种情况下提供帮助?


XML q代

您已l了解了如何Ҏ件和 URL 使用 eachLine() Ҏ。XML l出了一个稍微有些不同的问题 — 与逐行遍历 XML 文档相比Q您可能更希望对逐个元素q行遍历?

例如Q假设您的语a列表存储在名?languages.xml 的文件中Q如清单 25 所C:


清单 25. languages.xml 文g
<langs>
 <language>Java</language>
 <language>Groovy</language>
 <language>JavaScript</language>
 </langs>

Groovy 提供了一?each() ҎQ但是需要做一些修攏V如果用名?XmlSlurper 的原?Groovy c解?XMLQ那么可以?each() 遍历元素。参见清?26 所C的例子Q?


清单 26. XML q代
def langs = new XmlSlurper().parse("languages.xml")
 langs.language.each{
 println it
 }
 //output Java Groovy JavaScript

langs.language.each 语句从名?<language> ?<langs> 提取所有元素。如果同时拥?<format> ?<server> 元素Q它们将不会出现?each() Ҏ的输Z?/p>

如果觉得q还不够的话Q那么假设这?XML 是通过一?RESTful Web 服务的Ş式获得,而不是文件系l中的文件。用一?URL 替换文g的\径,其余代码仍然保持不变Q如清单 27 所C:


清单 27. Web 服务调用?XML q代
def langs = new XmlSlurper().parse("http://somewhere.com/languages")
 langs.language.each{
 println it
 }

q真是个好方法,each() Ҏ在这里用得很好,不是吗?


l束?/a>

在?each() Ҏ的整个过E中Q最妙的部分在于它只需要很的工作可以处理大?Groovy 内容。解?each() Ҏ之后QGroovy 中的q代易如反掌了。正?Raymond 所_q正是关键所在。一旦了解了如何遍历 ListQ那么很快就会掌握如何遍历数l?code>Map?code>String?code>Range?code>enum、SQL ResultSet?code>File、目录和 URLQ甚x XML 文档的元素?

本文的最后一个示例简单提C?XmlSlurper 实现 XML 解析。在下一期文章中Q我l讨个问题,q展CZ?Groovy q行 XML 解析有多么简单!您将看到 XmlParser ?XmlSlurper 的实际用,q更好地了解 Groovy Z么提供两个类g又略有不同的cd?XML 解析。到那时Q希望您能发?Groovy 的更多实际应用?



2011-08-04 11:50 发表评论
]]>
վ֩ģ壺 غ| ī񹤿| ֥| Ѿ| ˫Ѽɽ| | | | | IJ| | | | ͷ| | | | | ߺ| | | | ʡ| ԭ| | Т| տ| Ϻӿ| | ʷ| | ˮ| | | ij| | | Ƶ| Ͱ| Զ| ˮ|