栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Kotlin学习笔记(三)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Kotlin学习笔记(三)

null

在Java中 NullPointerException对于我们开发者已经司空见惯,带给我们太多不必要的麻烦,Kotlin对此做了改良,Kotlin更多地把运行时可能会出现 null问题,以编译时报错的方式,提前在编译期强迫我们重视起来,而不是等到运行时报错,防患于未然,提高了程序的健壮性。

对于 null值问题,Kotlin反其道而行之,除非另有规定,否则不允许变量为 null,这样一来,因为 null问题导致的运行时崩溃就从根源上得到了解决。

 如果我们给变量赋值为 null,编译器会报红提示我们修改代码。

 可空性

为了避免空指针异常,Kotlin的做法是不让我们给非空类型变量赋空值,但 null在Kotlin中依然存在着。

fun main() {
    // ? 在这里的意义就是表明声明的 str是可空字符串
    var str: String? = "honey"
    str = null
    println("input:$str")
}

Kotlin区分可空类型和非可空类型,所以要运行可空类型变量,而它又可能为 null值,对于这种潜在风险,编译器时刻警惕着。为了应对这种风险,Kotlin不允许我们使用可空类型变量调用函数,除非我们主动接手安全管理。

 安全调用操作符"?."

"?."会告诉编译器,如果是 null值,就跳过函数调用,而不是返回 null。

    str = null
    val newStr = str?.capitalize()
    println(newStr)

从下面的示例中,我们确实看到了当是null值是,会跳过函数调用:

fun main() {
    val str = null
    println(str?.capitalized())
}

private fun String.capitalized(): String {
    println("我被调用了")
    return if (isNotEmpty() && this[0].isLowerCase()) substring(0, 1).toUpperCase() + substring(1) else "String is null"
}
安全操作符“let”

安全调用允许我们使用可空类型值调用函数,但是我们还想做点额外的事情,比如变量为空白字符串时赋新值,或者不为 空白字符串时调用其他函数,此时 let就该出场表演了。

fun main() {
    var str: String? = "honey"
    //var str: String? = null  //为 null时安全调用let函数会直接跳过
    //str = ""

    str = str?.let {
        if (it.isNotBlank()) {
            it.capitalize()
        } else {
            "str is blank"
        }
    }

    println("str = $str")
}
安全操作调用符"!!."

"!!."是非空断言操作符,也叫感叹号操作符,当调用者为 null时,会抛出 KotlinNullPointerException。

fun main() {
    var str: String? = ""
    str = null
    str!!.capitalize()
}

上面的代码会跑出空指针异常: 

安全调用操作符 VS if

我们也可以跟Java中一样,使用 if判断 null值情况,但相比之下,安全调用操作符使用更灵活,代码更简洁,我们可以使用安全操作符进行多个函数的链式调用。

fun main() {
    var str: String? = "luffy"
    //str = null

    //使用 if判断
    if(str  != null) str = str.capitalize() else str = "str is null"
    println("str = $str")
    //使用安全调用操作符链式调用
    println(str?.capitalize().plus(" is great."))
}
空合并操作符

"?:"操作符的作用是,如果它左边的表达式求值结果为 null ,就使用右边的结果值,否则用左边的结果值。

fun main() {
    var str: String? = "luffy"
    str = null
    println(str ?: "honey")
}

空合并操作符也可以和 let函数结合使用,代替if/else:

fun main() {
    var str: String? = "luffy"
    str = null

    str = str?.let { it.capitalize() } ?: "Honey"
    println(str)
}
异常
import kotlin.IllegalArgumentException

fun main() {
    var str: String? = null
    try {
        checkOperation(str)
        str!!.capitalize()
    } catch (e: KotlinNullPointerException) {
        println(e.cause?.message)
    }
}

fun checkOperation(str: String?) {
    str ?: throw UnskilledException()
}


class UnskilledException() : IllegalArgumentException("Improper operation")

先决条件函数

Kotlin标准库提供了一些便利函数,使用这些内置函数,可以抛出带自定义信息的异常,这些便利函数 叫做先决条件函数,我们可以用它定义先决条件,条件必须满足,目标代码才能执行。

