Kotlin入门之程序结构

作者: wxyass 分类: Android,Kotlin 发布时间: 2018-03-13 19:13

一 常量与变量(val,var)

1.1 什么是常量

常量 定义不可变的量

val = value,值类型 | 类似 Java的final  | 不可能重复赋值  

举例:      
val x = getX()  // 运行时常量   
const val x = 2   // 编译期常量

从使用角度看 val和Java中的final是一样的

val FINAL_HELLO_WORLD: String = "HelloWorld"  
val FINAL_HELLO_CHINA = "HelloChina"

public final String FINAL_HELLO_WORLD = "HelloWorld";  

想要在Kotlin中获取编译期常量,需要在val前用const修饰

const val FINAL_HELLO_WORLD: String = "HelloWorld" 

1.2 什么是变量

var = variable   

举例:  
var x = "HelloWorld" // 定义变量  
x = "HiWorld" // 再次赋值  

1.3 类型推导

// 编译器可以推导量的类型    
val string = "Hello" // 推导出String类型    
val int = 5 // Int 类型     
var x = getString() + 5 // String 类型 

二 函数(function)

2.1 什么是函数

关键字fun

// 以特定功能组织起来的代码块
fun [函数名]([参数列表]):[返回值类型]{[函数体]}   
fun [函数名]([参数列表]) = [表达式]  

// 举例  
fun sayHi(name:String){println("Hi,$name")}  
fun sayHi(name:String) = println("Hi,$name")  

方法有返回值时,返回类型放在参数后面,用:连接

// 常见函数举例    
fun sum1(arg1: Int, arg2: Int):Int{
    return arg1 + arg2
}

fun sum2(arg1: Int, arg2: Int) = arg1 + arg2  

println(sum1(2,3))// 5
println(sum2(3,5))// 8 

方法没有返回值时,是Unit或者不写

fun main(args: Array<String>) {
    println("start")
    println("init a")  
}

2.2 什么是匿名函数

没有方法名的函数 (实际在底层是有名字的)

// 写法(注意要用变量接收?)  
fun([参数列表])...  

// 举例  
val sayHi = fun(name:String) = println("Hi,$name")   
println(sayHi("我是小明"))

匿名函数举例

// 匿名函数,需要用变量接收  
val intsum = fun(x: Int,y:Int): Int {
    return x + y
} 

println(intsum(6,5)) // 11

2.3 终止程序

fun checkArgs(args: Array<String>) {
    if (args.size != 2) {
        System.exit(-1)// 0xFF
    }
}    

2.4 编写函数的注意事项

  • 功能要单一
  • 函数名要做到顾名思义
  • 参数个数不要太多

三 Lambda表达式

1 什么是Lambda表达式

  • 简单说, 就是匿名函数
  • 写法: {[参数列表]->[函数体,最后一行是返回值]}
  • 举例: val sum = {a:Int,b:Int -> a+b }
val sum3 = { arg1:Int,arg2:Int -> arg1 + arg2}

val sum = { arg1: Int, arg2: Int ->
    println("$arg1 + $arg2 = ${arg1 + arg2}")
    arg1 + arg2
}  

2 Lambda 的类型表示举例

  • ()->Unit 无参,返回值为Unit
  • (Int)->Int 传入整型,返回一个整型
  • (String,(String)->String) -> Boolean 传入字符串,Lambda表达式,返回Boolean

3 Lambda表达式的调用

  • 用()进行调用, 理解为先定义匿名函数,再调用
  • 等价于 invoke()
  • 举例
    val sum = {a:Int,b:Int -> a+b }     
    sum(2,3)    
    sum.invoke(2,3)  
    

4 Lambda表达式的简化 (难以理解,需细细体会)

  • 函数参数调用时最后一个Lambda可以移出去
  • 函数参数只有一个lambda,调用时小括号可以省略
  • Lambda只有一个参数可默认为it
  • 入参,返回值与形参一致的函数可以用函数引用的方式作为实参传入

四 类成员(成员方法,成员变量)

4.1 什么是类成员

