Groovy學(xué)習(xí)之-與Java的不同之處

Groovy學(xué)習(xí)目錄-傳送門(mén)

Groovy試圖對(duì)Java開(kāi)發(fā)人員盡可能自然。 我們?cè)噲D在設(shè)計(jì)Groovy時(shí)遵循最小驚訝原則,特別是對(duì)于來(lái)自Java背景的Groovy開(kāi)發(fā)人員。

這里我們列出了Java和Groovy之間的所有主要區(qū)別。

默認(rèn) imports

所有這些包和類都是默認(rèn)導(dǎo)入的,您不必使用顯式import語(yǔ)句來(lái)使用它們:

java.io.*
java.lang.*
java.math.BigDecimal
java.math.BigInteger
java.net.*
java.util.*
groovy.lang.*
groovy.util.*

Multi-methods

在Groovy中,將在運(yùn)行時(shí)選擇將被調(diào)用的方法。 這稱為運(yùn)行時(shí)分派或Multi-methods。 這意味著將基于運(yùn)行時(shí)參數(shù)的類型來(lái)選擇方法。 在Java中,則是根據(jù)聲明的類型,在編譯時(shí)選擇方法。

下面的代碼,以Java代碼編寫(xiě),可以在Java和Groovy中編譯,但它的行為會(huì)有所不同:

int method(String arg) {
    return 1;
}
int method(Object arg) {
    return 2;
}
Object o = "Object";
int result = method(o);

在Java中, 您講得到:

assertEquals(2, result);

而在Groovy中:

assertEquals(1, result);

這是因?yàn)镴ava將使用靜態(tài)信息類型,即o被聲明為Object,而Groovy將在運(yùn)行時(shí)選擇該方法被實(shí)際調(diào)用時(shí)。 因?yàn)樗怯?code>String調(diào)用的,所以調(diào)用String版本。

數(shù)組初始化

在Groovy中,{...}塊是為閉包而保留的。 這意味著您不能使用以下語(yǔ)法創(chuàng)建數(shù)組literal

int [] array = {1,2,3}

實(shí)際上你必須使用:

int [] array = [1,2,3]

包范圍可見(jiàn)性

在Groovy中,在字段上省略修飾符不會(huì)像Java中一樣變成package-private字段:

class Person {
     字符串名稱
}}

相反,它用于創(chuàng)建一個(gè)屬性,也就是說(shuō)一個(gè)私有字段,一個(gè)關(guān)聯(lián)的getter和一個(gè)關(guān)聯(lián)的setter。

可以通過(guò)使用@PackageScope注釋來(lái)創(chuàng)建一個(gè)package-private字段:

class Person {
     @PackageScope字符串名稱
}}

自動(dòng)資源管理塊

Groovy不支持Java 7中的ARM(自動(dòng)資源管理)塊。 相反,Groovy提供了依賴閉包的各種方法,它們具有相同的效果,同時(shí)更加慣用。 例如:

Path file = Paths.get("/path/to/file");
Charset charset = Charset.forName("UTF-8");
try (BufferedReader reader = Files.newBufferedReader(file, charset)) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }

} catch (IOException e) {
    e.printStackTrace();
}

可以這樣寫(xiě):

new File('/path/to/file').eachLine('UTF-8') {
   println it
}

或者,如果你想要一個(gè)更接近Java的版本:

new File('/path/to/file').withReader('UTF-8') { reader ->
   reader.eachLine {
       println it
   }
}

內(nèi)部類

匿名內(nèi)部類和嵌套類的實(shí)現(xiàn)遵循Java方式,但是你不應(yīng)該拿出Java語(yǔ)言規(guī)范,并且對(duì)不同的東西不斷地?fù)u頭。 它的實(shí)現(xiàn)看起來(lái)很像groovy.lang.Closure,同時(shí)有一些好處和一些差異。 例如訪問(wèn)私有字段和方法可能成為一個(gè)問(wèn)題,但另一方面,局部變量不必是final的。

  1. 靜態(tài)內(nèi)部類
    這里有一個(gè)靜態(tài)內(nèi)部類的例子:
class A {
    static class B {}
}

new A.B()

靜態(tài)內(nèi)部類的使用是最好的支持。 如果你需要一個(gè)內(nèi)部類,你最好使用靜態(tài)的。

  1. 匿名內(nèi)部類
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

CountDownLatch called = new CountDownLatch(1)

Timer timer = new Timer()
timer.schedule(new TimerTask() {
    void run() {
        called.countDown()
    }
}, 0)

assert called.await(10, TimeUnit.SECONDS)
  1. 創(chuàng)建非靜態(tài)內(nèi)部類的實(shí)例
    在Java中,你可以這樣做:
public class Y {
    public class X {}
    public X foo() {
        return new X();
    }
    public static X createX(Y y) {
        return y.new X();
    }
}

Groovy不支持y.new X()語(yǔ)法。 相反,你必須用new X(y),如下面的代碼:

public class Y {
    public class X {}
    public X foo() {
        return new X()
    }
    public static X createX(Y y) {
        return new X(y)
    }
}

