配置相關(guān)
在build.gradle(app)中添加的內(nèi)容
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
apply plugin: 'kotlin-android-extensions'
其中第二個庫的作用是解決findViewById()問題
The Kotlin Android Extensions plugin allows us to obtain the same experience we have with some of these libraries, without having to add any extra code or shipping any additional runtime.
簡單創(chuàng)建項目流程
新建Activity并轉(zhuǎn)換成Kotlin類
文檔里提到的兩點
- Skip the "Converting Java code to Kotlin" step in Android Studio 3.0(3.0以后可以直接生成)
- Write it in Java, then copy-paste it into Kotlin file, and IDE will suggest to convert it
convert的快捷鍵是先輸入Ctrl+Shift+A
然后再在彈出的對話框中輸入convert

或者直接按Ctrl+Shift+ALT+K
如果是第一次在項目中使用java轉(zhuǎn)換kotlin,則需要config一下

語法
hello world
最簡版

| Java | Kotlin | |
|---|---|---|
| 方法標(biāo)志 | fun | |
| 數(shù)組標(biāo)志 | [ ] | Array |
| 形參 | 形參類型+形參名 | 形參名:形參類型 |
| 句尾 | 分號 | 無 |
進(jìn)化1:array access版
- args.size
- ${args[0]}
fun main(args: Array<String>) {
if (args.size == 0) {
println("Please provide a name as a command-line argument")
return
}
println("Hello, ${args[0]}!")
}
進(jìn)化2: 循環(huán)版
for (name in args)
println("Hello, $name!")
進(jìn)化3:分支版
- if(條件) 結(jié)果1 else 結(jié)果2
- when (條件){條件1->結(jié)果1...else->default結(jié)果 }
fun main(args: Array<String>) {
val language = if (args.size == 0) "EN" else args[0]
println(when (language) {
"EN" -> "Hello!"
"FR" -> "Salut!"
"IT" -> "Ciao!"
else -> "Sorry, I can't greet you in $language yet"
})
}
進(jìn)化4:面向?qū)ο蟀?/strong>
class Greeter(val name: String) {
fun greet() {
println("Hello, ${name}");
}
}
fun main(args: Array<String>) {
Greeter(args[0]).greet()
}
基本語法
條件表達(dá)式
搞一個性別轉(zhuǎn)換器,把男的變成女的,女的變成男的
fun main(args: Array<String>) {
println(transSex(args[0]))
}
fun transSex(a: String) = if (a == "男") "女" else "男"
非空檢查
Null Safety
以下一例是Kotlin的空值檢查簡單示例,計算兩個值的乘積。分別對輸入的兩個值進(jìn)行check,看是不是int,如果不是的話,catch異常,如果有一個輸入為空的話,則在main方法中處理。
// Return null if str does not hold a number
fun parseInt(str: String): Int? {
try {
return str.toInt()
} catch (e: NumberFormatException) {
println("One of the arguments isn't Int")
}
return null
}
fun main(args: Array<String>) {
if (args.size < 2) {
println("No number supplied");
} else {
val x = parseInt(args[0])
val y = parseInt(args[1])
// We cannot say 'x * y' now because they may hold nulls
if (x != null && y != null) {
print(x * y) // Now we can
} else {
println("One of the arguments is null")
}
}
}
is檢查
類似于java中的instanceOf方法,這樣在調(diào)用is-checked type的obj的方法時就不用再強轉(zhuǎn)。
Kotlin中的Any就是Java中的Object嗎?
/**
* The `is` operator checks if an expression is an instance of a type and more.
* If we is-checked an immutable local variable or property, there's no need
* to cast it explicitly to the is-checked type.
* See this pages for details:
* http://kotlinlang.org/docs/reference/classes.html#classes-and-inheritance
* http://kotlinlang.org/docs/reference/typecasts.html#smart-casts
*/
fun main(args: Array<String>) {
println(getStringLength("aaa"))
println(getStringLength(1))
}
fun getStringLength(obj: Any): Int? {
if (obj is String)
return obj.length // no cast to String is needed
return null
}
此例中還出現(xiàn)了Int?,以下對此進(jìn)行詳細(xì)的討論:
在Kotlin中,在reference分成了nullable references和non-null references,比方講一個常規(guī)的String變量是不能賦null值的,如果強行賦值,則會報compilation error。

如果想不報編譯錯誤的話,就在String后面加一個問號,使該string reference成為nullable string。

這時因為a可能為空值,如果去獲取a的長度的話,則會報編譯錯誤

解決方法是在.之前加上一個?。如果a不為null那么就返回a的長度,如果a為null就返回null。

還有一種方式就是在.之前加上!!,使用改操作符的區(qū)別是,如果a是null,拋出NPE。
如果在這一例的Int后面不加?的話,則編譯不會通過,因為Int類不接受null值,Int?接收

