一、常量與變量(val,var)
- 1.什么是常量?
1 .val = value ,值類型;
2.類似Java的final;
3.不能重復(fù)賦值;
4.舉例:
運行時常量:val x = getX(); 也就是程序運行時才賦值喜每;
編譯期常量:const val x = 2 ;也就是在編譯時期就賦值了务唐;
- 2.什么是變量?
1.var=variable ;
2.可以再次賦值带兜;
3.舉例:
var x = "HelloWorld"http://定義變量
x = "HiWorld"http://再次賦值
示例如下:
/**
* 常量
* 帶const為編譯期的常量
* 不帶const的val為運行期常量
* 不能再次賦值
*/
const val FINAL_HELLO_WORLD:String = "Hello world"
//變量 能夠再次賦值
var helloworld:String = FINAL_HELLO_WORLD
二枫笛、類型推導(dǎo)
val string = "Hello"http://推導(dǎo)出String類型
val int = 5 //Int類型
var x = getString()+5 //String類型,加號在這里是連接符
三刚照、函數(shù)--單一原則:
1.任何函數(shù)都是以fun開頭的刑巧,緊接著的是方法名字,緊接著的是參數(shù)列表无畔,緊接著的是返回值啊楚,緊接著是函數(shù)體;
fun <MethodName>(<ParamsName>:<ParamsType>):<returnValue>{}
2.如果無返回值浑彰,可以寫:Unit或者在參數(shù)列表后什么都寫特幔;Unit類型Java中的void;
3.如果參數(shù)有多個,以逗號分開闸昨;
4.如果一個函數(shù)只是返回一個函數(shù)的表達式的值蚯斯,直接可以等于表達式即可;
5.函數(shù)的名字不是必須的饵较,如果有個變量接受返回值即可編譯通過拍嵌;--請看下面的例子
6.函數(shù)作為類型的一種出現(xiàn)的,可以被用來賦值與傳遞的循诉;
/**
* 函數(shù)
* methodName
* param1,param2是參數(shù)名
* String Int 是參數(shù)類型
* 備注:
* 1.任何函數(shù)都是以fun開頭的横辆;
* 2.如果參數(shù)有多個,以逗號分開茄猫;
* 3沒有返回值在參數(shù)后添加:Unit狈蚤,也可以不寫,這個Unit相當(dāng)于java里面的void划纽;
* 4如果一個函數(shù)只是返回一個函數(shù)的表達式的值脆侮,直接可以等于表達式即可;
*/
fun methodName(param1:String,param2:Int):Unit {
}
//帶返回值的函數(shù)
fun testMethod(args:String):String{
return args
}
/**
* 如果一個函數(shù)只是返回一個函數(shù)的表達式的值勇劣,直接可以等于表達式即可
*/
fun returnFun0(param1: Int, param2: Int):Int {
return param1+param2
}
//上面的等價于下面的寫法:
fun returnFun(param1:Int,param2:Int) = param1+param2
/**
* 函數(shù)可以沒有名字的靖避,如果有一個變量來接收的話即可
*/
val resultValue = fun(x: Int):Int {
return x
}
四、Lambda表達式
1.也就是匿名函數(shù)比默;函數(shù)作為類型的一種出現(xiàn)的幻捏,可以被用來賦值與傳遞的;
2.寫法:{[參數(shù)列表] ->[函數(shù)體命咐,最后一行是返回值]}
3.() -> Unit
--無參篡九,返回值為Unit;
4.(Int) -> Int
--有參-傳入Int類型醋奠,返回一個整數(shù)榛臼;
5.(String,(String) -> String) -> Boolean
--傳入字符串伊佃、Lambda表達式,返回Boolean讽坏;
- 1.Lambda表達式的調(diào)用
1.用括號()來表示方法的調(diào)用锭魔,是Kotlin中的運算符,等價于invoke();這個invoke其實是運算符重載的方法
2.Lambda表達式如果沒有參數(shù)路呜,箭頭 (->)就不用寫了迷捧;
3.Lambda表達式不是只有一行的,它的返回值是它表達式的最后一行的值胀葱;
val sum = {a:Int,b:Int ->a+b}
//用括號()來調(diào)用漠秋,等價于invoke();
sum(2,3)
或者使用:sum.invoke(2,3),二者完全等價抵屿;
//Lambda表達式?jīng)]有參數(shù)庆锦,箭頭可以不寫,如下:
val printHello = {
println("hello")//相當(dāng)于函數(shù)的函數(shù)體
}
//Lambda表達式不是只有一行的轧葛,它的返回值是它表達式的最后一行的值
val sum = {a:Int,b:Int ->
println("$a + $b = ${a+b}")//這一行也是表達式搂抒,不過返回的是Unit類型
a+b//這一行最為Lambda的最后一行,它的值也是Lambda的返回值尿扯;
}
- 2.Lambda表達式的簡化
- 1.函數(shù)參數(shù)調(diào)用時最后一個Lambda可以移出去求晶;也就是說如果一個函數(shù)調(diào)用時,最后一個參數(shù)是Lambda表達式衷笋,我們傳入?yún)?shù)時芳杏,那么這個參數(shù)可以被移出去;
- 2.函數(shù)的參數(shù)只有一個Lambda辟宗,調(diào)用時小括號可以省略爵赵;
- 3.如果一個Lambda只有一個參數(shù),可以不寫泊脐,可默認為it空幻;
- 4.入?yún)ⅰ⒎祷刂蹬c形參一致的函數(shù)可以用函數(shù)引用的方式作為實參傳入晨抡;
val sum = {a:Int,b:Int ->a+b}
//Lambda表達式在沒有參數(shù)時氛悬,箭頭就不用寫了,如下:
//如下面的寫法耘柱,因為沒有參數(shù),箭頭就不用寫了:
val printHello = {
println("hello")//相當(dāng)于函數(shù)的函數(shù)體
}
//看下面的數(shù)組遍歷:
arg.forEach{element -> println(element) }
//如果一個Lambda傳入的參數(shù)只有一個棍现,可以不寫调煎,可默認為it;上面的等價于:
arg.forEach{ println(it) }
//函數(shù)的參數(shù)只有一個Lambda表達式時己肮,調(diào)用時可以將大括號移到小括號外面士袄;
//上面的等價于下面的:
arg.forEach(){println(it)}
//這個小括號沒有什么用悲关,可以把這個小括號省略
arg.forEach{println(it)}
//如果函數(shù)的參數(shù)和返回值與action的參數(shù)和返回類型一致,就可以用函數(shù)引用的方式娄柳,如下:
arg.forEach(::println)
五寓辱、循環(huán)語句
for循環(huán)如下:
for (i in args) {
println("輸出的是:$i")
}
for ((index, value) in args.withIndex()) {
println("$index -> $value")
}
for (indexValue in args.withIndex()) {
println("${indexValue.index}---->${indexValue.value}")
}
//或者使用下面的方式
args.forEach{
println(it)
}
}
//看下面的一個方法,return會把函數(shù)截斷赤拒,無法執(zhí)行到最后一行
fun main(args: Array<String>) {
args.forEach {
if (it == "c") return
println(it)
}
//你會發(fā)現(xiàn)如果上面的if條件觸發(fā)了 秫筏,將跳出for循環(huán),并且執(zhí)行不到下面的代碼挎挖,原因是:
//上面的是表達式这敬,而不是一個簡單的遍歷,return會調(diào)出整個函數(shù)的執(zhí)行
println("The End")
}
//如果想只跳出it=="c"這個條件蕉朵,循環(huán)繼續(xù)進行崔涂,整個函數(shù)執(zhí)行完畢,可以如下:
fun main(args: Array<String>) {
args.forEach ForEach@ {
if (it == "c") return@ForEach
println(it)
}
println("The End")
}
while循環(huán)
var int = 5
while (int > 0) {
println("int---->$int")
int--
}
do {
println("int---->$int")
int--
}while (int>5)
如何跳出 或 跳過循環(huán)始衅?
跳出或終止循環(huán):break
跳過循環(huán):continue
多層嵌套循環(huán)的終止需要結(jié)合標簽來實現(xiàn)
Outter@ for (i in args) {
Inner@while (i.toInt() > 0) {
break@Outter //這里只是跳出外層的for循環(huán) break和@Outter之間不能有空格
}
}
六冷蚂、異常捕獲(try catch finally)
kotlin里面的異常捕獲和Java中的異常捕獲用法一樣,最后都會調(diào)用finally;但Kotlin中的try汛闸、catch也是表達式蝙茶,這點與Java中的不一樣,它可以有返回值蛉拙,返回值是表達式的最后一行的值尸闸;
- catch分支匹配異常類型;
- 它是一個表達式孕锄,可以用來賦值吮廉,與if else when 表達式是完全類似的;
- finally 無論try catch 是否拋出異常都會執(zhí)行到畸肆;
注意此行代碼代表的含義:
return try{ x/y } catch(e:Exception){ 0 } finally{...}
代表:先執(zhí)行finally里面的代碼宦芦,再返回;如果無異常轴脐,返回x/y调卑;如果有異常,返回0大咱;
//kotlin中的try catch也是表達式恬涧,可以有返回值;返回值是表達式的最后一行的值碴巾;
val result = try {
args[0]
} catch (e: Exception) {
println("jinlaile")
0
} finally {
println("進入finally代碼塊")
}
println(result)
輸出結(jié)果:
jinlaile
進入finally代碼塊
0
七溯捆、成員方法、成員變量
- 屬性:或者說是成員變量厦瓢,類范圍內(nèi)的變量提揍;構(gòu)造方法中val/var修飾的都是屬性啤月;類內(nèi)部也是可以定義屬性的的;
/**
* aField和anotherField是類Hello的兩個屬性劳跃;
* 而notField不是屬性谎仲,只是普通構(gòu)造方法的參數(shù);
*/
class Hello(val aField: Int, notField: Int){
val anotherField:String = "hello"
}
- 方法:或者說是成員函數(shù)刨仑,類范圍內(nèi)的函數(shù)郑诺;
在kotlin的類中,自動為var修飾成員變量實現(xiàn)了get贸人、set方法间景,val修飾的只有g(shù)et方法,因為val修飾的是不可變的艺智;如果想要在get倘要、set方法中注入部分邏輯,需要我們重寫其get十拣、set方法封拧,如下;
/**
* Created by serenitynanian on 2017/6/27.
*/
class ClassMemberAndField {
//默認訪問控制是public
var b = 0
get() {
println("執(zhí)行打印邏輯")
//這個filed其實是上面b后真正的值0夭问,這個filed只有在get泽西、set方法中才能訪問的到
return field
}
/**
* 類型java中的set方法
*
* public void setB(int b){
*
* this.b = b ;
* }
*/
set(value) {
println("執(zhí)行打印邏輯")
field = value
}
}
如果想要控制get缰趋、set的訪問權(quán)限捧杉,可以在get、set方法前加訪問限制符秘血,比如protected
protected set(value) {
println("logic")
field = value
}
如果說get味抖、set中沒有部分邏輯,只是想要修改訪問控制符灰粮,只需要如下寫即可:
class ClassMemberAndField {
//默認訪問控制是public
protected var b = 0
// get() {
// //這個filed其實是上面b后真正的值0仔涩,這個filed只有在get、set方法中才能訪問的到
// return field
// }
// /**
// * 類型java中的set方法
// *
// * public void setB(int b){
// *
// * this.b = b 粘舟;
// * }
// */
// protected set(value) {
// println("logic")
// field = value
// }
//如果只想要控制訪問權(quán)限熔脂,只需要這樣寫即可:
protected get
protected set
}
在kotlin中聲明成員變量時,編譯器提醒你必須初始化柑肴,否則報錯霞揉;與java不同的時,java會自動給你初始化初始值晰骑;但初始值也占內(nèi)存的零聚,所以有時我們只需要在使用時才想初始化,這樣怎么辦呢些侍?
只需要在聲明成員變量時指定一個lateinit特殊字符就行了隶症;但是在使用之前必須進行初始化,否則報錯岗宣;
var age:Int = 0
//如果不指定lateinit 編譯器會提醒必須初始化或者abstract蚂会,
//指定后就是告訴編譯器,我后面會進行初始化耗式;
//如果你在初始化它之前就使用這個變量胁住,會報錯的;
lateinit var name:String
但是lateinit只能放在var修飾的可變變量前面刊咳,不能放在val修飾的變量前面彪见;如果想要達到延遲初始化必須使用delegate,如下:
/**
* lazy需要傳入一個lambda表達式,一個無參的表達式返回一個T類型娱挨,
* 這個T類型就是下面的String類型余指;
*/
val address:String by lazy {
"dsfa"
}
總結(jié)下屬性訪問控制:
var修飾的有g(shù)et、set方法跷坝;
val修飾的只有g(shù)et方法酵镜,沒有set方法,因為val修飾的變量是不可變的柴钻;
總結(jié)下屬性初始化:
屬性的初始化盡量在構(gòu)造方法中進行初始化完成淮韭;
無法在構(gòu)造方法中初始化,嘗試降級為局部變量贴届;
var用lateinit延遲初始化靠粪,val用lazy;
可空類型謹慎使用null直接初始化毫蚓;
八占键、表達式(中綴表達式、分支表達式绍些、when表達式)
- 中綴表達式
- 只有一個參數(shù)捞慌,且用infix修飾的函數(shù);
class Book {
infix fun on(place: String) {
}
}
fun main(args: Array<String>) {
//函數(shù)前沒有使用infix關(guān)鍵字柬批,必須像平常調(diào)用函數(shù)一樣使用
Book().on("my desk")
//如果函數(shù)前面使用了infix啸澡,不用在方法前加. 不用在方法后加括號
Book() on "my dest"
}
2.使用了中綴表達式后,在調(diào)用時氮帐,可以直接使用[對象] <函數(shù)名> [參數(shù)對象] 如上示例嗅虏;
分支表達式(if),而不只是分支語句
分支表達式是可以有返回值的上沐,返回值是分支語句中最后一行的值 皮服;
private const val DEBUG = 1
private const val USER = 0
fun main(args: Array<String>) {
// var mode = USER
// if (args.isNotEmpty() && args[0] == "1") {
// mode = DEBUG
// }
/**
* 從下面可以看出來if可不只是一個簡單的分支語句,
* 它還是一個表達式,它是有返回值的龄广,返回值是是分支表達式中最后一行的值硫眯;
* 在上面的分支語句中,只能定義var的mode择同,因為后面要修改两入;
* 如果使用分支表達式,就直接可以使用val修飾的mode了敲才,使用如下:
*/
val mode =
if (args.isNotEmpty() && args[0] == "1") {
DEBUG
}else{
USER
}
println("請輸入用戶名:")
val username = readLine()
println("請輸入密碼:")
val password = readLine()
if (mode == DEBUG && username == USERNAME && password == PASSWORD) {
println("超管登錄成功")
} else if (username == USERNAME && password == PASSWORD) {
println("普通用戶登錄成功")
} else {
println("登錄失敗")
}
}
- when表達式
類似Java中的switch語句裹纳,由于case語句中只能判斷String,enum紧武,byte剃氧,int等,并且在每個分支語句中都要寫break阻星;在kotlin中沒有了switch語句了朋鞍,使用了when表達式來代替了;
public void pause() {
switch (state) {
case BUFFERING:
case PLAYING:
doPause();
break;
default:
//什么都不做
}
}
//下面是kotlin中的when表達式
fun pause() {
when (state) {
PlayerKt.State.BUFFERING, PlayerKt.State.PLAYING -> doPause()
else -> {
}
}
}
when分支表達式只要第一個分支語句執(zhí)行了迫横,不用使用break番舆,后面的分支語句就不會執(zhí)行了
fun main(args: Array<String>) {
var x = 5
//when表達式只要第一個分支語句執(zhí)行了,不用使用break,后面的就不會執(zhí)行了
when (x) {
is Int -> println("Hello $x")
in 1..100 -> println("$x is in 1..100")//x的值是否在[1,100]
!in 1..100 -> println("$x is not in 1..100")//x的值不在[1,100]
in 1 until 5 -> println("$x is in[0,5)")//x的值是否在[0,5)之間矾踱,取不到5
args[0].toInt() -> println("x == args[0]")//這個是說args[0]是否與x一樣
}
}
//when與if一樣恨狈,也有返回值,都是每一個分支最后一行表達式的值呛讲;
val mode = when {
args.isNotEmpty()&& args[0] == "1" -> 1
else -> 0
}
表達式總結(jié):
- if ... else ...這個用法基本和Java中一致禾怠;
- 表達式必須具備完整性,如果只有if沒有else編譯報錯;
var b = if (mode == 0) {
0
}
//如果沒有下面的分支語句贝搁,編譯報錯
//賦值時吗氏,分支必須完備
else {
1
}
- when表達式,加強版的switch雷逆,支持任意類型弦讽,也不用寫break;
支持純表達式條件分支(類似if)
val mode = when {
args.isNotEmpty()&& args[0] == "1" -> 1
else -> 0
}
必須具備完備性膀哲;
九往产、具名參數(shù),變長參數(shù)某宪,默認參數(shù)
- 具名參數(shù):就是在給函數(shù)傳入實參的時候仿村,把形參也賦值上,也就是下面在調(diào)用sum函數(shù)時兴喂,在傳入實參的時候蔼囊,把arg1 和 arg2也附帶上(arg1 = 1焚志,arg2 = 2);
具名參數(shù)的順序可以不是固定的畏鼓;
class ForDemo {
fun sum(arg1:Int,arg2:Int) = arg1 + arg2
}
fun main(args: Array<String>) {
var forDemo = ForDemo()
/**
* 在使用函數(shù)傳入實參的時候酱酬,把形參也賦上;
* 因為是具名參數(shù),所以形參的順序可以不固定
* 也就是明確告訴編譯器這個2是給arg2的滴肿,1是給arg1的
*/
forDemo.sum(arg2 = 2, arg1 = 1)
}
- 變長參數(shù)
某個參數(shù)可以接收多個值岳悟;
變長參數(shù)可以不為最后一個參數(shù);但是傳入實參時泼差,可以放在最后用具名參數(shù)表示即可;
如果傳參有歧義呵俏,需要使用具名參數(shù)指定某個特定參數(shù)堆缘;
最常見的就是main函數(shù),它里面是個數(shù)組普碎,我們可以將它改變?yōu)樽冮L參數(shù)吼肥;它的使用和數(shù)組完全一樣
var array = intArrayOf(1,23,43,25,56)
hello(3.0,1,123,321,2,string = "hello")
//*:Spread Operator這個符號現(xiàn)在只支持變長參數(shù),且只支持array麻车,不支持list
hello(3.0,*array,string = "hello")
fun hello(double:Double,vararg ints: Int,string:String) {
ints.forEach { ::println }
}
在Java中變長參數(shù)只能是函數(shù)的最后一個參數(shù)缀皱,否則編譯器無法識別的;
在kotlin中因為存在具名函數(shù)动猬,因此它可以放在任意位置啤斗;在傳入實參的時候可以用具名函數(shù)放在最后一個位置;
*:Spread Operator 這個不是一般的運算符赁咙;
只支持展開Array;
只用于變長參數(shù)列表的實參钮莲;
不能重載;
- 默認參數(shù)
1.就是在函數(shù)編寫時彼水,可以給函數(shù)任意位置的形參一個默認值崔拥;在實際調(diào)用函數(shù)時,這個參數(shù)可以不傳凤覆;
2.但是如果該默認參數(shù)不是最后一個链瓦,其他參數(shù)使用具名參數(shù)即可,不用寫默認的盯桦;
3.傳參出現(xiàn)歧義時慈俯,也就是編譯器報錯,需要使用具名函數(shù)俺附,具體請看第二條肥卡;
hello(3.0,1,123,321,2,string = "hello")
//* 這個符號現(xiàn)在只支持變長參數(shù),且只支持array事镣,不支持list
hello(ints = *array,string = "hello")
fun hello(double:Double = 3.0 ,vararg ints: Int,string:String) {
ints.forEach { ::println }
}