《Groovy官方文檔》1.3 Groovy和Java比較
Groovy語言一直在努力親近Java開發人員。在設計Groovy語言的時候,我們遵循最小標新立異原則,努力讓那些Java開發背景的開發者容易上手並學會。下麵我們列舉Groovy和Java的一些主要區別。
1 默認導入
下麵的包和類是默認導入的,也就是說不必精確使用 import 語句來導入它們:
- java.io.*
- java.lang.*
- java.math.BigDecimal
- java.math.BigInteger
- java.net.*
- java.util.*
- groovy.lang.*
- groovy.util.*
2 動態方法(Multi-methods)
在Groovy裏,方法的調用是在運行時動態決定。這一特性叫做運行時分發(runtime dispatch)或動態方法(multi-methods)。也就是說方法的最後調用是根據傳入參數在運行時的類型所決定。在Java裏,這一點是不一樣的:在編譯時就決定了方法的參數類型。
下麵的代碼,我們采用Java風格,在Groovy和Java都可以編譯通過,但是運行結果不一樣:
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);
原因是Java使用的是靜態聲明的類型信息,這裏o被聲明為Object,但是Groovy是在運行時決定,當方法最終被調用時,因為這裏o實際是一個字符串,因此最終String版本的方法被調用。
譯者注:譯者之前也沒有接觸過Groovy語言,空閑時間也是有限的(姑且讓我找這個借口吧,雖然這個借口很牽強,對待知識本來應該以一種嚴謹,求真的態度)因此這裏有些專有名字可能翻譯不是很準確,比如對Multi-methods的翻譯。譯者也不確定是否準確,因此附帶了原文單詞,請讀者自行根據示例代碼和上下文意思理解。如果找到準確的中文翻譯懇請評論留言,以待修正。
3 數組初始化
在Groovy,{…}已經被用作閉包,也就是說你不能使用下麵的語法創建數組(譯者注:Java可以,並且很常用)
int[] array = { 1, 2, 3}
你應該這樣聲明並初始化一個數組
int[] array = [1,2,3]
4 包範圍可見性(Package scope visibility)
在Groovy裏,省略字段的修飾符不會像Java一樣使其成為包私有屬性(package-private field)
class Person {
String name
}
這裏,我們創建了一個屬性,它是私有的,而且自動關聯了getter和setter方法。如果我們要創建一個包私有屬性,可以添加@PackageScope注解來實現:
class Person {
@PackageScope String name
}
5 ARM塊
ARM(Automatic Resource Management 自動資源管理)塊從Java7開始支持,但是Groovy不支持。相應地,Groovy依賴於閉包來實現類似的功能。示例:
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();
}
在Groovy裏可以寫成:
new File('/path/to/file').eachLine('UTF-8') {
println it
}
或者也可以寫成跟Java類似風格:
new File('/path/to/file').withReader('UTF-8') { reader ->
reader.eachLine {
println it
}
}
6 內部類
Groovy遵循了Java的匿名內部類以及嵌套內的特點。但是它並沒有完全依照Java語言規範,因此在使用前應該記住它們是有區別的。Groovy的實現和groovy.lang.Clouser類的風格有些類似,但也有不同點。比如在訪問私有字段和方法以及局部變量沒有final等。
6.1 靜態內部類
這是一個靜態內部類的例子:
class A {
static class B {}
}
new A.B()
使用靜態內部類是一個非常好的實踐,如果你一定要使用內部類,建議優先考慮靜態內部類。
6.2 匿名內部類
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)
6.3 創建非靜態內部類實例
在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()語法,但你可以寫成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支持調用無參方法傳入一個參數。那個參數的值將會是null。這個特性對於調用構造函數同樣適用。可能會有人寫new X(this)而不是new X(),這是不合法的。雖然我們還沒有找到辦法避免用戶這樣寫。
7 拉姆達表達式
Java 8 支持拉姆達表達式和方法引用
Runnable run = () -> System.out.println("Run");
list.forEach(System.out::println);
Java8的拉姆達表達式或多或少被認為是匿名內部類。Groovy不支持這樣的語法,但是可以使用閉包代替:
Runnable run = { println 'run' }
list.each { println it } // or list.each(this.&println)
8 GStrings
使用雙引號修飾的字符串被解釋為GString值。如果一個字符串裏含有美元符號在Groovy和Java的編譯器裏將會產生編譯錯誤。
當然,Groovy會自動在GString和String之間進行類型轉換,就像Java可以接受一個Object參數然後檢查其實際類型一樣。
9 字符串和字符
在Groovy裏,使用單引號修飾的被當成String類型,使用雙引號修飾的可以當成GString類型或String類型。取決於字麵常量。
assert 'c'.getClass()==String
assert "c".getClass()==String
assert "c${1}".getClass() in GString
如果聲明是char類型,Groovy會自動將單個字符從String類型轉換為char類型。如果被調用的方法聲明的參數類型是char,我們需要強製類型轉換為char類型。
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支持兩種風格的類型轉換,在轉換成char類型的時候,當個字符和多個字符轉換有些不一樣。對於多個字符轉換成char類型,Groovy會選擇第一個字符,這一點不像C語言,會直接失敗。
// 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'
10 ==的行為
在Java裏,==意味著基本類型相等或對象類型相等。在Groovy裏,==會轉換成a.compareTo(b)==0,如果他們是Comparable,就是使用a.equals(b),否則檢查基本類型,也就是is,比如a.is(b)
11 不同的關鍵字
Groovy比Java有更多的關鍵字,請不要把它們當變量名使用
- in
- trait
最後更新:2017-05-22 13:01:28