属性:或者说成员变量,类范围内的变量
方法:或者说成员函数,类范围内的函数

4.2 函数和方法的区别

函数强调功能本身,不考虑从属
方法的称呼通常是从类的角度出发
叫法不同而已,不要纠结

4.3 定义成员方法

写法与普通函数完全一致,只是将方法放在类中

class Hello{
    fun sayHello(name:String) = println("Hello,$name")
}  

成员方法举例

class 妹子(var 性格: String, var  长相: String, var 声音: String){
    // 成员方法  
    fun 唱歌(歌名: String){
        //唱歌的具体实现
        println("妹子正在唱歌: $歌名")
    }

    fun 跳舞(舞蹈名: String){
        //跳舞的具体实现
        println("妹子正在跳舞: $舞蹈名")
    }
}

fun main(args: Array<String>) {
    val 某个妹子 = 妹子("彪悍", "未知", "没听过")
    某个妹子.唱歌("歌唱祖国")
    某个妹子.跳舞("天鹅湖")
}  

// 妹子正在唱歌: 歌唱祖国
// 妹子正在跳舞: 天鹅湖  

4.4 定义成员变量

类的构造方法参数中 用val/var修饰的都是成员变量
类内部也可以用val/var来定义成员变量

class Hello(val aField:Int,notAField:Int){
    var anotherField:Float = 3f
}  

成员变量举例

class A{
    var b = 0
        get() {return field}
        set(value) {field = value}
}

4.5 属性访问控制

属性可以定义 getter/setter

val a : Int = 0  
    get()=field
var b : Float = 0f
    set(value){field = value} 

4.9 属性初始化

  • 属性的初始化尽量在构造方法中完成
  • 无法在构造方法中初始化,尝试降级为局部变量
  • var用lateinit 延迟初始化, val用lazy
  • 可空类型谨慎用null直接初始化

成员变量初始化举例

// 当成员变量使用 lateinit 修饰,需要初始化,但lateinit只能作用var  
// 对于val,使用lazy 来延时初始化   

class A{

    // 定义成员变量
    var b = 0
        get() {return field}
        set(value) {field = value}

    // var 使用lateinit修饰
    lateinit var c: String
    lateinit var d: X

    // val 使用lazy来延时初始化
    val e: X by lazy {
        println("init X")
        X()
    }

    // 不推荐这样初始化
    var cc: String? = null
}

class X

fun main(args: Array<String>) {

    // 新建一个A对象
    val a = A()


    println(a.b) // 打印0
    println(a.e) // 不报错 

    a.d = X()  // 对于lateinit修饰的变量,使用前必须初始化
    println(a.d) // 不报错 

    println(a.c) // 这行会报错,因为对于lateinit修饰的变量,使用前必须初始化    

    println(a.cc?.length)
}

五 基本运算符

5.1 基本运算符

  1. 实际上是一些函数
  2. operator 运算符函数 的关键字
  3. 任何类可以定义或者重载父类的基本运算符
  4. 通过运算符对应的具名函数来定义
  5. 对参数个数作要求,对参数和返回值类型不坐要求
  6. 不能想Scala一样定义任意运算符

  7. 查看文档

5.2 基本运算符举例

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)
    }

    operator fun plus(other: Any): Int{
        return real.toInt()
    }

    operator fun invoke(): Double{
        return Math.hypot(real, imaginary)
    }

    override fun toString(): String {
        return "$real + ${imaginary}i"
    }
}

class Book{
     infix fun on(any: Any): Boolean{
        return false
    }
}

class Desk

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
    println(c1+5) // 8 + 4I
    println(c1+"HelloWorld") // 3 


    //-name <Name>
    if("-name" in args){
        println(args[args.indexOf("-name") + 1]) // 打印-name后面的一个对象  
    }

    if(Book() on Desk()){ // dsl

    }
}   

六 表达式(中缀表达式,分支表达式,when表达式等)

6.1 中缀表达式

// 只有一个参数,且用infix修饰的函数

class Book{
    infix fun on(place:String){
        ...
    }
}

