keep moving!

          We must not cease from exploration. And the end of all our exploring will be to arrive where we began and to know the place for the first time.
          隨筆 - 37, 文章 - 2, 評(píng)論 - 3, 引用 - 0
          數(shù)據(jù)加載中……

          [轉(zhuǎn)載] Groovy 1.5的新特性

          作者 Guillaume Laforge譯者 曹云飛 發(fā)布于 2008年1月15日 下午11時(shí)12分

          Groovy
          ,針對(duì)JVM的類Java動(dòng)態(tài)語言,如陳年好酒一樣成熟了。在2007年1月成功地發(fā)布了Groovy 1.0之后,下一個(gè)主要的里程碑1.5版已經(jīng)發(fā)布。在1.5版中有一些有趣而新穎的地方,我們會(huì)在這篇文章中考察這些特性。語言主要增強(qiáng)了對(duì)于Java 5特征的支持,包括注解、泛型和枚舉,這使得Groovy成為對(duì)于JVM完全支持的框架的唯一候選動(dòng)態(tài)語言,框架包括Spring,Hibernate,JPA,Goole Guice或者TestNG。除了新的Java 5特性,Groovy還在語言中增加了新的語法增強(qiáng),以及更強(qiáng)大的動(dòng)態(tài)特性定制,一個(gè)基于steroids的Swing UI構(gòu)建器以及改進(jìn)的工具支持。

          相關(guān)廠商內(nèi)容

          免費(fèi)迷你書下載:深入淺出Struts 2

          活動(dòng):體驗(yàn)基于OpenSolaris的Web/企業(yè)應(yīng)用(8.30 杭州)

          SOY Framework:Java富客戶端快速開發(fā)框架

          Hadoop中的集群配置和使用技巧

          免費(fèi)迷你書下載:Grails入門指南

          相關(guān)贊助商

          InfoQ中文站Java社區(qū),關(guān)注企業(yè)Java社區(qū)的變化與創(chuàng)新,通過新聞、文章、視頻訪談和演講以及迷你書等為中國Java技術(shù)社區(qū)提供一流資訊。

          為什么一個(gè)更加groovyGroovy是很重要的

          Groovy的關(guān)鍵賣點(diǎn)始終是它與Java的無縫集成。你能夠很容易地把Groovy和Java的類混合搭配:你可以讓一個(gè)Java類實(shí)現(xiàn)一個(gè)Groovy接口,然后讓一個(gè)Groovy類繼承那個(gè)Java類,或者相反。不幸的是,絕大多數(shù)其他的候選的JVM語言不能讓你無縫的在兩種不同的語言之間交換類。因此,如果你希望為工作使用最好的語言而不放棄優(yōu)美的類的層次結(jié)構(gòu),你沒有太多的選擇,而Groovy使得你可以自由的將兩種語言以幾乎透明的方式集成在一起。

          Groovy與Java共享同樣的庫,同樣的對(duì)象模型,同樣的線程模型,同樣的安全模型。在某種意義上,你可以認(rèn)為Groovy是你的Java項(xiàng)目的一個(gè)實(shí)現(xiàn)細(xì)節(jié),而不必忍受阻抗失配問題

          Groovy就是Java,而且Groovy使得Java更groovy了。與其他語言相比,Groovy對(duì)于Java開發(fā)者無疑提供了最平滑的學(xué)習(xí)曲線,這得益于兩者非常相似的語法。

          需要牢記的是Groovy產(chǎn)生的是正常的Java字節(jié)碼而且使用普通的JDK庫,所以你不需要學(xué)習(xí)全部的新的API而且不需要復(fù)雜的集成機(jī)制:極其方便,Groovy和Java是可以相互交換的。附加的好處是你可以保護(hù)對(duì)你的Java開發(fā)人員Java技巧方面的投資,或者是昂貴的應(yīng)用服務(wù)器,或者第三方的或者公司自己開發(fā)的庫,你可以在Groovy中毫無問題地重用他們。

          其他不支持強(qiáng)類型的候選語言,在調(diào)用JDK、第三方庫或者公司自己的庫的時(shí)候,由于它們不能辨別同一方法的某一多態(tài)變種,所以始終不能調(diào)用所有的Java方法。當(dāng)你選擇一種語言來提高你的生產(chǎn)率或者使你的代碼可讀性更強(qiáng)的時(shí)候,如果你需要調(diào)用其他Java類,你必須非常謹(jǐn)慎的選擇語言,因?yàn)榭赡軙?huì)碰到很多麻煩。

          今天,所有主要的企業(yè)框架都需要使用注解、枚舉或者泛型這樣的語言特性來充分提高它們的效率。幸運(yùn)的是,開發(fā)者使用Groovy1.5的話就可以在他們的項(xiàng)目中使用所有的Java 5特性并因此而獲益。讓我們看看在Groovy中如何使用注解,枚舉和泛型。

          Java 5增加的部分

          Groovy編譯器始終產(chǎn)生與以前的Java VM兼容的Java字節(jié)碼,但是由于Groovy使用了JDK1.4的核心庫,所以Groovy依賴于JDK1.4。然而,對(duì)于這些Java 5中增加的部分,肯定需要使用Java 5的字節(jié)碼。例如,產(chǎn)生的類中也許包含代表著運(yùn)行時(shí)保留策略注解的字節(jié)碼信息。所以,雖然Groovy1.5能夠在JDK1.4上運(yùn)行,但是某些Groovy的特征只能在JDK1.5上使用 —— 出現(xiàn)這種情況時(shí),本文會(huì)作出聲明。

          可變的參數(shù)

          在Java 5中創(chuàng)建了省略號(hào)表示法,代表方法的參數(shù)是可變長度的。通過三個(gè)小圓點(diǎn),Java允許用戶在一個(gè)方法的末端輸入相同類型的任意數(shù)量的參數(shù) —— 實(shí)際上,可變長度參數(shù)(vararg)就是一個(gè)那種類型的元素的數(shù)組。可變長度參數(shù)在Groovy 1.0中已經(jīng)出現(xiàn)了 —— 現(xiàn)在仍然可以在JDK1.4運(yùn)行時(shí)環(huán)境下工作,1.0足以向你展示如何來使用他們了。基本上,只要當(dāng)一個(gè)方法的最后一個(gè)參數(shù)是一個(gè)對(duì)象數(shù)組,或者是一個(gè)有三個(gè)點(diǎn)的參數(shù),你就可以向這個(gè)方法傳入多重參數(shù)。

          第一個(gè)例子介紹了在Groovy中用省略號(hào)來使用可變長度變量的方法:

          int sum(int... someInts) {
          def total = 0
          for (int i = 0; i < someInts.size(); i++)
          total += someInts[i]
          return total
          }
          assert sum(1)       == 1
          assert sum(1, 2)    == 3
          assert sum(1, 2, 3) == 6

          這個(gè)例子中所用的斷言顯示了我們?nèi)绾蝹魅肴我舛嗟膇nt類型的參數(shù)。還有一個(gè)有趣的地方,為了更好的兼容Java語法,Java中經(jīng)典的循環(huán)方式也加入了Groovy中 —— 盡管在groovy中更有groovy特色的循環(huán)是用in關(guān)鍵字,同樣可以透明地遍歷各種各樣的數(shù)組或者集合類型。

          請(qǐng)注意使用一個(gè)數(shù)組作為最后一個(gè)參數(shù)同樣可以支持可變長度變量,就像下面這樣聲明方法:

          int sum(int[] someInts) { /* */ }

          這個(gè)代碼片斷是非常無聊的。很明顯有很多更有表現(xiàn)力的方式來計(jì)算一個(gè)總和。例如,如果你有一個(gè)數(shù)字的列表,你可以在一行代碼中計(jì)算他們的總和:

          assert [1, 2, 3].sum() == 6

          Groovy中可變長度變量不需要JDK 5作為基本的Java運(yùn)行時(shí)環(huán)境,在下面的章節(jié)中我們要介紹的注解則需要JDK 5。

          注解

          正如在JBoss Seam的文檔中所介紹的那樣,Seam支持使用Groovy來寫Seam的實(shí)體,控制器和組件,類似@Entity,@Id,@Override以及其他的注解可以用來修飾你的bean:

          @Entity
          @Name("hotel")
          class Hotel implements Serializable
          {
          @Id @GeneratedValue
          Long id
          @Length(max=50) @NotNull
          String name
          @Length(max=100) @NotNull
          String address
          @Length(max=40) @NotNull
          String city
          @Length(min=2, max=10) @NotNull
          String state
          @Length(min=4, max=6) @NotNull
          String zip
          @Length(min=2, max=40) @NotNull
          String country
          @Column(precision=6, scale=2)
          BigDecimal price
          @Override
          String toString() {
          return "Hotel(${name}, ${address}, ${city}, ${zip})"
          }
          }

          Hotel實(shí)體用@Entity注解來標(biāo)識(shí),用@Name給了它一個(gè)名字。可以向你的注解傳遞不同的參數(shù),例如在@Length注解約束中,為了做有效性檢查可以給注解設(shè)置不同的上界和下界。在實(shí)例中你還會(huì)注意到Groovy的屬性:getter方法和setter方法都到哪里去了?公有或者私有的修飾符在哪里?你不必等待Java 7或者Java 8來獲得屬性!在Groovy中,按照慣例,定義一個(gè)屬性非常簡單:String country:這樣就會(huì)自動(dòng)生成一個(gè)私有的country成員變量,同時(shí)生成一個(gè)公有的getter和setter方法。你的代碼自然而然的變得簡潔而易讀

          Groovy中,注解可以象在Java中一樣用在類、成員變量、方法和方法參數(shù)上。但是,有兩個(gè)很容易犯錯(cuò)誤的地方需要小心。第一,你可以在Groovy中用注解,可是你不能定義它們 —— 然而,在一個(gè)快要到來的Groovy版本中將可以定義注解。第二,雖然Groovy的語法幾乎與Java的語法100%相同,但是在注解中傳入一個(gè)數(shù)組作為參數(shù)時(shí)還是有一點(diǎn)點(diǎn)不同:Groovy不是用圓括號(hào)來括起元素,而是需要使用方括號(hào),目的是為了提供更一致的語法 —— 在Groovy中列表和數(shù)組都用方括號(hào)來括起他們的元素。

          通過Groovy1.5中的注解,你可以在Groovy中方便地為JPA或者Hibernate定義你的的帶注解的bean

          http://www.curious-creature.org/2007/03/25/persistence-made-easy-with-groovy-and-jpa/),在你的Spring服務(wù)上增加一個(gè)@Transactional 注解,使用TestNG和Fest來測試你的Swing UI(http://www.jroller.com/aalmiray/entry/testing_groovy_uis_with_fest)。在Groovy項(xiàng)目中你可以使用所有支持注解的有用而強(qiáng)大的企業(yè)框架。

          枚舉

          當(dāng)你需要一組固定數(shù)量的相同類型的常量時(shí),枚舉是很方便的。例如你需要一種干凈的方式來為日期定義常量而不借助使用整數(shù)常量,那么枚舉是你的好幫手。下面的片斷顯示了如何定義一星期中的日子:

          enum Day {
          SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
          THURSDAY, FRIDAY, SATURDAY
          }

          一旦你定義了你的枚舉,你可以在Java中以通常的記法Day.MONDAY來使用它,還可以使用枚舉來潤色你的switch/case語句:

          def today = Day.SATURDAY
          switch (today) {
          // Saturday or Sunday
          case [Day.SATURDAY, Day.SUNDAY]:
          println "Weekends are cool"
          break
          // a day between Monday and Friday
          case Day.MONDAY..Day.FRIDAY:
          println "Boring work day"
          break
          default:
          println "Are you sure this is a valid day?"
          }

          請(qǐng)注意Groovy的switch語句比類似C風(fēng)格語言的switch語句要強(qiáng)大一些,在Groovy中可以在switch和case語句使用任何類型的對(duì)象。不用為每一個(gè)枚舉值羅列七個(gè)不同的case語句塊,你可以在列表或者ranges(Groovy集合類的一種類型)中重新分組case語句:當(dāng)值出現(xiàn)在列表或者range中,case將為真而且會(huì)執(zhí)行它關(guān)聯(lián)的命令。

          受到Java教程的啟示,這里是一個(gè)更復(fù)雜的關(guān)于天文學(xué)的例子,向你展示了在枚舉中如何包含屬性,構(gòu)造器和方法:

          enum Planet {
          MERCURY (3.303e+23, 2.4397e6),
          VENUS   (4.869e+24, 6.0518e6),
          EARTH   (5.976e+24, 6.37814e6),
          MARS    (6.421e+23, 3.3972e6),
          JUPITER (1.9e+27,   7.1492e7),
          SATURN  (5.688e+26, 6.0268e7),
          URANUS  (8.686e+25, 2.5559e7),
          NEPTUNE (1.024e+26, 2.4746e7)
          double mass
          double radius
          Planet(double mass, double radius) {
          this.mass = mass;
          this.radius = radius;
          }
          void printMe() {
          println "${name()} has a mass of ${mass} " +
          "and a radius of ${radius}"
          }
          }
          Planet.EARTH.printMe()

          與注解一樣,由于產(chǎn)生了Java 5的字節(jié)碼,Groovy中的枚舉需要JDK 5+的環(huán)境才能運(yùn)行,

          靜態(tài)導(dǎo)入

          在前面關(guān)于枚舉的例子中,我們始終需要在枚舉值的前面加上它的父枚舉類,但是通過靜態(tài)導(dǎo)入(可以在JDK1.4運(yùn)行時(shí)環(huán)境上工作)我們可以去掉Planet前綴,從而節(jié)省一些字符。

          import static Planet.*
          SATURN.printMe()

          這樣就不再需要Planet前綴。當(dāng)然,靜態(tài)導(dǎo)入不僅僅對(duì)枚舉有效,對(duì)其他類和靜態(tài)成員變量同樣有效。我們不妨作些數(shù)學(xué)計(jì)算。

          import static java.lang.Math.*
          assert sin(PI / 6) + cos(PI / 3) == 1

          java.lang.Math的靜態(tài)方法和靜態(tài)常量都被靜態(tài)導(dǎo)入了,這樣使得表達(dá)式更加簡明。但是如果sine和cosine的縮寫不便于你閱讀,那么你可以使用Groovy中的as關(guān)鍵字來做別名:

          import static java.lang.Math.PI
          import static java.lang.Math.sin as sine
          import static java.lang.Math.cos as cosine
          assert sine(PI / 6) + cosine(PI / 3) == 1

          別名不僅僅用于靜態(tài)導(dǎo)入,也可以用于正常的導(dǎo)入,是很有用的方法。例如在很多框架中有名字非常長的類,可以使用別名來增加快捷記法,或者重命名名字不太直觀的方法或者常量,或者重命名與你的命名約定標(biāo)準(zhǔn)不一致的方法或常量。

          泛型

          在Java 5中有爭議的特性:泛型,也出現(xiàn)在Groovy 1.5的最新版本中。畢竟,開始的時(shí)候可能覺得在一個(gè)動(dòng)態(tài)語言中加入更多類型信息是多余的。Java開發(fā)人員通常相信因?yàn)轭愋筒脸榱讼蚝蠹嫒軯ava以前的版本)使得在類的字節(jié)碼中沒有保留代表泛型的類型信息。然而,這是錯(cuò)誤的看法,通過反射API,你可以內(nèi)省一個(gè)類從而發(fā)現(xiàn)它的成員變量類型或者它的有泛型詳細(xì)信息的方法參數(shù)類型。

          例如,當(dāng)你聲明了類型為List的成員變量時(shí),這個(gè)信息是在字節(jié)碼的某個(gè)地方以某種元信息的方式保存的,盡管這個(gè)成員變量確實(shí)僅僅是List類型的。這種反射信息被諸如JPA或者Hibernate這樣的企業(yè)框架所使用,將一個(gè)元素的集合中的實(shí)體關(guān)聯(lián)到代表這些元素的類型的實(shí)體。
          為了實(shí)踐這些理論,讓我們檢查泛型信息是否保存在類的成員變量中。

          class Talk {
          String title
          }
          class Speaker {
          String name
          List talks = []
          }
          def me = new Speaker(
          name: 'Guillaume Laforge',
          talks: [
          new Talk(title: 'Groovy'),
          new Talk(title: 'Grails')
          ])
          def talksField =  me.class.getDeclaredField('talks')
          assert talksField.genericType.toString() ==
           'java.util.Listt'

          我們定義了兩個(gè)類:一個(gè)在會(huì)議上給出Talk的Speaker類。在Speaker類中,talks屬性的類型是List。然后,我們創(chuàng)建了一個(gè)Speaker實(shí)例,用兩個(gè)優(yōu)美的捷徑來初始化name和talks屬性,并創(chuàng)建了一個(gè)Talk實(shí)例的列表。當(dāng)初始化代碼就緒后,我們?nèi)〉么韙alks的成員變量,然后檢查泛型信息是否正確:正確!talks是一個(gè)List,但是它是一個(gè)TalkList

          共變的返回類型

          在Java 5中,如果你在一個(gè)子類中有一個(gè)方法,其名稱與參數(shù)類型與父類中的方法相同,但是返回值是父類方法的返回值的子類,那么我們可以覆蓋父類的方法。在Groovy1.0中,不支持共變的返回類型。但是在Groovy1.5中,你可以使用共變返回類型。而且,如果你試圖覆蓋一個(gè)方法而返回類型不是父類方法的返回類型的子類,將拋出一個(gè)編譯錯(cuò)誤。共變的返回類型對(duì)于參數(shù)化的類型同樣有效。

          除了因?yàn)橹С諮ava 5的特性而給Groovy語言帶來了一些增強(qiáng)外,Groovy1.5還引入了其他一些語法的增強(qiáng),我們在下面的章節(jié)中會(huì)探索這些部分。

          增加的語法

          Elvis操作符

          Java 5的特性除了帶給Groovy注解,泛型和枚舉,還增加了一個(gè)新操作符—— ?:,Elivis操作符。當(dāng)你看這個(gè)操作符的時(shí)候,你很容易猜測為什么會(huì)這樣命名 —— 如果不是,可以根據(jù)Smiley來思考。這個(gè)新操作符實(shí)際上是一個(gè)三目操作符的便捷記法。你是否經(jīng)常使用三目操作符來改變一個(gè)變量的值?如果它是null那么給它分配一個(gè)缺省值。在Java中典型的情況是這樣的:

          String name = "Guillaume";
          String displayName = name != null ? name : "Unknown";

          Groovy中,由于語言本身可以按需“強(qiáng)制”類型轉(zhuǎn)換到布爾值(例如在if或者while構(gòu)造中條件表達(dá)式需要為布爾值),在這個(gè)語句中,我們可以忽略和null的比較,因?yàn)楫?dāng)一個(gè)String是null的時(shí)候,它被強(qiáng)制轉(zhuǎn)換為false,所以在Groovy中語句會(huì)變?yōu)椋?/p>

          String name = "Guillaume"
          String displayName = name ? name : "Unknown"

          然而,你仍然會(huì)注意到name變量的重復(fù),這破壞了DRY原則(不要重復(fù)你自己 Don't Repeat Yourself)。由于這個(gè)構(gòu)造非常普遍,所以引入了Elvis操作符來簡化這些重復(fù)的現(xiàn)象,語句變成:

          String name = "Guillaume"
          String displayName = name ?: "Unknown"

          name變量的第二次出現(xiàn)被簡單的忽略了,三目操作符不再是三目的了,縮短為這種更簡明的形式。

          還有一點(diǎn)值得注意的是這個(gè)新的構(gòu)造沒有副作用,由于第一個(gè)元素(這里是name)不會(huì)象在三目操作符中那樣被估值兩次,所以不需要引入一個(gè)中間的臨時(shí)變量來保持三目操作符中第一個(gè)元素的第一次估值。

          經(jīng)典的循環(huán)

          雖然Groovy嚴(yán)格地來說不是100%的Java的超集,但是在每一個(gè)Groovy的新版本中,其語法都更接近Java的語法,在Groovy中越來越多的Java代碼是有效的。這種兼容性的好處是當(dāng)你開始用Groovy工作時(shí),你可以拷貝并粘貼Java代碼到你的Groovy類中,它們會(huì)如你所愿地工作。然后,隨著時(shí)間的推移你學(xué)習(xí)了Groovy語言,你可以扔掉那些從Java拷貝來的在Groovy中不地道的代碼,使用GStrings(內(nèi)插字符串),或者閉包等等。Groovy為Java開發(fā)者提供了一個(gè)非常平滑的學(xué)習(xí)曲線。

          然而,Groovy中有一處忽略了Java語法的兼容性,實(shí)際上Groovy中不允許使用從Java語言的C背景繼承而來的經(jīng)典的循環(huán)語法。最初,Groovy開發(fā)者認(rèn)為經(jīng)典的循環(huán)語法不是最好的,他們更喜歡使用可讀性更好的for/in構(gòu)造。但是由于Groovy用戶經(jīng)常要求Groovy包含這個(gè)舊的循環(huán)構(gòu)造,所以Groovy團(tuán)隊(duì)決定支持它。

          Groovy 1.5中,你可以選擇Groovy的for/in構(gòu)造,或者經(jīng)典的for循環(huán)構(gòu)造:

          for (i in 0..9)
          println i
          for (int i = 0; i < 10; i++)
          println i

          最終,這也許只是品味不同,Groovy的熟手用戶通常更喜歡for/in循環(huán)這樣更加簡明的語法。

          沒有圓括號(hào)的命名參數(shù)

          由于易適應(yīng)且簡明的語法,以及高級(jí)的動(dòng)態(tài)能力,Groovy是實(shí)現(xiàn)內(nèi)部領(lǐng)域特定語言(Domain-Specific Languages)的理想選擇。當(dāng)你希望在業(yè)務(wù)問題專家和開發(fā)者之間共享一種公共的比喻說法的時(shí)候,你可以借Groovy之力來創(chuàng)建一個(gè)專用的商業(yè)語言,用該語言為你的應(yīng)用的關(guān)鍵概念和商業(yè)規(guī)則建模。這些DSL的一個(gè)重要方面是使得代碼非常可讀,而且讓非技術(shù)人員更容易寫代碼。為了更進(jìn)一步實(shí)現(xiàn)這個(gè)目標(biāo),Groovy的語法做了通融,允許我們使用沒有圓括號(hào)括起來的命名參數(shù)。

          首先,在Groovy中命名參數(shù)看起來是這樣的:

          fund.compare(to: benchmarkFund, in: euros)
          compare(fund: someFund, to: benchmark, in: euros)

          通過向數(shù)字加入新的屬性 —— 這在Groovy中是可能的,但是超出了這篇文章的范圍 —— 我們可以寫出像這樣的代碼:

          monster.move(left: 3.meters, at: 5.mph)

          現(xiàn)在通過忽略圓括號(hào),代碼變得更清晰了:

          fund.compare to: benchmarkFund, in: euros
          compare fund: someFund, to: benchmark, in: euros
          monster.move left: 3.meters, at: 5.mph

          顯然,這沒有很大的區(qū)別,但是每個(gè)語句變得更接近淺白的英語句子,而且在宿主語言中刪除了通常冗余的技術(shù)代碼。Groovy語言這個(gè)小小的增強(qiáng)給予了商業(yè)DSL設(shè)計(jì)人員更多的選擇。

          改善的工具支持

          當(dāng)Groovy還不成熟的時(shí)候,一個(gè)常見的弱點(diǎn)是缺乏好的工具支持:工具系列和IDE支持都不到位。幸運(yùn)的是,隨著Groovy和Grails web框架的成熟和成功,這種狀況得到了改變。

          “聯(lián)合”編譯器的介紹

          Groovy以它與Java的透明而且無縫的集成而聞名。但是這不僅僅意味著在Groovy腳本中可以調(diào)用Java方法,不,兩個(gè)語言之間的集成遠(yuǎn)不止于此。例如,一個(gè)Groovy類繼承一個(gè)Java類,而該Java類實(shí)現(xiàn)一個(gè)Groovy接口是完全可能的,反之亦然。不幸的是,其他候選語言不支持這樣做。然而,到目前為止,當(dāng)把Groovy和Java混合起來使用的時(shí)候,你在編譯時(shí)要小心選擇正確的編譯順序,如果兩個(gè)語言中出現(xiàn)循環(huán)依賴,那么你也許會(huì)碰到一個(gè)“雞與蛋”的問題。幸運(yùn)的是在Groovy 1.5中這不再是問題,謝謝獲獎(jiǎng)的Java IDE IntelliJ IDEA的創(chuàng)建者JetBrains的一個(gè)貢獻(xiàn),你可以使用一個(gè)“聯(lián)合”編譯器將Groovy和Java代碼放在一起一次編譯而不必考慮類之間的依賴關(guān)系。

          如果你希望在命令行使用聯(lián)合編譯器,你可以像通常那樣調(diào)用groovyc命令,但是使用-j參數(shù)來進(jìn)行聯(lián)合編譯:

          groovyc *.groovy *.java -j -Jsource=1.4 -Jtarget=1.4

          為了向基本的javac命令傳遞參數(shù),你可以用J作為參數(shù)的前綴。你還可以在你的Ant或者M(jìn)aven構(gòu)建文件中使用聯(lián)合編譯器執(zhí)行Ant任務(wù):

          <taskdef name="groovyc"
          classname="org.codehaus.groovy.ant.Groovyc"
          classpathref="my.classpath"/>
          <groovyc
          srcdir="${mainSourceDirectory}"
          destdir="${mainClassesDirectory}"
          classpathref="my.classpath"
          jointCompilationOptions="-j -Jsource=1.4 -Jtarget=1.4" />

          Groovy的Maven插件

          對(duì)于Maven用戶,在Codehaus有一個(gè)全特性的Maven插件項(xiàng)目允許你構(gòu)建自己的Java/Groovy應(yīng)用:編譯你的Groovy和Java代碼,從JavaDoc標(biāo)簽生成文檔,甚至允許你在Groovy中開發(fā)自己的Maven插件。還有一個(gè)Maven的原型可以更迅速的引導(dǎo)你的Groovy項(xiàng)目。要得到更多信息,你可以參考插件的文檔:http://mojo.codehaus.org/groovy/index.html

          GroovyDoc文檔工具

          作為一個(gè)Java開發(fā)人員,你習(xí)慣于通過你的類,接口,成員變量或者方法的注釋中的JavaDoc標(biāo)簽來生成代碼文檔。在Groovy中,你仍然可以在你的注釋中使用這樣的標(biāo)簽,使用一個(gè)叫做GroovyDoc的工具為你所有的Groovy類生成與JavaDoc同樣的文檔。

          這里有一個(gè)Ant任務(wù),你可以定義并用它來產(chǎn)生文檔:

          <taskdef name="groovydoc"
          classname="org.codehaus.groovy.ant.Groovydoc">
          <classpath>
          <path path="${mainClassesDirectory}"/>
          <path refid="compilePath"/>
          </classpath>
          </taskdef>
          <groovydoc
          destdir="${docsDirectory}/gapi"
          sourcepath="${mainSourceDirectory}"
          packagenames="**.*" use="true"
          windowtitle="Groovydoc" private="false"/>

          新的交互性shell和Swing控制臺(tái)

          Groovy的發(fā)行版本總是包含兩個(gè)不同的shell:一個(gè)命令行shell和一個(gè)Swing控制臺(tái)。命令行shell,Groovysh,就其與用戶的交互性而言從來都不是很友好:當(dāng)你希望執(zhí)行一個(gè)語句的時(shí)候,你不得不在每個(gè)語句后面鍵入“go”或者“execute”,這樣才能執(zhí)行。為了某些快速的原型開發(fā)或者試用一些新的API,每次都鍵入“go”是非常累贅的。在Groovy 1.5中情況變化了,有了新的交互式的shell。不再需要鍵入“go”。

          這個(gè)新的shell有幾個(gè)增強(qiáng)的特性,例如使用了提供ANSI著色的JLine庫,tab命令補(bǔ)全,行編輯能力。你可以與不同的腳本緩沖器工作,記住已經(jīng)導(dǎo)入的類,裝載現(xiàn)存的腳本,將當(dāng)前腳本保存到一個(gè)文件中,瀏覽歷史記錄,等等。欲得到shell所支持特性的更詳細(xì)解釋,請(qǐng)參閱文檔

          不僅僅命令行shell得到了提高,Swing控制臺(tái)也有改進(jìn),有了新的工具條,先進(jìn)的undo能力,可以增大或者縮小字體,語法高亮等,總之,控制臺(tái)有了很多提高。

          IntelliJ IDEA JetGroovy 插件

          JetGroovy插件是最棒的工具支持:一個(gè)免費(fèi)而且開源的專用于支持Groovy和Grails的IntelliJ IDEA插件。這個(gè)插件是由JetBrains他們自己開發(fā)的,對(duì)于語言和Web框架都提供了無以倫比的支持。

          插件對(duì)Groovy有專門的支持,其中部分特性:

          • 對(duì)于所有的語法都可以語法高亮,對(duì)于未識(shí)別的類型加不同的警告。
          • 可以運(yùn)行Groovy類,腳本和用Groovy寫的JUnit測試用例。
          • 調(diào)試器:你可以一步一步地運(yùn)行你的Java和Groovy代碼,設(shè)置斷點(diǎn),顯示變量,當(dāng)前的堆棧信息等等。
          • 聯(lián)合編譯器:編譯器Groovy和Java一起編譯,可以解決語言之間的依賴問題。
          • 代碼補(bǔ)全,可以補(bǔ)全包,類,屬性,成員變量,變量,方法,關(guān)鍵字,甚至對(duì)于Swing UI builder有特殊的支持。
          • 先進(jìn)的類搜索和發(fā)現(xiàn)功能。
          • 重構(gòu):大多數(shù)在Java中你所喜愛的常用重構(gòu)功能都可以在Java和Groovy中使用,例如“surround with”,介紹、內(nèi)聯(lián)或者重命名一個(gè)變量,重命名包、類、方法和成員變量。
          • 導(dǎo)入優(yōu)化和代碼格式化。
          • 結(jié)構(gòu)視圖:對(duì)你的類有一個(gè)鳥瞰視圖。

          最終,考慮到在IntelliJ IDEA中提供的支持和相互影響的程度,你甚至不會(huì)意識(shí)到你是在Groovy中還是在Java中開發(fā)一個(gè)類。如果你正在考慮在你的Java項(xiàng)目中增加一些Groovy或者你打算開發(fā)Grails應(yīng)用,這個(gè)插件是肯定要安裝的。

          你可以在JetBrains站點(diǎn)得到更多信息。

          盡管我僅僅表揚(yáng)了IntelliJ IDEA的Groovy插件,但是你不必因此改變你的Groovy開發(fā)習(xí)慣。你可以使用由IBM的Zero項(xiàng)目開發(fā)者持續(xù)改進(jìn)的Eclipse插件,或者Sun的NetBeans的Groovy和Grails插件。

          性能提高

          Groovy的新版本除了增加新特性,與以前的版本相比還顯著地提高了性能,并且降低了內(nèi)存消耗。在我們的非正式的基準(zhǔn)測試中,我們發(fā)現(xiàn)與Groovy 1.5 beta版相比我們所有測試套件的運(yùn)行速度有了15%到45%的提高 —— 與Groovy 1.0相比肯定有更多的提高。雖然還需要開發(fā)更正式的基準(zhǔn)測試,但是一些開發(fā)人員已經(jīng)證實(shí)了這些測試數(shù)字,一家保險(xiǎn)公司的開發(fā)人員正在使用Groovy來寫他們的策略風(fēng)險(xiǎn)計(jì)算引擎的商業(yè)規(guī)則,另一個(gè)公司在高并發(fā)機(jī)器上運(yùn)行了多個(gè)測試。總的來說,Groovy在絕大多數(shù)情況下會(huì)更快,更輕盈。不過在具體的應(yīng)用中,效果還要看你如何使用Groovy

          增強(qiáng)的動(dòng)態(tài)能力

          由于Groovy和Grails項(xiàng)目的共生關(guān)系,Grails核心部分中成熟的動(dòng)態(tài)能力已經(jīng)被引入到Groovy中。

          Groovy是一個(gè)動(dòng)態(tài)語言:簡單的說,這意味著某些事情,例如方法分派發(fā)生在運(yùn)行時(shí),而不是象Java和其他語言那樣發(fā)生在編譯時(shí)。在Groovy中有一個(gè)特殊的運(yùn)行時(shí)系統(tǒng),叫做MOP(元對(duì)象協(xié)議Meta-Object Protocol),負(fù)責(zé)方法分派邏輯。幸運(yùn)的是,這個(gè)運(yùn)行時(shí)系統(tǒng)非常開放,人們可以深入系統(tǒng)并且改變系統(tǒng)的通常行為。對(duì)于每一個(gè)Java類和每一個(gè)Groovy實(shí)例,都有一個(gè)與之相關(guān)聯(lián)的元類(meta-class)代表該對(duì)象的運(yùn)行時(shí)行為。Groovy為你與MOP交互提供了幾種不同的方法,可以定制元類,可以繼承某些基類,但是謝謝Grails項(xiàng)目的貢獻(xiàn),有一種更groovy的元類:expando元類。

           

          代碼例子可以幫助我們更容易地理解概念。在下面的例子中,字符串msg的實(shí)例有一個(gè)元類,我們可以通過metaClass屬性訪問該元類。然后我們改變String類的元類,為其增加一個(gè)新方法,為toUpperCase()方法提供一個(gè)速記記法。之后,我們?yōu)樵惖膗p屬性分配一個(gè)閉包,這個(gè)屬性是在我們把閉包分配給它的時(shí)候創(chuàng)建的。這個(gè)閉包沒有參數(shù)(因此它以一個(gè)箭頭開始),我們在閉包的委托之上調(diào)用toUpperCase()方法,這個(gè)委托是一個(gè)特殊的閉包變量,代表著真實(shí)的對(duì)象(這里是String實(shí)例)。

          def msg = "Hello!"
          println msg.metaClass
          String.metaClass.up = { -> delegate.toUpperCase() }
          assert "HELLO!" == msg.up()

          通過這個(gè)元類,你可以查詢對(duì)象有哪些方法或者屬性:

          // print all the methods
          obj.metaClass.methods.each { println it.name }
          // print all the properties
          obj.metaClass.properties.each { println it.name }

          你甚至可以檢查某個(gè)特定的方法或者屬性是否可用,比使用instanceof來檢查的粒度要小的多:

          def msg = 'Hello!'
          if (msg.metaClass.respondsTo(msg, 'toUpperCase')) {
          println msg.toUpperCase()
          }
          if (msg.metaClass.hasProperty(msg, 'bytes')) {
          println  foo.bytes.encodeBase64()
          }

          這些機(jī)制在Grails web框架中得到了廣泛的使用,例如創(chuàng)建一個(gè)動(dòng)態(tài)查找器:由于你可以在一個(gè)Book領(lǐng)域類上調(diào)用一個(gè)findByTitle()動(dòng)態(tài)方法,所以在大多數(shù)情況下不需要DAO類。通過元類,Grails自動(dòng)為領(lǐng)域類加入了這樣的方法。此外,如果被調(diào)用的方法不存在,在第一次調(diào)用的時(shí)候方法會(huì)被創(chuàng)建并緩存。這可以由下面解釋的其他高級(jí)技巧來完成。

           

          除了我們已經(jīng)看到的例子,expando元類也提供了一些補(bǔ)充的功能。在一個(gè)expando元類中可以加入四個(gè)其他方法:

          • invokeMethod() 讓你可以攔截所有的方法調(diào)用,
          • methodMissing() 僅僅在沒有發(fā)現(xiàn)其他方法的時(shí)候被調(diào)用。
          • get/setProperty() 攔截對(duì)所有屬性的訪問,
          • propertyMissing()在沒有發(fā)現(xiàn)屬性的時(shí)候被調(diào)用。

          與以前的Groovy版本相比,通過expando元類可以更容易定制你的應(yīng)用行為,并且節(jié)約昂貴的開發(fā)時(shí)間。很明顯,不是每個(gè)人都需要使用這些技術(shù),但是在許多場合這些技術(shù)是很方便的,例如你想應(yīng)用某些AOP(面向方面的編程Aspect Oriented Techniques)來裝飾你的類,或者想通過刪除某些不必要的冗余代碼來簡化你的應(yīng)用的商業(yè)邏輯代碼并使其可讀性更強(qiáng)。

          Steroids之上的Swing

          Groovy項(xiàng)目有一個(gè)天才的Swing開發(fā)者團(tuán)隊(duì),他們努力工作使得在Groovy中用Swing來構(gòu)建用戶界面的能力更強(qiáng)大。在Groovy中構(gòu)建Swing UI的基石是SwingBuilder類:在你的代碼中,你可以在語法級(jí)別可視化的看到Swing組件是如何彼此嵌套的。Groovy web站點(diǎn)的一個(gè)過分簡單的例子顯示了如何簡單地創(chuàng)建一個(gè)小的GUI程序:

          import groovy.swing.SwingBuilder
          import java.awt.BorderLayout
          import groovy.swing.SwingBuilder
          import java.awt.BorderLayout as BL
          def swing = new SwingBuilder()
          count = 0
          def textlabel
          def frame = swing.frame(title:'Frame', size:[300,300]) {
          borderLayout()
          textlabel = label(text:"Clicked ${count} time(s).",
          constraints: BL.NORTH)
          button(text:'Click Me',
          actionPerformed: {count++; textlabel.text =
          "Clicked ${count} time(s)."; println "clicked"},
          constraints:BorderLayout.SOUTH)
          }
          frame.pack()
          frame.show()

          Swing構(gòu)建器的概念已經(jīng)擴(kuò)展到提供定制的組件工廠。有一些不是缺省包含在Groovy中的附加模塊,它們把JIDE或者SwingX項(xiàng)目中的Swing組件集成到Swing構(gòu)建器代碼中。

          在這個(gè)版本中,界面部分有很多改進(jìn),值得用一整篇文章來敘述。我僅僅列出其中一部分,例如bind()方法。受到JSR (JSR-295)的bean綁定(beans binding)的啟發(fā),你可以很容易地將組件或者bean綁定到一起,使得它們在對(duì)方發(fā)生變化的時(shí)候作出反應(yīng)。在下面的例子中,按鈕的間隔尺寸會(huì)根據(jù)滾動(dòng)條組件的值的變化而變化。

          import groovy.swing.SwingBuilder
          import java.awt.Insets
          swing = new SwingBuilder()
          frame = swing.frame {
          vbox {
          slider(id: 'slider', value:5)
          button('Big Button?!', margin:
          bind(source: slider,
          sourceProperty:'value',
          converter: { [it, it, it, it] as Insets }))
          }
          }
          frame.pack()
          frame.size = [frame.width + 200, frame.height + 200]
          frame.show()

          在構(gòu)建用戶界面的時(shí)候?qū)⒔M件綁定在一起是非常常見的任務(wù),所以這個(gè)任務(wù)通過綁定機(jī)制被簡化了。還可以使用其他的自動(dòng)綁定方法,但是需要一篇專門的文章來闡述。

          在其他新的值得注意的特性中,新增了一些方便的方法,使得閉包可以調(diào)用聲名狼籍的SwingUtilities類,啟動(dòng)新的線程:edt()將調(diào)用invokeAndWait()方法, doLater()將會(huì)調(diào)用invokeLater()方法,doOutside()方法會(huì)在一個(gè)新線程中啟動(dòng)一個(gè)閉包。不再有丑陋的匿名內(nèi)部類:只要通過這些便捷方法使用閉包就可以!

          最后但是也最重要的是,由于SwingBuilder的build()方法,分離視圖的描述與它相關(guān)聯(lián)的行為邏輯變成再簡單不過的事情了。你可以創(chuàng)建一個(gè)僅僅包含視圖的單獨(dú)的腳本,而與組件的交互或者綁定都在主類中,在MVC模式中可以更清晰的分離視圖與邏輯部分。

          總結(jié)

          這篇文章列出了Groovy 1.5中引人注目的新特性,但是我們僅僅觸及了Groovy這個(gè)新版本的皮毛。重要的亮點(diǎn)主要圍繞著Java 5的新特性,例如注解、枚舉或者泛型:這使得Groovy可以完美地與諸如Spring、Hibernate或者JPA這樣的企業(yè)框架優(yōu)美而無縫的集成。得益于改進(jìn)的語法以及增強(qiáng)的動(dòng)態(tài)能力,Groovy讓你能夠創(chuàng)建內(nèi)嵌的領(lǐng)域特定語言來定制你的商業(yè)邏輯,并在應(yīng)用的擴(kuò)展點(diǎn)將其方便地集成進(jìn)來。由于工具支持的大幅改善,開發(fā)者的體驗(yàn)有了顯著的提高,開發(fā)體驗(yàn)不再是采用Groovy的一個(gè)障礙。總的來說,Groovy 1.5前所未有的滿足了簡化開發(fā)者生活的目標(biāo),Groovy應(yīng)該成為所有Java開發(fā)者工具箱的一部分。

          關(guān)于作者

          Guillaume Laforge是Groovy的項(xiàng)目經(jīng)理和JSR-241規(guī)范的領(lǐng)導(dǎo)者,Java規(guī)范請(qǐng)求(Java Specification Request)在Java社區(qū)過程(Java Community Process)中標(biāo)準(zhǔn)化了Groovy語言。他還是Technology的副主席以及G2One, Inc.的核心創(chuàng)建者,該公司資助并領(lǐng)導(dǎo)著Groovy和Grails項(xiàng)目的發(fā)展。Guillaume經(jīng)常在不同的會(huì)議談?wù)?strong style="color: black; background-color: #ffff66">Groovy和Grails,例如JavaOne,JavaPolis,Sun TechDays,Spring Experience,Grails eXchange。

          查看英文原文What's New in Groovy 1.5

          posted on 2008-08-31 21:00 大石頭 閱讀(980) 評(píng)論(0)  編輯  收藏 所屬分類: Groovy


          只有注冊用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 雷山县| 宁海县| 乌鲁木齐市| 维西| 古浪县| 拉萨市| 专栏| 双鸭山市| 常宁市| 延安市| 新源县| 西和县| 花莲市| 裕民县| 永年县| 米泉市| 富宁县| 荣昌县| 汝阳县| 涡阳县| 冀州市| 南宫市| 玉林市| 普兰店市| 龙游县| 西城区| 小金县| 浮山县| 龙山县| 育儿| 无为县| 南雄市| 西昌市| 府谷县| 克什克腾旗| 米易县| 丰顺县| 恩施市| 巴南区| 资中县| 望谟县|