Kotlin | 2.Kotlin基础

  • 声明函数、变量、类、枚举以及类型
  • Kotlin中的控制结构
  • 智能转换
  • 抛出和处理异常

函数学习

函数和变量

函数

    /**
     *  求最大值
     * if是表达式而不是语句,表达式有值,语句没有。
     * java中所有的控制结构都是语句
     * kotlin中除了循环以外大多数控制结构都是表达式
     */
    private fun max(a: Int, b: Int): Int {
        return if (a > b) a else b
    }

    /**
     * 如果函数体写在花括号中,我们说这个函数有代码块体。
     * 如果直接返回了一个表达式体,他就有表达式体。
     */
    fun max2(a: Int, b: Int): Int = if (a > b) a else b

变量

可变变量和不可变变量
  • val - 不可变引用。 相当于Java的final变量。
  • var - 可变引用。 普通的Java变量。

在定义了val变量的代码块执行期间,val变量只能进行唯一一次初始化。但是,如果编译器能确保只有唯一一条初始化语句被执行,可以根据条件使用不同的值来初始化它:

val message:String
if (CanPerformOperation()){
   message = "Success"
   // ...
} else{
   message = "Failed"
}

注意:尽管val引用自身是不可变的,但是它指向的对象可能是可变的。例如:

val languages = arrayListOf("Java")  // 声明不可变引用
languages.add("Kotlin")              // 改变引用指向的对象

错误:类型不匹配

var answer = 42
answer = "no answer"

字符串模板

        var a1 = 1
        val s1 = "a is $a1"
        a1 = 3
        // 模板中的任意表达式
        val s2 = "${s1.replace("is", "was")},but no is $a1"
        // a was 1, but now is 3
        Log.e("s2", s2)

和许多脚本语言一样,只需要在变量名称前加上 ,就可以在字符串字面值中引用局部变量。 引用""需要转义“\$”

类和属性

在Kotlin中,public是默认的可见性,所以你能省略它。

public class Person {
    
    private final String name;

    public Person(String name) {
        this.name = name;
    }
}

--->

class Person(private val name: String)

属性

class PersonProperty {

    // 只读属性:生成一个字段和一个简单的getter
    val name: String = "kotlin_hahaha"

    // 可写属性:一个字段、一个getter和一个setter
    var isMarried: Boolean = false

    fun set() {
        isMarried = true
    }
}

自定义访问器

/**
 * Created by jingbin on 2018/11/18.
 * 自定义访问器
 * 也可以使用函数返回,实现和性能没有差别,唯一的差别是可读性
 * 通常来说:
 * 如果描述的是类的特征(属性),应该把它声明成属性。
 */
class Rectangle(val height: Int, val width: Int) {

    // 函数表达式 可以赋值
    val isSquare: Boolean
    // 声明属性的getter
        get() {
            return height == width
        }

}

Kotlin源码布局:目录和包

1.把类和函数的声明放在包中,可以同级

class Rectangle(val height: Int, val width: Int) {

    // 函数表达式 可以赋值
    val isSquare: Boolean
    // 声明属性的getter
        get() {
            return height == width
        }

}

fun createRandomRectangle(): Rectangle {
    val random = Random()
    return Rectangle(random.nextInt(), random.nextInt())
}

Kotlin不区分导入的是类还是函数,而且,它允许使用import关键字导入任何种类的声明。可以直接导入顶层函数的名称。

2.导入其他包中的函数

// 导入函数的名称
import com.kotlin.jingbin.kotlinapp.classproperty.createRandomRectangle
// 导入其他包中的函数
LogUtil.e(createRandomRectangle().isSquare)

包层级和java类似。

表示和处理选择: 枚举和"when"

when结构,java中switch结构的替代品,但是更强大。智能转换。

枚举

1.声明简单的枚举类
enum class SimpleColor {
    RED, ORANGE
}
2.声明一个带属性的枚举类
enum class Color(
        // 声明枚举常量的属性
        val r: Int, val g: Int, val b: Int) {
    // 在每一个常量创建的时候指定属性值
    RED(255, 0, 0),
    ORANGE(255, 165, 0),
    WELLOW(255, 255, 0),
    GREEN(0, 255, 0),
    BULE(0, 0, 255),
    INDIGO(75, 0, 130),
    VIILET(238, 130, 238);// 分号

    fun rgb() = (r * 256 + g) * 256 + b
}
3.使用“when”处理枚举类
 /**
     * 使用when处理枚举类:
     * 直接返回一个“when"表达式
     */
    fun getMnemonic(color: Color) = {
        when (color) {
            RED -> "Richard"
            ORANGE -> "Of"
            WELLOW -> "Haha"
            // 合并多个选项
            BULE, GREEN -> "望穿"
            VIILET, INDIGO -> "秋水"
        }
    }