循環(huán)語句
While
fun main(args: Array<String>) {
var i = 0
while (i < args.size)
println(args[i++])
}
For
fun main(args: Array<String>) {
for (arg in args)
println(arg)
// or
println()
for (i in args.indices)
println(args[i])
}
輸入4及輸出結(jié)果:

a..b相當(dāng)于[a,b]
!in:不在
${x}:用在" "中
fun main(args: Array<String>) {
val x = args[0].toInt()
//Check if a number lies within a range:
val y = 10
if (x in 1..y - 1)
println("OK")
//Iterate over a range:
for (a in 1..5)
print("${a} ")
//Check if a number is out of range:
println()
val array = arrayListOf<String>()
array.add("aaa")
array.add("bbb")
array.add("ccc")
if (x !in 0..array.size - 1)
println("Out: array has only ${array.size} elements. x = ${x}")
//Check if a collection contains an object:
if ("aaa" in array) // collection.contains(obj) is called
println("Yes: array contains aaa")
if ("ddd" in array) // collection.contains(obj) is called
println("Yes: array contains ddd")
else
println("No: array doesn't contains ddd")
}
When
is和!is,類型檢查
輸出結(jié)果:

fun main(args: Array<String>) {
cases("Hello")
cases(1)
cases(0L)
cases(MyClass())
cases("hello")
}
fun cases(obj: Any) {
when (obj) {
1 -> println("One")
"Hello" -> println("Greeting")
is Long -> println("Long")
!is String -> println("Not a string")
else -> println("Unknown")
}
}
class MyClass() {
}
補充:
Java中的異常問題
Java異常的官方教程
Exception handling in Java?

Java中使用try...catch原因

What is the purpose of the try and catch blocks in Exceptions?

綜上,使用try...catch第一個作用是避免大量if...else使用,在第一例中,file的引用可能為空,line的引用也可能為空。用if...else,就要先判斷file不為空的情況,如果file不為空,再判斷str不為空的情況。用try...catch則把整個可能出現(xiàn)異常情況的語句都包含在其間。在第二例中可以看到,還可以在異常發(fā)生時,統(tǒng)一做一些相應(yīng)的處理,比如釋放資源等。
在上面兩例中,都有String的保護(hù)問題,String為什么需要進(jìn)行非空檢查?假如你寫的方法里去獲取str.length(),如果string為null的時候,就會拋出異常。
堆內(nèi)存、棧內(nèi)存
我們來看看其中最著名的異常之一:NPE
What is a NullPointerException, and how do I fix it?
Why do I get a NullPointerException?

左邊的表達(dá)式是int基本數(shù)據(jù)類型,而右邊則是Integer類。
int x;這句表達(dá)式,java會自動賦初始值0,但是當(dāng)Integer num;時,java將num設(shè)為null,意思是I am pointing at nothing. 如果這個引用變量是null的情況下,你去調(diào)用它的方法,就會拋出NPE。要了解整個賦值過程,必須要對heap和stack有一個簡要的理解:What and where are the stack and heap?

**stack **: local variables (including method parameters) are stored
heap: object variables, these are merely references (pointers) to the actual objects
String相關(guān)補充
先來看看String的兩種賦值方式:
What is the difference between “text” and new String(“text”)?
-
String s = "text";(string literal) -
String s = new String("text");(string object)
** new String("text");** explicitly creates a new and referentially distinct instance of a String object;
String s = "text"; may reuse an instance from the string constant pool if one is available.
使用string literal方式進(jìn)行賦值的時候,如果string constasnt pool中已經(jīng)存在該值,則會復(fù)用string constasnt pool中的instance variable。所有string literal都是String類的實例,也就是說當(dāng)你以string literal方式進(jìn)行賦值的時候,是編譯器來調(diào)用其構(gòu)造函數(shù)。
The
Stringclass represents character strings. All string literals in Java programs, such as"abc", are implemented as instances of this class.
因此會有如下經(jīng)典問題
String s1 = "foobar";
String s2 = "foobar";
System.out.println(s1 == s2); // true
s2 = new String("foobar");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
equals : checks the actual contents of the string
**== operator **: checks whether the references to the objects are equal
== 比較的是地址,equals比較的是實質(zhì)的內(nèi)容。stackoverflow上的網(wǎng)友給出的回答很贊,如果你是小王,你在北京和上海有兩套房子,你兩邊的鄰居都說“小王住在我隔壁”,如果用equals來比較小王,就是true,因為北京的小王和上海的小王都是小王。用==就是false,因為地址不一樣。
其他資料
pythontutor 這個網(wǎng)站可以可視化調(diào)用
Should I learn Kotlin or stick to Java?