针对as?的使用优化

前言

写代码的时候往往会用到类型检测is和类型转换as或者空安全的类型转换as?,在这里记录一下使用as?的一点优化。

正常使用

举个例子

1
2
3
4
5
6
7
8
9
10
11
12

fun getCurrentProcessName(context: Context?): String {
return try {
(context?.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager)
?.runningAppProcesses
?.first { it.pid == android.os.Process.myPid() }
?.processName
?: ""
} catch (e: Exception) {
""
}
}

在正常使用的时候,往往是要在外面加一层括号(),这样写代码就很麻烦,不能一步到位,那要怎么样才能把这括号删掉呢?

加工之后

首先我们要想到扩展和reified,然后写一个方法来实现类型转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

inline fun <reified T> Any?.asType(): T? {
// 如果类型转换成功,那么返回对应的`T`类型,如果转换失败,那么就会返回`null`
return this as? T
}

// 或者
// 这个方法是https://droidyue.com/blog/2020/03/29/kotlintips-as-type/,里面的实现
inline fun <reified T> Any.asType1(): T? {
// 先检查this的类型,如果是T则返回T,否则返回null
return if (this is T) {
this
} else {
null
}
}

说一下isasas?的区别

  • is是表示类型检查,与Java的instanceof一样
  • as是表示不安全的类型转换,但是左边的类型如果是空的那么就会抛出一个异常,这就是所谓的不安全的,对应Java的强转
  • as?则表示安全的类型转换,如果转换失败则不会抛出异常,而是直接返回null,对应Java的话则是if (test instanceof String) String str = (String) test,先instanceof,然后再强转。

所以上面两种写法都可以用,最终实现的目的都是一样的,最后看调用的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13

fun getCurrentProcessName(context: Context?): String {
return try {
context?.getSystemService(Context.ACTIVITY_SERVICE)
?.asType<ActivityManager>()
?.runningAppProcesses
?.first { it.pid == android.os.Process.myPid() }
?.processName
?: ""
} catch (e: Exception) {
""
}
}

这样写起来的会就很顺畅了,直接一步到位,不用再写完as之后在写一个括号,然后再回来接着写下面的代码。

感谢