when

1、在 when 结构中使用任意对象
fun mix(c1: Color, c2: Color) = {
        // when 表达式的实参可以是任何对象,它被检查是否与分支条件对等
        when (setOf(c1, c2)) {
            setOf(Color.RED, Color.YELLOW) -> Color.ORANGE
            setOf(Color.BLUE, Color.YELLOW) -> Color.GREEN
            setOf(Color.BLUE, Color.VIOLET) -> Color.INDIGO
        // 如果没有任何其他分支匹配这里就会执行
            else -> throw Exception("Dirty color")
        }
    }
2、不带参数的 when
fun minOptimized(c1: Color, c2: Color) = {
        // 没有实参传给 when
        when {
            (c1 == Color.RED && c2 == Color.YELLOW) || (c2 == Color.RED && c1 == Color.YELLOW) -> Color.ORANGE
            (c1 == Color.BLUE && c2 == Color.YELLOW) || (c2 == Color.BLUE && c1 == Color.YELLOW) -> Color.GREEN
            (c1 == Color.BLUE && c2 == Color.VIOLET) || (c2 == Color.BLUE && c1 == Color.VIOLET) -> Color.INDIGO

            else -> throw Exception("Dirty color")
        }
    }
3、智能转换:合并类型检查和转换
// 3.1表达式层次结构
    interface Expr

    // 简单的值对象类,只有一个属性value,实现了Expr接口
    class Num(val value: Int) : Expr

    // sum运算的实参可以是任何Expr: Num或者另一个Sum
    class Sum(val left: Expr, val right: Expr) : Expr

    /**
     * 3.2 使用 if 层叠对表达式求值
     * 在 Kotlin 中,如果你检查过一个变量是某种类型,后面就不再需要转换它,可以就把它当作你检查过的类型使用。
     * 事实上编译器为你执行了类型转换,我们把这种行为称为智能转换。
     * */
    fun eval(e: Expr): Int {
        // is - instanceOf
        if (e is Num) {
            // 显示的转换成类型 Num是多余的
            val num = e as Num
            return num.value
        }
        if (e is Sum) {
            // 变量 e 被智能转换了类型
            return eval(e.left) + eval(e.right)
        }
        throw IllegalAccessException("Unknown expression")
4、重构:用“when”代替“if”
/**
     * Kotlin 中没有三元运算符,因为if有返回值
     * 意味着: 可以用表达式语法重写eval函数,去掉return语句和花括号,使用if表达式作为函数体
     */
    // 4.1 使用用返回值的 if 表达式
    fun eval2(e: Expr): Int =
            if (e is Num) {
                e.value
            } else if (e is Sum) {
                eval2(e.right) + eval2(e.left)
            } else {
                throw IllegalAccessException("Unknown expression")
            }

    // 4.2 使用 when 代替 if 层叠
    fun eval3(e: Expr): Int =
            when (e) {
                is Num -> e.value
                is Sum -> eval3(e.right) + eval3(e.left)
                else -> throw IllegalAccessException("Unknown expression")
            }
5、代码块作为 “if” 和 “when” 的分支
/**
     * 一个函数要么具有不是代码块的表达式函数体,
     * 要么具有包含显示return语句的代码块函数体
     */
    // 在分支中含有混合操作的 when
    fun evalWithLogging(e: Expr): Int =
            when (e) {
                is Num -> {
                    LogUtil.e("num: ${e.value}")
                    e.value
                }
                is Sum -> {
                    val left = this.evalWithLogging(e.left)
                    val right = this.evalWithLogging(e.right)
                    LogUtil.e("Sum: $left + $right")
                    // 代码块中最后的表达式就是结果
                    left + right
                }
                else -> throw IllegalAccessException("Unknown expression")
            }

迭代事物: “when”循环和“for”循环

1、“while” 循环

Kotlin 有 while 循环和 do-while 循环,他们的语法和Java中相应的循环没有什么区别

2、迭代数字:区间和数列

 /**
     * 区间:区间本质上就是两个值之间的间隔,这两个值通常是数字:一个起始值,一个结束值。
     * 使用 .. 运算符来表示区间
     * 数列:你能用整数区间做的最基本的事情就是循环迭代其中所有的值。
     * 如果你能迭代区间中所有的值,这样的区间被称作数列。
     * */

    val oneToTen = 1..10

    // 使用 when 实现 Fizz-Buzz 游戏
    fun fizzBuzz(i: Int) = when {
        i % 15 == 0 -> "FizzBuzz"
        i % 3 == 0 -> "Fizz"
        i % 5 == 0 -> "Buzz"
        else -> "$i"
    }

        for (i in 1..100) {
//            LogUtil.e(fizzBuzz(i))
        }
        // 倒序 只计偶数 [使用 until 函数可以标识:不包含指定结束值的半闭合区间]
        for (i in 100 downTo 0 step 2) {
            LogUtil.e(fizzBuzz(i))
        }

3、迭代map

       // 使用 TreeMap 让键排序
        val binaryReps = TreeMap<Char, String>()
        // 创建字符区间 包括 F
        for (c in 'A'..'F') {
            // 把 ASCII 码转换成二进制
            val binaryString = Integer.toBinaryString(c.toInt())
            binaryReps[c] = binaryString
        }
        // 迭代 map ,把键和值赋值给两个变量
        for ((letter, binary) in binaryReps) {
            LogUtil.e("$letter = $binary")
        }

        // 迭代集合时 使用下标
        val list = arrayListOf("10", "11", "1001")
        for ((index, element) in list.withIndex()) {
            LogUtil.e("$index = $element")
        }

4、使用 “in” 检查集合和区间的成员

   // 1.使用 in 检查区间的成员
    fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'

    fun isNoDigitic(c: Char) = c !in '0'..'9'

    // 2.用 in 检查作为when分支
    fun recognize(c: Char) = when (c) {
        in '0'..'9' -> "In's a digit!"
        in 'a'..'z', in 'A'..'Z' -> "In's a letter!"
        else -> "I don't know.."
    }

Kotlin中的异常

// val 不能再赋值,相当于 final
        val percentage = 0

        if (percentage !in 0..100) {
            throw IllegalAccessException("A percentage value must be between 0 and 100: $percentage")
        }
        /**
         * 和所有其他类一样,不必使用 new 关键字来创建异常实例。
         * 和java不同的是,Kotlin中throw结构是一个表达式,能作为另一个表达式的一部分使用:
         */

        val number = 8
        val percentage2 =
                if (number in 0..100) {
                    number
                } else {
                    // throw 是一个表达式
                    throw IllegalAccessException("A percentage value must be between 0 and 100: $percentage")
                }

        val bufferedReader = BufferedReader(StringReader("239"))

1、try catch 和 finally

// 不必显式地知道这个函数可能抛出的异常
    fun readNumber(reader: BufferedReader): Int? {
        try {
            val line = reader.readLine()
            return Integer.parseInt(line)

            // 异常类型在右边
        } catch (e: NumberFormatException) {
            return null
        } finally {
            reader.close()
        }
    }

2、try 作为表达式

fun readNumber2(reader: BufferedReader) {
        val number = try {
            // 没有任何异常发生时 使用这个值
            Integer.parseInt(reader.readLine())
        } catch (e: NumberFormatException) {
//            return
            // 发生异常时的情况下使用 null
            null
        }
    }

总结

  • fun 关键字用来声明函数。Val关键字和var关键字分别用来声明只读变量和可变变量。
  • 字符串模板帮组你避免繁琐的字符串拼接。在变量名称前加上 前缀或者用{} 包围一个表达式,来把值注入到字符串中。
  • 值对象类在Kotlin中以简洁的方式表示。
  • 熟悉的if现在是带返回值的表达式。
  • when表达式类似于Java中的switch但功能更强大。
  • 在检查过变量具有某种类型之后不必显示地转换它的类型:编译器使用智能转换字段帮你完成。
  • for、while、和 do-while 循环与java类似,但是for循环现在更加方便,特别是当你需要迭代map的时候,又或是迭代集合需要下标的时候。
  • 简洁的语法 1..5 会创建一个区间。区间和数列允许Kotlin在for循环中使用统一的语法和同一套抽象机制,并且还可以使用in运算符和!in运算符来检查值是否属于某个区间。
  • Kotlin中的异常处理和java非常相似,除了Kotlin不要求你声明函数可以抛出异常。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,513评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,312评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,124评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,529评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,937评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,913评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,084评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,816评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,593评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,788评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,267评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,601评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,265评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,158评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,953评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,066评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,852评论 2 277

推荐阅读更多精彩内容