Book() on "My Desk"   

6.2 分支表达式

if表达式 其中 表达式必须完备

// 正确写法  
val x = if(b<0) 0 else b    

// 错误写法  
val x = if(b<0) 0 // 错误,赋值时,分支必须完备  

// 完整举例
private const val USERNAME = "kotlin"
private const val PASSWORD = "jetbrains"

private const val ADMIN_USER = "admin"
private const val ADMIN_PASSWD = "admin"

private const val DEBUG = 1
private const val USER = 0

fun main(args: Array<String>) {
    val mode = if(args.isNotEmpty() && args[0] == "1"){
        DEBUG
    }else{
        USER
    }

    println("请输入用户名:")
    val username = readLine()
    println("请输入密码:")
    val passwd = readLine()

    if(mode == DEBUG && username == ADMIN_USER 
                            && passwd == ADMIN_PASSWD) {
        println("管理员登录成功")
    }else if(username == USERNAME && passwd == PASSWORD){
        println("登录成功")
    }else{
        println("登录失败")
    }
}   

when关键字 满足第一条,后面的就不执行了

// 加强版switch , 支持任意类型   
// 支持纯表达式条件分支(类似if)   
// 表达式与完备性  

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]")
    }

    val mode = when{
        args.isNotEmpty() && args[0] == "1" -> 1
        else -> 0
    }.let(::println)
}   

七 循环语句(for循环,while循环,continue,break)

7.1 for循环

// 基本写法  
for(element in elements)...   

// 给任意类实现Iterator方法  
写法: ...  

7.2 for循环举例

fun main(args: Array<String>) { // args:  a b c d 

    for (arg in args){
        println(arg)
    }

    for((index, value) in args.withIndex()){
        println("$index -> $value")
    }

    for(indexedValue in args.withIndex()){
        println("${indexedValue.index} -> ${indexedValue.value}")
    }
}

// a
// b
// c
// d
// 0 -> a
// 1 -> b
// 2 -> c
// 3 -> d 
// 0 -> a
// 1 -> b
// 2 -> c
// 3 -> d 

7.3 for迭代自定义对象

fun main(args: Array<String>) {

    val list = MyIntList()
    list.add(1)
    list.add(2)
    list.add(3)

    for(i in list){
        println(i)
    }
}

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 fun iterator(): MyIterator{
        return MyIterator(list.iterator())
    }
}

// 1
// 2
// 3

7.4 while循环

// while(...)...   // 先判断条件,再执行函数体

// do...while(...)...  // 先执行函数体,在判断条件      

7.5 while循环举例

fun main(args: Array<String>) {

    var x = 5
    while(x > 0){ // 先判断条件,再执行函数体
        println(x)
        x--
    }

    do{ 
        println(x)
        x--
    }while (x > 0)// 先执行函数体,在判断条件

}

// 5
// 4
// 3
// 2
// 1

// 0

7.6 跳出循环(break),跳过循环(continue)

// 跳过当前循环用 continue
// 终止循环用break
// 多层循环嵌套的终止结合标签使用
Outter@for(...){
    Inner@while(i<0){
        if(...){
            break@Outter // break后加标签,则跳出Outter这个for循环,
                            // 如果break后什么也没有,则跳出while魂环  
        }
    }
}

7.7 跳过和终止循环举例

class Student{
    fun isNotClothedProperly(): Boolean{
        return false
    }
}

fun main(args: Array<String>) {
    val students = ArrayList<Student>()
    val you = Student()
    for (student in students){
        if(student == you) continue // 跳过这个对象,继续循环
        if(student.isNotClothedProperly()){
            break  // 跳出整个循环  
        }
    }
}

八 异常捕获(try,catch,finally)

8.1 try..catch的一般写法

fun main(args: Array<String>) {
    try {
        val arg1 = args[0].toInt() //1
        val arg2 = args[1].toInt() //2a
        println("$arg1 + $arg2 = ${sum(arg1, arg2)}")
    }catch (e: NumberFormatException){
        println("您确定输入的是整数吗?")
    }catch (e: ArrayIndexOutOfBoundsException){
        println("您确定输入的是两个整数吗?")
    }catch (e: Exception){
        println("程序出现了未知异常,可能是您的人品太差了。${e.message}")
    }finally {
        println("谢谢您使用我们的加法计算器")
    }
}

