【轉】Scala學習——注解


原文鏈接 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();
		}
	}

}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM