2、Kotlin 基礎程序結構
一、Val和Var
1.一、val=value,值類型 ,相似Java的final修飾,不能夠重複賦值
ps:相似於java的中的final關鍵字修飾的 ,因此通常val 修飾的詞爲Final類型值
val定義的是常量
val FINAL_HELLO_CHINA = 「hello china」 //類型推導(Java中須要必須寫明final和修飾關鍵字)
在Java中含有final關鍵字修飾的變量,變量FINAL_HELLO_WORLD爲編譯期常量,在用到這個變量的時候,編譯器一概把 「對這個變量的引用都會自動換成 它的值類型進行使用」,提升代碼運行效率。
public String FINAL_HELLO_WORLD =「...「;
ex:
~運行時常量;val x =getX()
~編譯期常量: const val x:值類型=值
1.二、 var = variable 臨時變量
ex:
var x = 「HelloWorld 「 //定義變量
x = 「 hiWolrd 「 //再次賦值
類型推導
val String = 「hello」 //推導出String類型
val int = 5 //Int類型
var x = getString() + 5 //String 類型
二、函數 Function
什麼是函數?
以特定功能組織起來的代碼塊
fun[函數名](參數列表):[返回值類型] { 函數體}
fun[函數名](參數列表) = 表達式
ex:
fun sayFuck( name: String ) : String{ println(「fuck,$name」) }
fun sayFuck( name: String ) = println(「fuck,$name")
什麼是匿名函數?
fun(參數列表),必須賦值給一個變量不然沒法識別,如上例2
值類型返回值要加參數類型 ,默認返回類型是Unit
fun main(args: Array<String>) {
val arg1 = args[0].toInt()
val arg2 = args[1].toInt()
println("$arg1+$arg2= ${sum(arg1, arg2)}")
}
fun sum(arg1: Int, arg2: Int): Int {
return arg1 + arg2
}
kotlin簡便寫法:
fun sum(arg1: Int, arg2: Int) = arg1 + arg2
思考:方法必定有名字嘛?
答:用一個變量接收一個方法就不須要有名字了:
也就是一個變量的值是一個函數的返回值
val int2 = fun(x:Int ) : Long {
return x.toLong()
}
注意事項
- 方法要功能單一
- 函數名顧名思義
- 參數列表不要太複雜
三、類
ex:
public class JavaA {
private int b = 0;
public int getB() {
System.out.println("some one tyies to get b");
return b;
}
public void setB(int b) {
System.out.println("some one tyies to set b");
this.b = b;
}
}
class A {
在kotlin方法中get()、set()是默認實現的版本,想要實現必須得複寫get or set方法
var b = 0;
get() {
println("...")
return field //field 這裏指代b後面真正的值,只在get/set訪問器中才能訪問到
}
set(value){
field = value ; //至關於java中的this .b=b;
}
}
lateinit 延時初始化 and by lazy 懶加載
lateinit var c:String
延時初始化,在須要的時候進行初始化,禁止初始化以前使用
lateinit val e:x is false
var 可使用 lateinit 進行延時初始化,也只能使用在var上 ,
但val的延時初始化須要用下面的操做:
val e : X by lazy {
… //適合於val的懶加載模式
}
當var xx:String ?= null //初始化爲null而且可空類型
在使用的時候不可以使用,由於沒有向編譯器保證該值不能爲null
解決辦法:
println(cc ?. length) or println(cc !!. length)
類成員
屬性:或者說成員變量,類範圍內的變量
方法:或者說成員函數,類範圍內的函數
構造方法 參數中 val / var 修飾的都是屬性,沒有就只是構造方法的參數
一、val 沒有set()方法由於是不可變的final的
二、 屬性的初始化儘可能在構造方法中完成。
三、沒法在構造方法中完成初始化,嘗試降級爲局部變量
四、var用lateinit延遲初始化,val用lazy
五、可空類型謹慎用null直接初始化 (!!or?)
四、修飾符
kotlin 語言的修飾符 存放在kotlin源碼工程的kotlin/grammar/src/modifiers.grm 文件中,完整定義在kotlin/compiler/frontend/src/org/jetbrains/kotlin/lexer/KtToken.java源碼中
/**
## Modifiers
*/
modifiers
: (modifier| annotations)*
typeModifiers
: (suspendModifier| annotations)*
modifier
: classModifier
: accessModifier
: varianceAnnotation
: memberModifier
: parameterModifier
: typeParameterModifier
: functionModifier
: propertyModifier
classModifier 類修飾符
: "abstract" 抽象類
: "final" 不可被繼承final類
: "enum" 枚舉類
: "open" 可繼承open類
: "annotation" 註解類
: "sealed" 密封類
: "data" 數據類
memberModifier
: "override" 重寫函數
: "open" 可被重寫
: "final" 不可被重寫
: "abstract" 抽象函數
: "lateinit" 後期初始化
accessModifier 訪問權限控制, 默認是public
: "private"
: "protected"
: "public"
: "internal" 整個模塊內(模塊(module)是指一塊兒編譯的一組 Kotlin 源代碼文件: 例如,一個 IntelliJ IDEA 模塊,一個 Maven 工程, 或 Gradle 工程,經過 Ant 任務的一次調用編譯的一組文件等)可訪問;
varianceAnnotation 泛型可變性
: "in"
: "out"
parameterModifier
: "noinline"
: "crossinline"
: "vararg" 變長參數
typeParameterModifier
: "reified"
functionModifier
: "tailrec" 尾遞歸
: "operator"
: "infix"
: "inline"
: "external"
: suspendModifier
propertyModifier
: "const"
suspendModifier
: "suspend"
五、關鍵字 keywords
一些常見的關鍵字:
KtKeywordToken PACKAGE_KEYWORD = KtKeywordToken.keyword("package");
KtKeywordToken AS_KEYWORD = KtKeywordToken.keyword("as");
KtKeywordToken TYPE_ALIAS_KEYWORD = KtKeywordToken.keyword("typealias");
KtKeywordToken CLASS_KEYWORD = KtKeywordToken.keyword("class");
KtKeywordToken THIS_KEYWORD = KtKeywordToken.keyword("this");
KtKeywordToken SUPER_KEYWORD = KtKeywordToken.keyword("super");
KtKeywordToken VAL_KEYWORD = KtKeywordToken.keyword("val");
KtKeywordToken VAR_KEYWORD = KtKeywordToken.keyword("var");
KtKeywordToken FUN_KEYWORD = KtKeywordToken.keyword("fun");
KtKeywordToken FOR_KEYWORD = KtKeywordToken.keyword("for");
KtKeywordToken NULL_KEYWORD = KtKeywordToken.keyword("null");
KtKeywordToken TRUE_KEYWORD = KtKeywordToken.keyword("true");
KtKeywordToken FALSE_KEYWORD = KtKeywordToken.keyword("false");
KtKeywordToken IS_KEYWORD = KtKeywordToken.keyword("is");
KtModifierKeywordToken IN_KEYWORD = KtModifierKeywordToken.keywordModifier("in");
KtKeywordToken THROW_KEYWORD = KtKeywordToken.keyword("throw");
KtKeywordToken RETURN_KEYWORD = KtKeywordToken.keyword("return");
KtKeywordToken BREAK_KEYWORD = KtKeywordToken.keyword("break");
KtKeywordToken CONTINUE_KEYWORD = KtKeywordToken.keyword("continue");
KtKeywordToken OBJECT_KEYWORD = KtKeywordToken.keyword("object");
KtKeywordToken IF_KEYWORD = KtKeywordToken.keyword("if");
KtKeywordToken TRY_KEYWORD = KtKeywordToken.keyword("try");
KtKeywordToken ELSE_KEYWORD = KtKeywordToken.keyword("else");
KtKeywordToken WHILE_KEYWORD = KtKeywordToken.keyword("while");
KtKeywordToken DO_KEYWORD = KtKeywordToken.keyword("do");
KtKeywordToken WHEN_KEYWORD = KtKeywordToken.keyword("when");
KtKeywordToken INTERFACE_KEYWORD = KtKeywordToken.keyword("interface");
// Reserved for future use:
KtKeywordToken TYPEOF_KEYWORD = KtKeywordToken.keyword("typeof");
...
KtKeywordToken FILE_KEYWORD = KtKeywordToken.softKeyword("file");
KtKeywordToken FIELD_KEYWORD = KtKeywordToken.softKeyword("field");
KtKeywordToken PROPERTY_KEYWORD = KtKeywordToken.softKeyword("property");
KtKeywordToken RECEIVER_KEYWORD = KtKeywordToken.softKeyword("receiver");
KtKeywordToken PARAM_KEYWORD = KtKeywordToken.softKeyword("param");
KtKeywordToken SETPARAM_KEYWORD = KtKeywordToken.softKeyword("setparam");
KtKeywordToken DELEGATE_KEYWORD = KtKeywordToken.softKeyword("delegate");
KtKeywordToken IMPORT_KEYWORD = KtKeywordToken.softKeyword("import");
KtKeywordToken WHERE_KEYWORD = KtKeywordToken.softKeyword("where");
KtKeywordToken BY_KEYWORD = KtKeywordToken.softKeyword("by");
KtKeywordToken GET_KEYWORD = KtKeywordToken.softKeyword("get");
KtKeywordToken SET_KEYWORD = KtKeywordToken.softKeyword("set");
KtKeywordToken CONSTRUCTOR_KEYWORD = KtKeywordToken.softKeyword("constructor");
KtKeywordToken INIT_KEYWORD = KtKeywordToken.softKeyword("init");
KtModifierKeywordToken ABSTRACT_KEYWORD = KtModifierKeywordToken.softKeywordModifier("abstract");
KtModifierKeywordToken ENUM_KEYWORD = KtModifierKeywordToken.softKeywordModifier("enum");
KtModifierKeywordToken OPEN_KEYWORD = KtModifierKeywordToken.softKeywordModifier("open");
KtModifierKeywordToken INNER_KEYWORD = KtModifierKeywordToken.softKeywordModifier("inner");
KtModifierKeywordToken OVERRIDE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("override");
KtModifierKeywordToken PRIVATE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("private");
KtModifierKeywordToken PUBLIC_KEYWORD = KtModifierKeywordToken.softKeywordModifier("public");
KtModifierKeywordToken INTERNAL_KEYWORD = KtModifierKeywordToken.softKeywordModifier("internal");
KtModifierKeywordToken PROTECTED_KEYWORD = KtModifierKeywordToken.softKeywordModifier("protected");
KtKeywordToken CATCH_KEYWORD = KtKeywordToken.softKeyword("catch");
KtModifierKeywordToken OUT_KEYWORD = KtModifierKeywordToken.softKeywordModifier("out");
KtModifierKeywordToken VARARG_KEYWORD = KtModifierKeywordToken.softKeywordModifier("vararg");
KtModifierKeywordToken REIFIED_KEYWORD = KtModifierKeywordToken.softKeywordModifier("reified");
KtKeywordToken DYNAMIC_KEYWORD = KtKeywordToken.softKeyword("dynamic");
KtModifierKeywordToken COMPANION_KEYWORD = KtModifierKeywordToken.softKeywordModifier("companion");
KtModifierKeywordToken SEALED_KEYWORD = KtModifierKeywordToken.softKeywordModifier("sealed");
KtModifierKeywordToken DEFAULT_VISIBILITY_KEYWORD = PUBLIC_KEYWORD;
KtKeywordToken FINALLY_KEYWORD = KtKeywordToken.softKeyword("finally");
KtModifierKeywordToken FINAL_KEYWORD = KtModifierKeywordToken.softKeywordModifier("final");
KtModifierKeywordToken LATEINIT_KEYWORD = KtModifierKeywordToken.softKeywordModifier("lateinit");
KtModifierKeywordToken DATA_KEYWORD = KtModifierKeywordToken.softKeywordModifier("data");
KtModifierKeywordToken INLINE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("inline");
KtModifierKeywordToken NOINLINE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("noinline");
KtModifierKeywordToken TAILREC_KEYWORD = KtModifierKeywordToken.softKeywordModifier("tailrec");
KtModifierKeywordToken EXTERNAL_KEYWORD = KtModifierKeywordToken.softKeywordModifier("external");
KtModifierKeywordToken ANNOTATION_KEYWORD = KtModifierKeywordToken.softKeywordModifier("annotation");
KtModifierKeywordToken CROSSINLINE_KEYWORD = KtModifierKeywordToken.softKeywordModifier("crossinline");
KtModifierKeywordToken OPERATOR_KEYWORD = KtModifierKeywordToken.softKeywordModifier("operator");
KtModifierKeywordToken INFIX_KEYWORD = KtModifierKeywordToken.softKeywordModifier("infix");
KtModifierKeywordToken CONST_KEYWORD = KtModifierKeywordToken.softKeywordModifier("const");
KtModifierKeywordToken SUSPEND_KEYWORD = KtModifierKeywordToken.softKeywordModifier("suspend");
KtModifierKeywordToken HEADER_KEYWORD = KtModifierKeywordToken.softKeywordModifier("header");
KtModifierKeywordToken IMPL_KEYWORD = KtModifierKeywordToken.softKeywordModifier("impl");
this 關鍵字
- 持有當前對象的引用,使用this來引用變量或是成員函數,亦可使用return this,來返回某個類的引用
- 在類的成員中,this指向的是該類的當前對象
- 在擴展函數或者帶接收者的函數字面值中,this表示在點左側傳遞的 接收者參數
- 若是this沒有限定符,它指的是最內層的包含它的做用域;若是引用其餘做用域中的this,可使用this@label標籤
小示例:
class Outer {
val oh = "Oh!"
inner class Inner {
fun m() {
val outer = this@Outer
val inner = this@Inner
val pthis = this
println("outer=" + outer)
println("inner=" + inner)
println("pthis=" + pthis)
println(this@Outer.oh)
val fun1 = hello@ fun String.() {
val d1 = this // fun1 的接收者
println("d1" + d1)
}
val fun2 = { s: String ->
val d2 = this
println("d2=" + d2)
}
"abc".fun1()
fun2
}
}
}
六、基本運算(操做)符
- 運算符方法重載的定義,任何類能夠定義或是重載基本運算符
- 經過運算符對應的具名函數來定義,要求方法名字必須一致對的上,fun前面加上operator 關鍵字
- 參數的個數對的上,類型和返回類型不做要求
- 不能像Scala同樣定義任意運算符
6.一、操做符優先級
級別由上到下 ,由高到低
後綴 Postfix : 「++」 , " - - 「 ,」 .」 ,」 ?.」 ,」 ?"
前綴 Prefix : "- " ,"+ ", "++ ", " - - " , 「!」 ,」labelDefinition@"
右手類型運算 RHS:」 :" , " as " , "as?"
乘除取餘 Multiplicative : "* 「 , 「 / 「 , 「%"
加減 Additive : 「+」 , 「-"
區間範圍 Range : " ..」
Infix 函數 : 給Int 定義擴展 infix fun Int .shl( x:Int ) :Int {…} —>調用 1 shl 2 ,等同於1.shl(2)
Elvis 操做符 :「 ?:」
命名檢查符號 Named checks: 「in" , "!in」, 「is」, 「!is"
比較大小 Compariosn : 「<「 , 「>」 ,」<=「 , 「>="
相等性判斷 Equality : 「==「 , 「!=="
與 Conjunction : 「&&"
或 DIsjunction : 「||"
最低 賦值 Assignment : 「 = 「 , 「+= 「 ,」 -= 「 , 「*=「, 」/=「 , 「%="
6.2 、遞增 or 遞減
inc () / dec () 函數必須返回一個值,用於賦值給使用 ++ or — 操做的變量
a ++ : a.inc() 返回值 a
a - - : a.dec () 返回值 a
++ a : a.inc() 返回值 a+1
—a : a.dec() 返回值是 a-1
解析:
編譯器執行如下步驟來解析後綴表達式的操做符,例如:後綴形式a++
一、肯定a的類型 ,令其解析爲T
二、查找一個適用於類型爲T的接收者的、帶有operator修飾符的無參數函數inc()
三、檢查函數的返回類型是T的子類型
表達式計算步驟:
一、把a的初始值存儲到臨時存儲a _ 中
二、把a.inc ( ) 結果賦值給 a
三、把a_ 做爲表達式的結果返回
對於前綴形式:
++a 和 —a解析步驟相似,返回值不一樣是取的新值來返回
把 a.inc () 結果賦值給a
把 a的新值 a+1 做爲表達式結果返回
6.3 、算術運算符
a + b : a.plus ( b )
a - b : a.minus ( b )
a * b : a.times ( b )
a / b : a.div ( b )
a & b : a.rem ( b ) a.mod ( b )
a .. b : a .rangTo ( b )
6.4 、in 操做符
a in b : b.contains ( a )
a !in b : !b.contains ( a )
6.5 、計算並賦值
a += b : a .plusAssign ( b )
a -= b : a .minusAssign ( b )
a *= b : a .timesAssign ( b )
a /= b : a .divAssign ( b )
a %= b : a.modAssign ( b )
編譯器操做 a += b : 生成a = a+b 的代碼,a+b 的類型必須是a的子類
6.六、相等 與 不等操做符
a == b : a ?.equals ( b ) ?: ( b === null )
a != b : ! ( a ?.equals ( b ) ?: ( b === null ) )
在這裏 == 操做符 特殊性:被翻譯成一個複雜的表達式,用於篩選 null 值;
也就是說若是 a不是null,則調用 equals ( Any )函數並返回其值 ,不然 ( a === null ) 就計算 ( b === null )的值並返回
當與 null 顯示 比較時候, a == null 會被自動轉換爲 a === null
6.7 、 Elvis 操做符 ?:
在kotlin 中, Elvis 操做符 特定是跟null 比較 ,也就是說用來作null安全檢查
y = x ?: 0 ——>二元
等價於==》
val y = if ( x !== null ) x else 0 )——>kotlin 三元運算符
?: 這是一個二元運算符 ,若是第一個操做數爲真,則返回第一個操做數,不然將計算並返回其第二個操做數
注意:
用( ?: ) 能夠把帶有默認值的if/else 結構寫的精簡,不用檢查null,也不用重複變量
6.8 、中綴操做符
經過自定義infix函數來實現中綴操做符
示例:
data class Person ( val name :String .val age :Int )
infix fun Person.grow ( years:Int ) :Person{
return Person ( name ,age +years )
}
test:
@RunWith(Junit4::Class )
class InfixFunctionTest {
@Test
fun testInfixFuntion ( ){
val person = Person (「son」 ,25)
println ( person .grow (2 ) )
println ( person grow 2 )
}
結果:
name = son, /n age = 27
小示例
加法:
class Complex(var real: Double, var imaginary: Double) {
//定義一個加法函數
operator fun plus(other: Complex): Complex {
return Complex(real +other.real, imaginary + other.imaginary)
}
operator fun plus(other: Int): Complex {
return Complex(real + other, imaginary)
}
override fun toString(): String {
return "$real+${imaginary} i"//實部+虛部
}
//取模方法
operator fun invoke() :Double{
return Math.hypot(real, imaginary)
}
class Book {
//中綴表達式 infix
infix fun on(any: Any): Boolean {
return false
}
}
fun main(args: Array<String>) {
val c1 = Complex(3.0, 4.0) //3+4i
val c2 = Complex(2.0, 7.5) //2+7.5i
println(c1 + c2) //5+11.5i—>toString() 須要用到
println(c1 + 4)
println(c1) //(3的平方+4的平方) 再開方
//-name <Name> //args contains name,若是包含的話就取後面的Name
if ("-name" in args) { //in表示Array<out T>.contains(element: T): Boolean,
// 實際上返回的是indexOf >=0,若是indexOf有這個元素,返回的就是它的位置若是沒有返回 -1
println(args[args.indexOf("-name") + 1])//返回-name在args裏面的後面一個位置的值
}
if(Book() on Desk()) { … }//DSL裏常見 中綴表達式替換.()方法
}
}
七、Lambda表達式 *****
本質:匿名函數(能夠賦值和傳遞)
lambda表達式返回值 :表達式最後一行表達式的值
Lambda表達式(匿名函數)
寫法:{ [參數列表]->[函數體,最後一行時返回值] }
ex:
普通函數表達式:fun sum( arg1:Int, arg2:Int ) = arg1 + arg2
lambda 表達式 : val sum ={ arg1:Int ,arg2 :Int -> arg1+arg2 }
參數列表:arg1:Int ,arg2 :Int
函數體,返回值最後一行:arg1+arg2
-> xxx :lambda表達式返回值是表達式最後一行的值
val/var xxx = {函數體} ps:arg1:Int,arg2:Int ->arg1+arg2
arg1:Int 表示參數返回類型
arg1+arg2:函數返回值
->:用右箭頭連接
lambda表達式能夠做爲參數傳遞!
print(sum(1, 2))=== print(sum.invoke(1,3))是一個意思!—【invoke :運算符重載】
在kotlin中數組的遍歷兩種寫法:
for( i in args) { … } or for ( i in array.indices) {...} //在Program arguments裏: 添加參數中間用空格隔開
args.forEach( {…lambda...} )
注意:函數若是最後一個參數是lambda表達式,能夠將括號內的內容移動到括號外面,若括號內無內容可直接刪除。
forEach: Array的擴展方法 ,返回值是Unit類型,使用action調用傳遞的Array裏面的元素做爲參數
Array<out T> .forEach (action : (T) -> Unit ) :Unit {for (element in this ) action (element) }
action : (T):參數的類型
->Unit :lambda 表達式返回的類型
(action : (T) -> Unit )==lambda
args.forEach( {println(it)} ) === args.forEach(){ println(it) }====>
注意:若參數的最後一個是lambda表達式,能夠將( ) 移動到lambda表達式外面
args.forEach(::println) //[若傳入的函數和lambda表達式類型徹底同樣]
將println函數做爲參數傳遞 ,println的參數是Any,接收任何對象均可以
args.forEachForEach@{
if(i=x) return@ForEach
println(it)
}
println(...)
終斷lambda表達式的迭代。以上作法能夠跳出lambda表達式內的執行繼續執行lambda表達式下面的內容
@ForEach:接收Array<T>類型
Lambda表達式的類型舉例
main(args:Array<String>) 函數
—— 傳入參數 Array<String> -> Unit
println(…)
——傳入(Any?可空的any)-> 返回Unit
()->Unit
——無參,返回值Unit
(Int)->Int
——傳入整型,返回一個整型
(String,(String) ->String)->Boolean
——傳入字符串,lambda表達式,返回一個boolean
println(::printUsage is () -> Unit) :參數爲0的Function0 ()————具名函數printUsage()
invoke多少參數就是Function幾,最多能夠Function0-22
lambda表達式的調用
ex : val sum = {a:Int ,b:int -> a+b}
// in P1,in P2 out R ,傳入兩個int返回一個int ,Function0-22均調用invoke(參數列表)
sum(2,3) ——————> sum.invoke(2,3)
lambda表達式的簡化特色
- 函數參數調用時最後一個lambda表達式能夠移出去
- 函數參數只有一個lambda,調用時小括號能夠省略
- lambda只有一個參數可默認爲it
- 入參、返回值與形參一致的函數能夠用函數引用的方式做爲實參傳入(forEach裏面傳入一個printnln [::println])
八、表達式 -中綴表達式、分支表達式、when表達式
8.一、中綴表達式
只有一個參數,且用infix修飾的函數
ex:
class Book {
infix fun on ( place :String){
…}
}
Book() on 「My desk」()
8.二、 分支表達式
傳統的分支使用方法:
var max = a
if ( a < b )
max = b
搭配else 的使用:
var max : Int
if ( a > b )
max = a
else
max = b
kotlin 中的分支表達式:
8.2.1 、if表達式 :
if…else :
var x = if (b <0) 0 else b
var x = if (b <0) 0//錯誤 ,賦值時,分支必須完備
if max = if ( a >b ) {
a
}
else {
b
}
val mode = if (args.isNotEmpty() && args[0] == "1") {
//if表達式有返回值因此能夠作爲代碼塊,每一個分支裏面的最後一句話是其段的返回值
DEBUG
} else {
USER
}
注意:
一、在kotlin中沒有沒有 java中的這一種寫法: true ? 1:0 三元表達式或是說正則,對應的kotlin寫法是:
if( boolean ) 1 else 0
二、若是if 表達式 只有一個分支, 或者分支結果返回Unit ,其值也是Unit
三、else 和 else if 同時出現,else要再else if 以後
四、若是有多條else if 語句同時出現,那麼若是有一條else if 語句表達式測試成功,那麼就會忽略掉其餘全部else if 和else分支
五、若是出現多個if ,只有一個else情形,那麼else子句歸屬於最內層的if語句
8.2.2 、when表達式
增強版 switch,支持任意類型,不用寫break
支持純表達式條件分支 類型if
表達式與完備性
when 既能夠被看成表達式使用也能夠被看成語句使用;當被看成表達式,符合條件的分支的值就是整個表達式的值,若是看成語句使用,則忽略單個分支的值
fun pause() {
when (state) {
Player.State.BUFFERING -> {}
Player.State.PAUSED -> {}
Player.State.PLAYING -> {}
}
}
fun main(args: Array<String>) {
val x = 5
when (x) {
is Int -> println("Hello $x")
in 1..100 -> println("$x is in 1..100")
!in 1..100 -> println("$x is not in 1..100")
args[0].toInt() -> println("x == args[0」)
}
}
注意:
一、else 在when 分支裏至關於default 其餘分支都不知足條會到else分支裏
二、分支處理方式相同,用逗號分隔
三、分支條件能夠是常量也能夠是表達式
8.三、循環表達式
8.3.1 、for循環實例:
for(element in elements 任何提供迭代器的集合)… for{ :. keyword }
遍歷一個簡單的數組 or list :
for ( i in array.indices )
println ( array [i] )
等同於 下面的 i in args
A:
for (arg in args) { //for ( i in array.indices) {...}
println(arg)
}
B:庫函數 withIndex
for ((index, value) in
args.withIndex()) {
println("$index->$value")
//0 -> a 1-> b 2-> c 3-> d
}
C:結果和B如出一轍
for (indexedValue in args.withIndex()) {
println("${indexedValue.index}->${indexedValue.value}」)
//0 -> a 1-> b 2-> c 3-> d
}
解析:返回一個IndexValue 類型
public fun <T> Array<out T>.withIndex(): Iterable<IndexedValue<T>> {
return IndexingIterable { iterator() }
}
public data class IndexedValue<out T>(public val index: Int, public val value: T)
8.3.二、 while循環實例:while(…) / do {...} while(…)...
var x = 5
//一、首先判斷條件,接着執行循環體
while (x > 0) {
println(x)
x--
}
//二、先執行一次循環體,再判斷條件是否繼續執行
do {
println()
x--
} while (x > 0)
8.3.三、 continue、break 跳出循環實例
continue:跳過當前循環 ,直接進入循環體的下次循環;
break:終止最近的封閉循環 用break
class Student {
fun isNotClothedProperly(): Boolean {
return false
}
fun main(args: Array<String>) {
val you = Student()
val students = ArrayList<Student>()
for (students in students) {
if (students == you) continue //當條件知足時候 ,跳過循環
if (students.isNotClothedProperly()) {
break//當條件知足時候,跳出循環
}
}
}
}
8.3.四、 return 返回
在java,c語言中,return語句使用咱們在常見不過了。雖然在Scala、groovy語言中,函數的返回值能夠不須要在顯示的用return 來制定,可是咱們仍然認爲,使用return 的編碼風格更加容易閱讀
在kotlin中,除了表達式的值,
有返回值的函數都要求顯示使用return 來返回其值
小示例:
fun sum(a: Int ,b :Int ) :Int {
return a + b
}
fun max ( a:Int , b:Int ) :Int {
if ( a >b ) returna else returnb
}
or 在kotlin 中能夠直接使用 = 符號 直接返回一個函數體的值
fun sum ( a:Int , b :Int ) = a +b
fun max ( a:Int , b:Int ) = if ( a >b ) returna else b
注意:
ex1:
fun return_1( ){
val Array1 = intArrayOf( 1,2,3,4,5)
Array1.forEach {
if( it ==3 ) return
println(it)
}
}
結果:在遇到3的時候會直接返回 println結果: 1 2
用一個方法表達式替代內部匿名方法,在方法內部聲明一個return{ :. keyword} 將從其內部返回
ex2:
fun return2( ){
val intArray = intArrayOf (1,2,3,4,5)
intArray.forEach (
fun (a:Int ) {
if (a == 3) return
println(a)
})
}
結果:在運行時候遇到3會跳過它繼續執行,輸出結果:1 2 4 5
須要在返回的時候帶有一個值:
ex3:
return @ a1
結果:在標籤@a 上返回1,而不是「返回一個帶標籤的表達式(@a 1)」
8.四、 標籤 label
在kotlin中 任何表達式均可以用標籤來標記。標籤的格式爲標識符後跟 @ 符號;做用是用標籤來控制 return/break/continue的跳轉行爲
在lambda表達式開頭處添加標籤here@ ,能夠理解爲 該標籤至關於記錄了Lambda入口地址,而後在表達式內部使用了return@here來跳轉至lambda表達式該地址處
接收該Lambda表達式的函數是forEach ,因此能夠直接使用return@ForEach,來跳轉到此處執行下一輪循環;若是使用break在循環體中,是跳出最外層的循環
多層循環嵌套的終止結合標籤使用:
Outter@for (…) {
Inner@while ( i < 0) {
if( …)
// break :若沒有@Outter 這裏是把while循環給break掉,繼續執行for循環
break@Outter // 將for循環也給break 掉
}
}
8.五、 throw
throw 用來標記無返回的函數,它的類型是特殊類型Nothing。該類沒有值。和void 相似
fun fail (msg :String) :Noting {
throw IllegalArgumentException(msg)
}
throw 表達式賦值給一個變量,須要顯示聲明類型:Nothing
val ex:Nothing = throw Exception(「xxxxxx")
注意:該ex變量是Noting類型,沒有任何值,沒法看成參數傳遞給函數
8.六、課後小栗子:
自定義一個迭代器,實現數組的添加or 刪除功能
fun main(args: Array<String>) {
val list=MyIntList()
list.add(1)
list.add(2)
list.add(3)
}
class MyIterator(val iterator: Iterator<Int>) {
operator fun next(): Int {
return iterator.next()
}
operator fun hasNext(): Boolean {
return iterator.hasNext()
}
}
class MyIntList {
private val list = ArrayList<Int>()
fun add(int: Int) {
list.add(int)
}
fun remove(int: Int) {
list.remove(int)
}
//定義operator 運算符
operator fun iterator(): MyIterator {
return MyIterator(list.iterator())
}
}
八、異常捕獲
try{…}catch(e:xxxx){...}finally{…} 表達式,能夠用來賦值
val result = try{ … }catch(e:xxx){ … }
注意:
先執行finally 代碼在返回 return
return try { x/y
}catch (e: Exception ){
0
}finally{
…
}
九、具名參數、變長參數、默認參數
具名參數:指定實參的方式 ,在使用的時候須要賦值在括號裏(...)
fun sum( arg1: Int ,arg2: Int ) =arg1+arg2
sum ( arg1 = 2 ,arg2 =3) //參數位置能夠互換
變長參數:某個參數能夠接受多個值;能夠不爲最後一個參數;參數時候有歧義須要使用具名參數
args:Array<String> —> varargargs:String 二者徹底同樣
hello(1, 2, 3, 4, 5, string = "hello」)
//將hello賦值給string,在這裏使用具名參數,將1-5賦值給ints,後面複製給string
ex:
fun hello(vararg ints: Int, string: String) {
ints.forEach(::println)
println(string)
}
Spread Operator——變長參數場景
特色:
- *array :表示把array展開(只支持array數組),變成一個個元素傳入使用
- 該類僅支持變長參數的實參
- 不能重載
- 只能使用array數組 ,不能使用list 等其餘集合
val array = intArrayOf (1 ,2 ,3,4)
hello( 3.0, *array ,string = 「hello」)
默認參數:能夠指定給參數列表的任意一個參數,若是把默認參數指定給一個比較靠前位置的參數,其後面的參數須要使用具名參數的形式表示
一個簡單的命令行計算器:
/**
* 一個極簡的命令行計數器
* */
fun main(args: Array<String>) {
while (true) {
try {
println("請輸入算式數據,好比:1+1")
val input = readLine() ?: break
val splits = input.trim().split(" 「) //空格分隔符,並去掉string首尾空字符
if (splits.size < 3) {
throw IllegalArgumentException("參數個數異常")
}
val arg1 = splits[0].toDouble()
val op = splits[1] //運算符
val arg2 = splits[2].toDouble()
println(
"$arg1 $op $arg2=${
Operator(op).invoke(arg1, arg2)
}」
) //將op運算符賦值給等式
} catch (e: NumberFormatException) {
println("類型格式異常:" + e)
} catch (e: IllegalArgumentException) {
println("輸入是否爲三個參數的通常計算:" + e)
}
println("是否再來一次[Y]")
val cmd = readLine()
if (cmd == null || cmd.toLowerCase() == "y") {
println("輸入有誤請查看")
break
}
}
}
//定義一個運算類
class Operator(op: String) {
val opFun: (left: Double, right: Double) -> Double
//初始化opFun
init {
opFun = when(op) {
"+" -> { l, r -> l + r }
"-" -> { l, r -> l - r }
"*" -> { l, r -> l * r }
"/" -> { l, r -> l / r }
"%" -> { l, r -> l % r }
else -> {//when表達式的完備性
throw UnsupportedOperationException(op)
}
}
}
fun invoke(left: Double, right: Double): Double {
return opFun(left, right)
}
}
Kotlin導出執行程序
在根目錄 ,build.gradle中添加依賴:
apply plugin: ‘application'
mainClassName = 「包名.類名kt」
CMD: cd build/instal/下包名
授予權限:chmod 755 bin/下包名
bin/下包名