Kotlin 第十七章: 异常和注解

Kotlin 第十七章: 异常和注解

异常类

所有的异常类都是 Exception 的子类。每个异常都有一个消息,栈踪迹和可选的原因。

使用 throw 表达式,抛出异常

throw MyException("Hi There!")

使用 try 捕获异常

try {
  // some code
}
catch (e: SomeException) {
  // handler
}
finally {
  // optional finally block
}

有可能有不止一个的 catch 块。finally 块可以省略。

try 是一个表达式

try 可以有返回值:

val a: Int? = try { parseInt(input) } catch (e: NumberFormatException) { null }

try 返回值要么是 try 块的最后一个表达式,要么是 catch 块的最后一个表达式。finally 块的内容不会对表达式有任何影响。

检查异常

Kotlin 中没有异常检查。这是由多种原因造成的,我们这里举个简单的例子

下面是 JDK StringBuilder 类实现的一个接口

Appendable append(CharSequence csq) throws IOException;

这个签名说了什么? 它说每次我把 string 添加到什么东西(StringBuilder 或者 log console 等等)上时都会捕获 IOExceptions 为什么呢?因为可能涉及到 IO 操作(Writer 也实现了 Appendable)… 所以导致所有实现 Appendable 的接口都得捕获异常

try {
  log.append(message)
}
catch (IOException e) {
  // Must be safe
}

注解声明

注解是一种将元数据附加到代码中的方法。声明注解需要在类前面使用 annotation 关键字:

annotation class fancy

@Retention 注解

指定该注解是否存储在编译后的 Class 文件中,以及它在运行时能否通过反射可见,有三个值,默认是AnnotationRetention.RUNTIME,分别为:

  • AnnotationRetention.SOURCE:不存储在编译后的 Class 文件。
  • AnnotationRetention.BINARY:存储在编译后的 Class 文件,但是反射不可见。
  • AnnotationRetention.RUNTIME:存储在编译后的 Class 文件,反射可见。

@Target 注解

表示该注解可以用于什么地方,类型有

  • AnnotationTarget.CLASS:类,接口或对象,注解类也包括在内。
  • AnnotationTarget.ANNOTATION_CLASS:只有注解类。
  • AnnotationTarget.TYPE_PARAMETER:Generic type parameter (unsupported yet)通用类型参数(还不支持)。
  • AnnotationTarget.PROPERTY:属性。
  • AnnotationTarget.FIELD:字段,包括属性的支持字段。
  • AnnotationTarget.LOCAL_VARIABLE:局部变量。
  • AnnotationTarget.VALUE_PARAMETER:函数或构造函数的值参数。
  • AnnotationTarget.CONSTRUCTOR:仅构造函数(主函数或者第二函数)。
  • AnnotationTarget.FUNCTION:方法(不包括构造函数)。
  • AnnotationTarget.PROPERTY_GETTER:只有属性的 getter
  • AnnotationTarget.PROPERTY_SETTER:只有属性的 setter
  • AnnotationTarget.TYPE:类型使用。
  • AnnotationTarget.EXPRESSION:任何表达式。
  • AnnotationTarget.FILE:文件。
  • AnnotationTarget.TYPEALIAS@SinceKotlin("1.1") 类型别名,Kotlin1.1已可用。

@Repeatable 注解

表示允许在同一申明类型(类,属性,或方法)的多次使用同一个注解

@MustBeDocumented 注解

决定了注解是公共 API 的一部分,因此应该包含在用于注解的元素的生成文档注解中。

这里声明一个 Fancy 注解:

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
        AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
annotation class Fancy

用法

@fancy class Foo {
    @fancy fun baz(@fancy foo: Int): Int {
        return (@fancy 1)
    }
}

在多数情形中 @ 标识是可选的。只有在注解表达式或本地声明中才必须:

fancy class Foo {
    fancy fun baz(fancy foo: Int): Int {
        @fancy fun bar() { ... }
        return (@fancy 1)
    }
}

如果要给构造函数注解,就需要在构造函数声明时添加 constructor 关键字,并且需要在前面添加注解:

class Foo @inject constructor (dependency: MyDependency)
    //...

也可以注解属性访问者:

class Foo {
    var x: MyDependency?=null
        @inject set
}

构造函数

注解可以有带参数的构造函数。

annotation class special(val why: String)
special("example") class Foo {}

Lambdas

注解也可以用在 Lambda 中。这将会应用到 lambda 生成的 invoke() 方法。这对 Quasar 框架很有用,在这个框架中注解被用来并发控制

annotation class Suspendable
val f = @Suspendable { Fiber.sleep(10) }

java 注解

java 注解在 kotlin 中是完全兼容的:

import org.junit.Test
import org.junit.Assert.*

class Tests {
  Test fun simple() {
    assertEquals(42, getTheAnswer())
  }
}

java 注解也可以通过在导入是重命名实现像修改者那样:

import org.junit.Test as test

class Tests {
  test fun simple() {
    ...
  }
}

因为 java 中注解参数顺序是没定义的,你不能通过传入参数的方法调用普通函数。相反,你需要使用命名参数语法:

//Java
public @interface Ann {
    int intValue();
    String stringValue(0;
}
//kotlin
Ann(intValue = 1, stringValue = "abc") class C

像 java 中那样,值参数是特殊的情形;它的值可以不用明确的名字。

public @interface AnnWithValue {
    String value();
}

//kotlin
AnnWithValue("abc") class C

如果java 中的 value 参数有数组类型,则在 kotlin 中变成 vararg 参数:

// Java
public @interface AnnWithArrayValue {
    String[] value();
}
// Kotlin
AnnWithArrayValue("abc", "foo", "bar") class C

如果你需要明确一个类作为一个注解参数,使用 Kotlin 类 KClass。Kotlin 编译器会自动把它转为 java 类,因此 java 代码就可以正常看到注解和参数了。

import kotlin.reflect.KClass

annotation class Ann(val arg1: KClass<*>, val arg2: KClass<out Any?>)

Ann(String::class, Int::class) class MyClass

注解实例的值在 kotlin 代码中是暴露属性。

// Java
public @interface Ann {
    int value();
}
// Kotlin
fun foo(ann: Ann) {
    val i = ann.value
}

后记

这一篇文章算是学习 Kotlin 的最后一篇文章了,后面会不定期的带来几篇 Kotlin 实战小 Demo 用来增加 Kotlin 的理解和记忆,经历的这么长的时间,Kotlin 的学习算是告一段落了,虽然学习文章中有些内容在以后的编码中不一定能够用得到,但是写下来,以后翻翻加深记忆还是不错,玩意能用到呢?

最后还是希望各位看官能够多多留言,有问题多多指正。

参考

Kotlin中文文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值