原文鏈接 http://nerd-is.in/2013-09/scala-learning-annotations/
原文發表於:http://nerd-is.in/2013-09/scala-learning-annotations/
注解可以在程序中的各項條目添加信息,這些信息可以被編譯器或外部工具處理。
將學習到如何與Java注解實現互操作,以及如何使用Scala特有的注解。
什么是注解
注解是插入到代碼中以便有工具可以對它們進行處理的標簽。
工具可以在代碼級別運作,也可以處理被編譯器加入了注解信息的類文件。
可以對Scala類使用Java注解。也可以使用Scala注解,是由Scala注解特有的,通常由Scala編譯器或編譯器插件處理。
Java注解並不影響編譯器如何將源碼翻譯成字節碼,僅僅往字節碼中添加數據,以便外部工具可以利用它們。
而在Scala中,注解可以影響編譯過程,比如@BeanProperty注解。
什么可以被注解
Scala中可以為類、方法、字段、局部變量和參數添加注解,與Java一樣。
可以同時添加多個注解,先后順序沒有影響。
給主構造器添加注解時,需要將注解放置在構造器之前,並加上一對圓括號:
為表達式添加注解,在表達式后加上冒號,然后是注解:
為類型參數添加注解:
針對實際類型的注解應放置在類型名稱之后:
這個暫時不知道是什么東西,@cps注解將會在22章介紹。
注解參數
Java注解可以有帶名參數。如果參數的名字是value,參數名可以略去。
如果注解不帶參數,圓括號可以省去。大多數注解參數帶有缺省值。
Java注解的參數類型是有規定的,但Scala中參數可以是任何類型,不過只有很少幾個注解使用了。
針對Java特性的注解
不常用的Java特性,Scala提供了相應的注解。
@volatile注解標記為易失的;
@transient注解將字段標記為瞬態的;
@strictfp注解對應strictfp修飾符;
@native注解標記在C或C++代碼中實現的方法,對應native修飾符。
Scala使用@cloneable和@remote注解來代替Cloneable和java.rmi.Remote標記接口。
Java編譯器會跟蹤受檢異常。那么如果從Java代碼中調用Scala的方法時,需要包含那些可能拋出的受檢異常。
這時,需要使用@throws注解來生成正確的簽名:
使用@varargs注解可以讓Java調用Scala中帶有變長參數的方法。
用於優化的注解
尾遞歸
遞歸有時能被轉化成循環,可以節省棧空間。
在函數式編程中這很重要,因為通常會使用遞歸方法來遍歷集合。
尾遞歸計算過程的最后一步是遞歸調用同一個方法,可以變換成跳回到方法頂部的循環。
比如:
上面的代碼中Scala會自動嘗試使用尾遞歸優化。
不過有的時候可能會因為某些原因使得編譯器無法進行優化。
如果需要依賴於編譯器去掉遞歸,給方法加上@tailrec注釋。這樣的話,如果編譯器無法應用遞歸優化,就會報錯。
對於消除遞歸,一個更加通用的機制叫“蹦床”。
蹦床會執行一個循環,不停地調用函數,每個函數都返回下一個將被調用的函數。
尾遞歸是一個特例,每個函數都返回它自己。Scala有一個名為TailCalls的工具對象,可以幫助實現蹦床。
相互遞歸的函數返回類型為TailRec[A],要么返回done(result),要么返回tailcall(fun),fun是下一個要被調用的函數。
這個函數必須是不帶額外參數且同樣返回TailRec[A]的函數。示例:
跳轉表生成與內聯
在C++或Java中,switch語句通常可以被編譯成跳轉表,這比一系列的if/else表達式更加高效。
Scala也會嘗試對匹配語句生成跳轉表。而@switch注解可以檢查match語句是不是真的被編譯成了跳轉表。
方法內聯是另一個常見的優化。內聯將方法調用語句替換為被調用的方法體(減少了調用的開支,
應該相當於C++中的inline函數吧,適合於小方法)。
使用@inline來建議編譯器做內聯,或者使用@noinline來告訴編譯器不要內聯。
可省略方法
@elidable注解給可以在生產代碼中移除的方法打上標記。這個等到使用時再回來看詳細的吧。
基本類型的特殊化
打包和解包基本類型的值不高效,不過這樣的操作在泛型代碼里很常見。
當使用泛型代碼時,可以使用@specialized注解來使編譯器自動生成基本類型的重載版本。
@specialized注解后的括號內,是指定特殊化的基本類型。如上面的例子,特殊化了Long和Double兩種類型。
如果沒有括號及括號內的內容,則是全部生成。
用於錯誤和警告的注解
加上了@deprecated注解的特性如果被使用,編譯器會生成一個警告信息。
@implicitNotFound注解用於子啊某個隱式參數不存在的時候生成有意義的錯誤提示,詳細參見21章。
@unchecked注解用於在匹配不完整時取消警告信息。
@uncheckedVariance注解會取消與型變相關的錯誤提示。
本書讀到現在,大概也開始出現了許多平時很少使用的特性了,而且沒有好好使用過我也沒法體會到真正的用處和強大。
下一章的內容是XML處理,我認為可以先放一邊,或者是先粗略看看,等要用了再細看。
不過后面的章節,我認為有的還是需要再了解一下的,比如隱式轉換和Actor。
這些之后,估計就可以先去接觸一些框架試試了,Lift、Akka或Spark之類的。
最近感覺有點緊,實習的事情還需要我再去補J2EE和Android的內容。
package test.scala.lang.annotation
import java.io.IOException
class TestAnnotation {
//@throws(classOf[IOException]) def test =
@throws(classOf[IOException]) def test(): Unit = {
println("test throw")
throw new IOException("test IOException")
}
}
object TestAnnotation {
def main(args: Array[String]): Unit = {
testAssert("test")
testAssert("test1")
testDeprecated
}
def testAssert(test: String){
assert(test.equalsIgnoreCase("test"), s"test is $test")
println("$test is not test")
}
@deprecated(message = "test @deprecated")
def testDeprecated = {
println("testDeprecated")
}
}
package test.scala.lang.annotation;
import java.io.IOException;
public class TestAnno {
public static void main(String[] args) {
test();
}
public static void test(){
TestAnnotation ta = new TestAnnotation();
try {
ta.test();
} catch (IOException e) {
e.printStackTrace();
}
}
}
