【转】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(); } } }
posted on 2015-09-16 00:38 develooop 阅读(3789) 评论(0) 编辑 收藏 举报