fun main() {
    var num: Int? = null
    try {
        checkNotNull(num){"Improper operation"}
        num!!.plus(1)
    } catch (e: KotlinNullPointerException) {
        println(e.cause?.message)
    }
}
字符串操作 substring

字符串截取,substring函数支持IntRang类型(表示一个整数范围的类型)的参数,until创建的范围不包括上限值。

const val WORDS = "Luffy's friend"
fun main() {
    val index = WORDS.indexOf(''')
    var str1 = WORDS.substring(0, index)
    //Kotlin中,substring函数支持IntRang类型
    var str2 = WORDS.substring(0 until index)

    println("str1 = $str1")
    println("str2 = $str2")
}
 split

split函数返回的是List集合数据,List集合有支持解构语法特性,它允许我们在一个表达式里给多个变量赋值,解构常用来简化变量的赋值。
 

const val NAMES = "Luffy,Honey,Kitty"
fun main() {
    val names: List = NAMES.split(',')
    println(names[0])
    //解构语法特性
    val (origin, dest, proxy) = NAMES.split(',')
    println("$origin,$dest,$proxy")
}
replace
fun main() {
    //加密替换一个字符串
    val str1 = "The people's Republic of China."
    //第一个参数是正则表达式,用来指定要替换哪些字符
    //第二个参数是匿名函数,用来决定当匹配到正则中的字符时,该怎么处理
    val str2 = str1.replace(Regex("[aoeiu]")) {
        when (it.value) {
            "a" -> "8"
            "o" -> "6"
            "e" -> "5"
            "i" -> "2"
            "u" -> "0"
            else -> it.value
        }
    }
    println("str1 = $str1")
    println("str2 = $str2")
}
字符串比较

在Kotlin中,用"=="检查两个字符串中的字符是否匹配,用"==="检查两个变量是否指向内存堆上同一对象,而在java中,"=="用作引用的比较
,做内容比较时用equals方法。 

fun main() {
    val name1 = "Honey"
    val name2 = "Honey"
    println("name1 == name2 : ${name1 == name2}")
    println("name1 === name2 : ${name1 === name2}")

    val name3 = "Luffy"
    val name4 = "luffy".capitalize()
    println("name3 == name4 : ${name3 == name4}")
    println("name3 === name4 : ${name3 === name4}")
}

执行结果:

 上面示例代码执行结果有没有疑问,这个就涉及到Java的内存模型了,字符串是放在常量池中的,因为字符串也是常量,所以示例代码中的name1和name2都指向了同一字符串对象“Honey”,所以两个输出都是true;而“Luffy”和“luffy”是两个不同的字符串常量,虽然"luffy".capitalize()的执行结果也是“Luffy”,但是这期间生成了新的字符串对象:

 看下 capitalize()的源码就明白了,这里进行了字符串的拼接,所以生成了新的字符串对象,所以name3和name4虽然内容一样,但是指向了不同的对象。

foreach遍历字符
fun main() {
    val saying = "For you, a thousand times over."
    println("* * *")
    saying.forEach { println("* $it *") }
    println("* * *")
}
数字类型 

和java一样,Kotlin的所有数字类型都是有符号的,即可以表示正数,也可以表示负数。

 安全转换函数

Kotlin提供了 toDoubleOrNull和 toIntOrNull这样的安全转换函数,如果数值不能正确转换,与其触发异常不如干脆返回null值。

import kotlin.math.roundToInt


fun main() {
    //val result = "66.88".toInt()//抛出 java.lang.NumberFormatException
    val result1 = "66.88".toIntOrNull()
    println("result1:$result1")

    val result2 = "66.88".toDouble()
    println("result2:$result2")

    //精度损失
    val result4 = 98.66.toInt()
    println("result4:$result4")

    //四舍五入
    val result5 = 98.66.roundToInt()
    println("result5:$result5")
}
Double类型格式化

格式化字符串是一串特殊的字符,它绝对如何格式化数据。

fun main() {
    val result = "%.2f".format(5.20522)
    println("result:$result")
}

注意到上述代码输出结果是:5.21,说明格式化之后的Double数据会四舍五入 。

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/341156.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号