开始切换到 Kotlin_ 谷歌工程师给初学者的知识点总结(2)

private Module activeModule; // 初始化之后可以再赋值
/// Kotlin
private val project: Project // 初始化之后无法再赋值
private var activeModule: Module // 初始化之后可以再赋值

在 Java 中您可能会经常遇到很多成员变量应该是常数,但是却没有使用 final 关键字 (忘记加上 final 是容易犯的错误)。在 Kotlin 中您必须显式地声明每个成员变量的类型。如果您一开始不确定该选择哪种类型,那就默认使用 val 类型,后面有需求变化时再改为 var。

顺便说一句,在 Java 中函数参数类型是可变的,但是可以使用 final 关键字修改为不可变。在 Kotlin 中,函数参数始终是不可变的,它们是被 val 关键字隐式地标记为不可变。

/// Java
public void log(final String message) { … }
/// Kotlin
fun log(message: String) { … } // “message” is immutable

可空性

Kotlin 中取消了 @NotNull 跟 @Nullable 的注解方法。如果变量可以赋值为 null,您只需要在变量类型后面加上一个 “?” 就可以了:

/// Java
@Nullable Project project;
@NotNull String title;
/// Kotlin
val project: Project?
val title: String

在某些情况下,当您确定某些可以被赋值为 null 的变量不可能是 null,您可以使用 !! 操作符设置一个断言。

/// Kotlin
// ‘parse’ 可以返回 null,但这条用例总是能够运行
val result = parse(“123”)!!
// 下面这行是多余的,因为 !! 已经触发断言了
❌ assertThat(result).isNotNull()

如果您错误地使用了 !!,它有可能会抛出 NullPointerException 的异常。在单元测试中,这只会造成测试用例的失败,但是在生产环境中,可能会使程序崩溃,所以要非常小心。事实上,在生产环境的代码中有太多的 !! 操作符,可能意味着此处有 “代码异味” (“代码异味” 代表这部分代码可能需要审查或重构)。

在单元测试中,测试用例里使用 !! 操作符是可接受的,原因是当假设不成立的时候测试用例会失败,并且您还可以修复它。

如果您确定使用 !! 操作符是有意义的,那尽量靠前使用,如下面的用法:

/// Kotlin
val result = parse(“…”)!!
result.doSomething()
result.doSomethingElse()

下面是错误用法:

/// Kotlin (自动生成)
val result = parse(“…”)
❌ result!!.doSomething()
❌ result!!.doSomethingElse()

可省略变量的类型

在 Java 中会看到如下写法的代码:

/// Java
SomeClass instance1 = new SomeClass();
SomeGeneric<List> instance2 = new SomeGeneric<>();

在 Kotlin 中,类型声明被认为是冗余的操作,不需要写两次:

/// Kotlin
val instance1 = SomeClass()
val instance2 = SomeGeneric<List>()

然而,我们在使用动态绑定的时候可能会需要声明这些类型:

/// Java
BaseClass instance = new ChildClass(); // 如:List = new ArrayList

在 Kotlin 中使用下面语法达到同样目的:

/// Kotlin
val instance: BaseClass = ChildClass()

没有检查性异常

不像 Java 那样,Kotlin 中的类方法不需要声明自己的异常类型。因为在 Kotlin 中检查性异常 (Checked Exception) 跟运行时异常 (Runtime Exception) 之间是没有区别的。

/// Java
public void readFile() throws IOException { … }
/// Kotlin
fun readFile() { … }

但是为了使 Java 可以调用 Kotlin 的代码,Kotlin 还是提供 @Throws 注解功能,用于隐式的声明异常类型。当执行 Java → Kotlin 转换时,IDE 会保证安全性并且始终包含这类信息。

/// Kotlin (从 Java 自动转换而来)
@Throws(Exception::class)

fun testSomethingImportant() { … }

但您不需要担心您的单元测试会被 Java 类调用。因此,您可以安全地删除这些类型声明而且还可以减少代码行数:

/// Kotlin
fun testSomethingImportant() { … }

Lambda 调用时可以省略括号

在 Kotlin 中,如果您想要把一个闭包赋值给变量,您需要显式地声明它的类型:

val sumFunc: (Int, Int) -> Int = { x, y -> x + y }

如果所有类型是可以被推测的,则可以简写成:

{ x, y -> x + y }

举个例子:

val intList = listOf(1, 2, 3, 4, 5, 6)
val sum = intList.fold(0, { x, y -> x + y })

需要注意的是,如果一个函数调用的最后一个参数是 lambda 调用时,这时候可以把闭包写在函数括号的外面。

上面代码等同于如下:

val sum = intList.fold(0) { x, y -> x + y }

有能力做,但并不意味着您应该这么做。有些人会觉得上面使用 fold 的方法比较奇怪。某些场景下这种语法减少了视觉干扰,特别是函数的参数只有一个闭包时。如果我们想统计偶数的数量时,对比如下两个用法:

