最近 Kotlin 特别流行,并且我也赞同 Kotlin 是一个经过深思熟虑后被设计出的语言,除了下面提到的缺点之外。
\\我会在本文向你分析一些我在开发过程中遇到的陷阱,并且教你如何避免他们。
\\谜一样的 null
\\当你使用 Kotlin 编写程序的时候,无需考虑 null
的处理。这会让你忘记 null
其实是无处不在的,只不过被隐藏了起来。看看下面这个表面看起来没有问题的类:
\class Foo {\ private val c: String\ init {\ bar()\ c = \"\"\ }\ private fun bar() {\ println(c.length)\ }\}\\\
如果你尝试初始化这个类,那么代码就会抛出一个 NullPointerException
。因为 bar
方法尝试在 c
变量初始化之前就访问它。
尽管这个代码本身就是有问题的,才导致异常抛出。但是更糟糕的是你的编译器不会发现这一点。
\\Kotlin 可以帮你在绝大部分情况下避免 null
,但是你不能因此而忘记 null
的存在。否则迟早有一天你会碰上类似的问题。
来自 JDK 的 null
\\Kotlin 的标准库能够很好地处理 null
。但是如果你使用了 JDK 中的类,你需要自己处理关于 JDK 方法调用可能产生的空指针。
大部分情况下 Kotlin 的标准库就足够了,但是有时你需要使用到 ConcurrentHashMap:
\\\val map = ConcurrentHashMap()\map[\"foo\"] = \"bar\"\val bar: String = map[\"foo\"]!!\,\u0026gt;\\
这时,你需要使用 !!
操作符。但某些情况下你还可以使用像 (?
) 这样的对 null
安全的操作符来替换它。尽管如此,当你使用 !!
或者 ?
,或者编写了一个适配器来使用 Java 类库的时候,你会发现代码因为这些修改而变的混乱。这是你无法避免的问题。
你还可能会碰上更多更可怕的问题。当你使用 JDK 类中的方法的时候,返回值可能是 null
,而且没有什么像 Map
访问一样的语法糖。
考虑如下例子:
\\\val queue: Queue = LinkedList()\queue.peek().toInt()\\\
这种情况下,你使用了可能返回 null
值的 peek
方法。但是 Kotlin 编译器不会提示你这个问题,所以当你的 Queue
是空队列的的时候,可能会触发 NullPointerException
异常。
问题在于我们使用的 Queue
是 JDK 的一个接口,并且当你查看 peek
方法的文档时:
\/**\ * Retrieves, but does not remove, the head of this queue,\ * or returns {@code null} if this queue is empty.\ *\ * @return the head of this queue, or {@code null} if this queue is empty\ */\ E peek();\\\
文档中说 peek 方法会返回一个 E 类型的对象,但是 Kotlin 认为 E 是不可空的。在接下来的 Kotlin 版本中可能会解决这个问题,但是现在当你在你的工程中使用类似接口的时候,一定要注意:
\\\val queue: Queue = LinkedList()\queue.peek()?.toInt()\?\u0026gt;\\
内部 it
\\当一个 lambda 表达式只有一个参数的时候,你可以在你的代码中将其省略,并用 it
代替。
\\\it:单参数的内部名称。当你表达式只有一个参数的时候,这是一个很有用的特性,声明的过程可以省略(就像 -\u0026gt;),并且参数名称为 it。
\
问题是,当你的代码中存在向下面例子一样的嵌套函数的时候:
\\\val list = listOf(\"foo.bar\