二、Kotlin 基础程序结构
1、Val和Var
1.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.2、 var = variable 临时变量
ex:
var x = “HelloWorld “ //定义变量
x = “ hiWolrd “ //再次赋值
类型推导
val String = “hello” //推导出String类型
val int = 5 //Int类型
var x = getString() + 5 //String 类型
2、函数 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()
}
注意事项
- 方法要功能单一
- 函数名顾名思义
- 参数列表不要太复杂
3、类
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 修饰的都是属性,没有就只是构造方法的参数
1、val 没有set()方法因为是不可变的final的
2、 属性的初始化尽量在构造方法中完成。
3、无法在构造方法中完成初始化,尝试降级为局部变量
4、var用lateinit延迟初始化,val用lazy
5、可空类型谨慎用null直接初始化 (!!or?)
4、修饰符
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"
5、关键字 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
}
}
}
6、基本运算(操作)符
- 运算符方法重载的定义,任何类可以定义或是重载基本运算符
- 通过运算符对应的具名函数来定义,要求方法名字必须一致对的上,fun前面加上operator 关键字
- 参数的个数对的上,类型和返回类型不作要求
- 不能像Scala一样定义任意运算符
6.1、操作符优先级
级别由上到下 ,由高到低
后缀 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++
1、确定a的类型 ,令其解析为T
2、查找一个适用于类型为T的接收者的、带有operator修饰符的无参数函数inc()
3、检查函数的返回类型是T的子类型
表达式计算步骤:
1、把a的初始值存储到临时存储a _ 中
2、把a.inc ( ) 结果赋值给 a
3、把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.6、相等 与 不等操作符
-
引用相等 "===" , " !==“ ————》两个引用指向同一对象————〉不能重载!!!
- 结构相等 “ == “ , “ != “ ————> 使用 equals() 判断
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里常见 中缀表达式替换.()方法
}
}
7、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表达式的调用
- 用()进行调用
- 等价于invoke()
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])
8、表达式 -中缀表达式、分支表达式、when表达式
8.1、中缀表达式
只有一个参数,且用infix修饰的函数
ex:
class Book {
infix fun on ( place :String){
…}
}
Book() on “My desk”()
8.2、 分支表达式
传统的分支使用方法:
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 :
- 表达式与完备性
- if(boolean)
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
}
注意:
1、在kotlin中没有没有 java中的这一种写法: true ? 1:0 三元表达式或是说正则,对应的kotlin写法是:
if( boolean ) 1 else 0
2、如果if 表达式 只有一个分支, 或者分支结果返回Unit ,其值也是Unit
3、else 和 else if 同时出现,else要再else if 之后
4、如果有多条else if 语句同时出现,那么如果有一条else if 语句表达式测试成功,那么就会忽略掉其他所有else if 和else分支
5、如果出现多个if ,只有一个else情形,那么else子句归属于最内层的if语句
8.2.2 、when表达式
- 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”)
}
}
注意:
1、else 在when 分支里相当于default 其他分支都不满足条会到else分支里
2、分支处理方式相同,用逗号分隔
3、分支条件可以是常量也可以是表达式
8.3、循环表达式
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.2、 while循环实例:while(…) / do {...} while(…)...
var x = 5
//1、首先判断条件,接着执行循环体
while (x > 0) {
println(x)
x--
}
//2、先执行一次循环体,再判断条件是否继续执行
do {
println()
x--
} while (x > 0)
8.3.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.4、 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
注意:
-
在koltin中 return 语句会从最近的函数 或 匿名函数中 返回,但是在Lambda表达式中遇到return ,则直接返回最近的外层函数
-
在非全局的返回只支持内部方法,如果我们只是需要跳出内部方法,就必须标记它并且返回这个标签
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.4、 标签 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.5、 throw
throw 用来标记无返回的函数,它的类型是特殊类型Nothing。该类没有值。和void 类似
fun fail (msg :String) :Noting {
throw IllegalArgumentException(msg)
}
throw 表达式赋值给一个变量,需要显示声明类型:Nothing
val ex:Nothing = throw Exception(“xxxxxx")
注意:该ex变量是Noting类型,没有任何值,无法当作参数传递给函数
8.6、课后小栗子:
自定义一个迭代器,实现数组的添加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())
}
}
8、异常捕获
try{…}catch(e:xxxx){...}finally{…} 表达式,可以用来赋值
val result = try{ … }catch(e:xxx){ … }
注意:
先执行finally 代码在返回 return
return try { x/y
}catch (e: Exception ){
0
}finally{
…
}
9、具名参数、变长参数、默认参数
具名参数:指定实参的方式 ,在使用的时候需要赋值在括号里(...)
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/下包名