用法一:

intList.filter({ x -> x % 2 == 0 }).count()

用法二:

intList.filter { x -> x % 2 == 0 }.count()

或者对比 Thread 函数使用,如下两个用法:

用法一:

Thread({ doThreadWork() })

用法二:

Thread { doThreadWork() }

无论您喜欢与否,当您在 Kotlin 中看到这类用法时您应该知道它是怎么工作的,Java → Kotlin 转换中也会用到这种语法。

equals() 方法、 == 与 === 运算符

Kotlin 在相等性测试方面不同于 Java。

在 Java 中,== 运算符是用于比较两个对象的引用是否相同,它是有别于 equals() 方法。尽管从理论上听起来不错,在实践中开发者经常会在需要使用 equals 的地方使用了 == 运算符。这可能会引入不易察觉的 Bug,需要花费数小时来定位问题。

在 Kotlin 中 == 运算符等同于 equals 方法,唯一的区别是它还能正确地处理与 null 间的比较。举个例子,null==x 是合法的操作,但是 null.equals(x) 会抛出 NullPointerException 异常。

如果您想在 Kotlin 中判断对象引用的相等性,那您可以使用 === 运算符,这种语法不容易用错而且还更容易定位问题。

/// Java
Color first = new Color(255, 0, 255);
Color second = new Color(255, 0, 255);
assertThat(first.equals(second)).isTrue();
assertThat(first == second).isFalse();
/// Kotlin
val first = Color(255, 0, 255)
val second = Color(255, 0, 255)
assertThat(first.equals(second)).isTrue()
assertThat(first == second).isTrue()
assertThat(first === second).isFalse()

当您使用 Kotlin 的时候,大部分情况下会使用 == 运算符,因为 === 运算符的应用场景相对来说比较少。需要指出的是,Java → Kotlin 转换器始终会把 Java 中的 == 运算符转换成 Kotlin 中的 === 运算符。出于代码可读性跟功能意图考虑,在必要时您应该把 === 运算符恢复成 == 运算符。对比枚举类型时经常会遇到上面所说的情况,如下所示:

/// Java
if (day == DayOfWeek.MONDAY) { … }

/// Kotlin (从 Java 自动转换而来)
❌ if (day === DayOfWeek.MONDAY) { … }

/// Kotlin
if (day == DayOfWeek.MONDAY) { … }

移除成员变量的前缀

在 Java 中,对私有变量编写成对的 getter 与 setter 方法是很常见的做法,而且很多 Java 代码给成员变量命名时加上了前缀,有点像是匈牙利命名法。

/// Java
private String myName;
// 或者 private String mName;
// 或者 private String _name;
public String getName() { … }
public void setName(String name) { … }

这种前缀适合给变量做标记,代表着该变量只在类的内部可见。而且还容易区分是类的内部成员变量还是通过函数参数传递进来的变量。

在 Kotlin 中,成员变量与 getter/setters 方法被整合成同一个概念。

/// Kotlin
class User {
val id: String // 代表成员变量与 getter 方法
var name: String // 代表成员变量与 getter 和 setter 方法
}

当您使用自动转换功能时,Java 中的成员变量前缀有时候会被保留下来,带来的隐患是曾经隐藏在内部类中的实现细节有可能会被 public 接口暴露出来。

/// Kotlin (从 Java 自动转换而来)
class User {
❌ val myId: String
❌ var myName: String
}

为了防止前缀带来的实现细节的暴露,建议您养成移除前缀的习惯。

有时候阅读没有前缀的成员变量代码时候会比较费劲,尤其是使用网页版的 Code Review 工具 (比如在很长的类中阅读很长的函数)。不过当您使用 IDE 阅读代码时候,可以通过语法高亮功能很清楚地知道哪些是成员变量,哪些是函数参数。您可以通过取消前缀来编写目的更为聚焦的函数与类,以便养成更好的编程习惯。

结束语

希望本文章有助于您开始学习 Kotlin。您从编写 Java 开始,使用自动转换功能将 Java 转换成 Kotlin。这时候您会编写 Java 风格的 Kotlin 代码,随着练习,不久之后您将会像专家那样熟练地编写 Kotlin 代码了。
这篇文章只是简单介绍了 Kotlin 的使用。它的目的在于向那些没有时间学习但需要将测试用例跑起来的开发者们介绍 Kotlin 的基本概念与语法。
当然,本文并没有涵盖您需要知道的一切。为此,请参考学习官方的 Kotlin 文档:

  • 语言参考
  • 互动教程
    语言参考教程非常有用,它涵盖了 Kotlin 的所有知识点,而且难度适中。
    互动教程提供了学习编程语言的平台,还包含了一系列练习题用于验证您所学到的知识点是否正确。
    最后,为了将您的代码重构到 Kotlin,请尝试我们为您准备的 Codelab —— “重构为 Kotlin”,它包含了本文中介绍过的内容和其他方面的更多内容。

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
15905012900)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 10
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值