Kotlin — Part 2:语法,空安全,静态类型

在这个部分,我们将理解这个语言的一些基本概念,添加一些代码到 MainActivity.kt中.

全部章节:

Kotlin — Part 0:关于这个系列
Kotlin — Part 1:配置 Android Studio
Kotlin — Part 2:语法,空安全,静态类型
Kotlin — Part 3:扩展函数、Android 扩展、委托属性
Kotlin — Part 4:RecyclerView— Kotlin 适配器委托&数据类
Kotlin — Part 5:Kotlin,RxJava&RxAndroid
Kotlin — Part 6:API-Retrofit&Kotlin)
Kotlin — Part 7:无限滑动:高阶函数& Lambdas
Kotlin — Part 8:方向改变(序列化&数据类)
Kotlin — Part 9:单元测试与 Kotlin(Mockito,RxJava)

Github 仓库:https://github.com/imuhao/KedditBySteps

Kotlin 语法

现在我们准备好开始学习一些语法,当你第一眼看到这些代码你可能会有一些恐惧,但是相信我会让你喜欢它.

Kotlin 是一个简洁,安全,静态类型,可以与 Java 相互操作的程序语言

我们回顾刚刚插件自动生成的代码,在这将给你两个 MainActivity 文件: Java 和 Kotlin 文件.

MainActivity. java(转换前的代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}

MainActivity.kt(转换后的代码)

1
2
3
4
5
6
7
8
9
10
11
12
class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar = findViewById(R.id.toolbar) as Toolbar
setSupportActionBar(toolbar)

val fab = findViewById(R.id.fab) as FloatingActionButton
fab.setOnClickListener { view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show() }
}
}

简洁

你有没有注意到 Java 文件有19行代码, Kotlin 文件只有12行?

这是因为大多数冗长的 java 代码被消除,简洁的代码将花费更少的时间编写和阅读.这将改善你的生产力.

继承和实现

extends“和” implement“单词已经被一个冒号”:“取代.在这种情况下我们从 AppCompatActivity 下继承.

1
class MainActivity : AppCompatActivity()

####Fun — 关键字

我们不需要我们的类存在”public void methodName()“结构.现在我们在使用”fun“关键字,在类中定义一个函数.返回的类型添加在结尾.

1
override fun onCreate(savedInstanceState: Bundle?)

但是我们 onCreate方法的返回类型在哪里?

在 Java 中如果我们不需要返回任何值使用” void”,在这里我们使用” Unit”替代,编译器将知道我们不需要返回任何东西,所以我们可以省略它,在这种情况下我们使用下面的方式添加.

1
override fun onCreate(savedInstanceState: Bundle?):Unit

参数的顺序将发生改变,首先你需要定义参数的名字,之后是类型

分号再见

在 Kotlin 中你不需要在代码的结尾添加”;”分号,但是你也可以添加(建议不要)

值和变量

定义一个变量使用” var“关键字,它的类型会在上下文中推断出来,另一个相同的常量使用” val“关键字

1
2
3
4
val price = 100        // Int
price = 30 // don't compile! it's a constant
var total = price * 3 // Int
val name = "Juancho" // String

你可以显示的指定类型

1
2
3
val lastname : String = "Keddit" // explicit type definition
var size : Double = 30.0
var time : Float = 15f

你可以注意到没有原始类型,我们不使用” double”而是” Double”.这是因为 Kotlin 中任何事物都是对象.为了提高性能,编译器在内部将转换一些对象到原始类型.

属性和字段

在 Kotlin 你访问属性,像在 Java 中访问字段.而不是从Activity调用它的 getResources() 方法.

1
2
3
resources.getString(R.string.id)
// vs
getResources().getString(R.string.id) // still allowed

你可以仍然调用 getResult() 方法,但是 Android Studio 建议你改变它.

这不以为这你直接访问这个字段,在内部它也是调用” getResource()”方法,但是这是更方便的方法.

Safe?:Safe!

这是一个在Kotlin 中伟大的事情,在 Kotlin 中没有可以为空的,除非你使用这个方法特别指定它,这个方法是使用”?

1
2
3
val a : String = null  // 不会编译!
var b : Int // 必须初始化,或者抽象
val ok : String? = null // 正确 :)

编译器将检测可能为空的对象,这将使你避免常见的” NullPointerException”

安全调用

与一个可以为空的对象交互式很简单的,”?”只会在这个对象存在的时候调用,否则将会忽略它,安全运行程序.

1
2
val context : Context? = null
val res = context?.getResources() // 不会崩溃,但是 res 将为空.

聪明的做法

如果你继续使用可以为空的对象,代码最终会是这样:

1
2
3
4
val context : Context? = null
val res = context?.getResources()
val appName = res?.getString(R.string.app_name)
val shortName = appName?.substring(0, 2)

这是很可怕的,你可以使用其他更好的方法,只是检测如果 context 不为空,其他的对象将是非空对象:

1
2
3
4
5
6
7
8
9
10
11
12
val context : Context? = null
if (context != null) {
val res = context.getResources() // 不需要 '?'
val appName = res.getString(R.string.app_name)
val shortName = appName.substring(0, 2)
}
val context : Context? = null
context?.let {
val res = context.getResources() // 不需要'?'
val appName = res.getString(R.string.app_name)
val shortName = appName.substring(0, 2)
}

Elvis 操作 ?:

使用”?:”操作符你可以为这个对象二选一值.它像一个短的空检查.在下面的例子中”message”可以为空,它的类型是” String?”.在这种情况下对象不为空将使用它的值,否则它将使用另一个值.

1
2
3
4
5
try {
// code...
} catch (e: Throwable) {
Log.e("TAG", e.message ?: "Error message")
}

静态类型

这将意味着 Kotlin 需要只要你在代码中的一切类型,因为编译器将在编译期间检测.Android Studio 将很好的支持,IDE 将做一个伟大的工作帮助我们知道分配一个值到另一个变量.

通常我们不需要指定一个变量的类型.下面的 toolbar 常量,它的类型将会从上下文中推断出来,这是一个其它关于 Kotlin伟大的特征.

1
val toolbar = findViewById(R.id.toolbar) as Toolbar

类型推断带来了很大的优势:可靠性(编译器将验证程序的正确性)、可维护性(代码通过它本身解析)、工具支持性能

完全与 Java 交互

这是另一个 Kotlin 伟大的特性,你可以在 Kotlin 中使用 Java 代码,反之亦然.

更新 MainActivity

我添加了一些代码到 MainActivity ,打开一个 在下一章创建的 fragment.

注意我们是如何使用 Fragment Manager 的

1
2
3
4
5
fun changeFragment(f: Fragment) {
val ft = supportFragmentManager.beginTransaction()
ft.replace(R.id.fl_container, f)
ft.commit()
}

这个新的方法 changeFragment 将允许我们在 activity 内部打开一个 fragment.

仓库

文章中所有的代码可以在这个仓库中获得

KedditBySteps

结论

这个部分只讲了一小部分关于 Kotlin 的概念,在之后的部分我们将继续学习更多.