fun sum(arg1: Int, arg2: Int): Int{
    return arg1 + arg2
}

8.2 另外, try…catch 也是表达式

fun main(args: Array<String>) {
    val result = try{
        args[0].toInt() / args[1].toInt()
    }catch (e: Exception){
        0
    }finally{
        1
    }
    println(result)
}

// 0 

8.3 finally

// finally无论代码是否抛出异常都是会执行    
// 注意下面代码 ,先执行finally,在执行返回  
return try{ x/y } catch (e : Exception){0}finally{...}

九 具体参数,变长参数,默认参数

9.1 具体参数

// 给函数的实参附上形参
fun sum(arg1:Int,arg2:Int) = arg1+arg2  
sum(arg=2,arg2=3)

9.2 变长参数 ,普通传参

变长参数解释:
1 某个参数可以接收多个值
2 可以不为最后一个参数
3 如果传参时有歧义,需要使用具名参数
4 使用vararg修饰

fun main(vararg args: String) {
    hellc(4.0,1,2,3,4,string = "Hellc")
}

// 在Kotlin中变长参数可以在任意位置,而不是只能放在最后一个参数
fun hellc(double: Double,vararg ints: Int, string: String ){
    println(double)
    ints.forEach(::println)
    println(string)
}

// 4.0
// 1
// 2
// 3
// 4
// Hellc

9.3 变长参数,可接收数组 其中*号表示展开数组且只能作用于数组

fun main(vararg args: String) {
    val list = arrayListOf(1,3,4,5)
    val array = intArrayOf(1,3,4,5)
    hello(3.0, *array)
}

fun hello(double: Double, vararg ints: Int, string: String = "Hello"){
    println(double)
    ints.forEach(::println)
    println(string)
}


3.0
1
3
4
5
Hello

9.4 默认参数

解释:
1 为函数参数指定默认值
2 可以为任意位置的参数指定默认值
3 传参时,如果有歧义,需要使用剧名参数

fun main(vararg args: String) {
    val list = arrayListOf(1,3,4,5)
    val array = intArrayOf(1,3,4,5)
    hello(3.0, *array)
}

// 给参数设置默认值  
fun hello(double: Double, vararg ints: Int, string: String = "Hello"){
    println(double)
    ints.forEach(::println)
    println(string)
}

十 小案例:命令行计数器开发

fun main(args: Array<String>) {
    while (true) {
        try {
            println("请输入算式例如: 3 + 4")
            val input = readLine() ?: break
            val splits = input.trim().split(" ")
            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)(arg1, arg2)}")
        }catch (e: NumberFormatException){
            println("您确定输入的是数字吗?")
        }catch (e: IllegalArgumentException){
            println("您确定输入的是三个参数吗?或者您确定您的输入是用空格分隔的吗?")
        }catch (e: Exception){
            println("亲爱的用户,您的人品太差了,程序遇到了未知的异常,${e.message}")
        }

        println("再来一发?[Y]")
        val cmd = readLine()
        if (cmd == null || cmd.toLowerCase() != "y") {
            break
        }
    }
    println("感谢您使用我们的计算器。")
}

class Operator(op: String) {
    val opFun: (left: Double, right: Double) -> Double

    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 -> {
                throw UnsupportedOperationException(op)
            }
        }
    }

    operator fun invoke(left: Double, right: Double): Double {
        return opFun(left, right)
    }

}

十一 导出可执行程序

1 在build.gradle 中添加想要导出的类

apply plugin: 'application'
mainClassName = "com.wxyass.kotlin.CalcKt"

2 同步gradle

3 找到并打开 distribution — installDist

4 在build文件夹中找到导出的bat文件,可执行

5 使用命令行执行

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

邮箱地址不会被公开。 必填项已用*标注