注意,Groovy支持使用一個(gè)參數(shù)調(diào)用方法,而不提供參數(shù)。 然后,參數(shù)的值為null。 基本上,相同的規(guī)則適用于調(diào)用構(gòu)造函數(shù)。 有一個(gè)危險(xiǎn),例如你會(huì)寫(xiě)new X(),而不是new X(this)。 由于這也可能是正常的方式,我們還沒(méi)有找到一個(gè)好的方法來(lái)防止這個(gè)問(wèn)題。

Lambdas

Java 8支持lambdas和方法引用:

Runnable run = () -> System.out.println("Run");
list.forEach(System.out::println);

Java 8 lambdas可以或多或少被認(rèn)為是匿名內(nèi)部類。 Groovy不支持該語(yǔ)法,但是可以使用閉包:

Runnable run = { println 'run' }
list.each { println it } // or list.each(this.&println)

GStrings

由于雙引號(hào)字符串字面量被解釋為GString,如果具有包含美元字符的String的類是使用Groovy和Java編譯器編譯的,Groovy可能會(huì)失敗并產(chǎn)生編譯錯(cuò)誤或產(chǎn)生細(xì)微不同的代碼。

通常,Groovy將在GStringString之間自動(dòng)轉(zhuǎn)換,如果API聲明參數(shù)的類型,小心接受Object參數(shù)的Java API,然后檢查實(shí)際的類型。

字符串和字符

Groovy中的單引號(hào)用于String,雙引號(hào)結(jié)果是StringGString,取決于文字中是否有插值。

assert 'c'.getClass()==String
assert "c".getClass()==String
assert "c${1}".getClass() in GString

只有在賦給char類型的變量時(shí),Groovy會(huì)自動(dòng)將單字符String轉(zhuǎn)換為char。 當(dāng)調(diào)用類型為char的參數(shù)的方法時(shí),我們需要顯式轉(zhuǎn)換或確保該值已預(yù)先轉(zhuǎn)換。

char a='a'
assert Character.digit(a, 16)==10 : 'But Groovy does boxing'
assert Character.digit((char) 'a', 16)==10

try {
  assert Character.digit('a', 16)==10
  assert false: 'Need explicit cast'
} catch(MissingMethodException e) {
}

Groovy支持兩種類型的轉(zhuǎn)換,在轉(zhuǎn)換為char的情況下,在轉(zhuǎn)換multi-char 時(shí)存在微妙的差別。 Groovy風(fēng)格的轉(zhuǎn)換是更寬松的,將采取第一個(gè)字符,而C風(fēng)格的轉(zhuǎn)換將失敗,異常。

// for single char strings, both are the same
assert ((char) "c").class==Character
assert ("c" as char).class==Character

// for multi char strings they are not
try {
  ((char) 'cx') == 'c'
  assert false: 'will fail - not castable'
} catch(GroovyCastException e) {
}
assert ('cx' as char) == 'c'
assert 'cx'.asType(char) == 'c'

原始和封裝

因?yàn)镚roovy使用Objects來(lái)做每一件事,它對(duì)原始的引用自動(dòng)包裝。 因此,它不遵循Java的行為擴(kuò)展優(yōu)先于裝箱。 這里有一個(gè)使用int的例子

int i
m(i)

//這是Java將調(diào)用的方法,因?yàn)閿U(kuò)展優(yōu)先于拆箱。
void m(long l) {
  println "in m(long)"
}

//這是Groovy實(shí)際調(diào)用的方法,因?yàn)樗械幕疽枚际褂盟鼈兊陌b類。
void m(Integer i) {
  println "in m(Integer)"
}

==的行為

在Java中==表示對(duì)象的原始類型或標(biāo)識(shí)的相等性。 在Groovy ==翻譯為a.compareTo(b)== 0,如果他們是可比較的,否則a.equals(b)。 如果要檢查身份,有is方法,例如a.is(b)。

轉(zhuǎn)換

詳情請(qǐng)點(diǎn)擊超鏈接

額外的關(guān)鍵字

Groovy中還要比Java多幾個(gè)關(guān)鍵字。 不要將它們用于變量名稱等。

  • as
  • def
  • in
  • trait
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,694評(píng)論 19 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,834評(píng)論 18 399
  • 前言 人生苦多,快來(lái) Kotlin ,快速學(xué)習(xí)Kotlin! 什么是Kotlin? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,736評(píng)論 9 118
  • 剽悍一只貓又開(kāi)了一個(gè)推送讀書(shū)感悟分享的公眾號(hào):剽悍晨讀。這個(gè)公眾號(hào)每天早上6點(diǎn)半左右推送文章,有點(diǎn)類似羅輯思維的每...
    十六畫(huà)生的寫(xiě)作閱讀 370評(píng)論 0 0
  • 人為什么要死,死了就什么都沒(méi)有了嗎?
    Chris遼閱讀 194評(píng)論 0 0

友情鏈接更多精彩內(nèi)容