【转】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编辑  收藏  举报

导航

AmazingCounters.com