Kotlin快速入门(一)——基础类型

最近了解一下Kotlin,毕竟Google力挺,网上对于Kotlin褒贬不一,有吹捧的,也有贬低的,在拿不定主意的时,不如自己动手试试,看看Kotlin会带来哪些新的体验,本文主要针对Java的开发者,着重总结两者区别。

Kotlin的优势

好好了解一下,不然被别人问为什么使用Kotlin,会被问的哑口无言。

  • 全面支持Lambda表达式
  • 数据类(Data classes)
  • 函数字面量和内联函数(Function literals & inline functions)
  • 函数扩展(Extension function)
  • 空安全(Null safety)
  • 智能转换(Smart casts)
  • 字符串模版(String templates)
  • 主构造函数(Primary constructors)
  • 类委托(Class delegation)
  • 类型判断(Type inference)
  • 单例(Singletons)
  • 声明点变量(Declaration-site variance)
  • 区间表达式 (Range expressions)

Kotlin的基础类型

1. 分隔符

Kotlin每行语句可以不以分号结束。

fun main(args: Array) {
    println("Hello world")
}

2. 注释

多行注释可以嵌套使用;单行注释和文档注释与Java一致。

fun main(args: Array) {

    /*println("Hello world")

    /*println("first")*/

    println("second")*/

    println("third")
}

的Kotlin代码高亮有点问题,放到编译器中的效果

Kotlin快速入门(一)——基础类型_第1张图片
注释嵌套

3. 变量

  • 声明变量varvalval是只读数据类型,只能赋值一次
  • 类型推断,可以不显示声明变量类型
fun main(args: Array) {

    var i: Int // 显示声明变量i的类型,Java中的int a;
    var name: String = "Kotlin" // 显示声明变量并赋值,Java中的String name = "Kotlin";
    var my_name = "JamFF" // 上面的简写,编译器推断Sting类型

    name = "Java" // 重新赋值,Java中的name = "Java";
    my_name = 18 // my_name是String类型,不能赋值为Int

    val a = false // 不可以重新赋值,Java中的final boolean b = false;

    val b: Int // 不同于Java,可以先声明,不赋值
    b = 1 // 只要在使用之前赋值即可,只能赋值一次
}

4. 整型

  • Byte,Java的byteByte,8bit。
  • Short,Java的shortShort,16bit。
  • Int,Java的intInteger,32bit。
  • Long,Java的longLong,64bit。
  1. 整型会默认类型推断为Int,如果超过Int取值范围,会推断为Long

    fun main(args: Array) {
    
        var a: Int = 18
        a = 100_000_000_000 // 不能赋值,超过Int范围
    
        var b = 1// 整型默认推断为Int,Byte,Short需要显示声明
        var c = 100_000_000_000 // 如果超过Int范围,会自动推断类型为Long
    }
    
  2. Kotlin是空安全的语言,所以上述四种数据类型均不能接受null值,如果要存储null值需要使用Byte?Short?Int?Long?类型

    fun main(args: Array) {
    
        val a: Int = null // 报错
        val b: Int? = null // 正确
    }
    
  3. Kotlin将不带?类型映射为Java的基本类型,将带?类型映射为Java的引用类型。

    fun main(args: Array) {
    
        val a: Int = 666
        val b: Int = 666
        // ===比较的是地址,==比较的是值
        println(a === b) // true,基本类型比较
    
        val c: Int? = 666
        val d: Int? = 666
        println(c === d) // false,引用类型比较
    }
    
  4. Kotlin支持二进制、十进制和十六进制,不支持八进制

    fun main(args: Array) {
    
        val a = 0b10101
        val b = 0xab
        // a的值为21,b的值为171,a+b的值为192
        println("a的值为$a,b的值为$b,a+b的值为${a + b}")
    }
    

5. 浮点型

与Java一致。

  • Float:32bit,需要在尾部添加f
  • Double:64bit,类型推断的默认值。
fun main(args: Array) {

    var a = 3.14 // 默认Double
    a = 2.0f // 报错,不能赋值给Float
    var b = 1.5f // Float
    b = 3.14 // 报错,不能赋值给Double
}

6. 字符型

与Java不同,Kotlin的Char型变量不能当成整数值使用。

fun main(args: Array) {

    var a: Char = 'a' // 字符a
    a = '\n' // 换行符
    a = '\u8888' // 汉字'驾'
    a = 1 // 报错
}

7. 数值型之间的类型转换

  1. Kotlin不支持取值范围小的数据类型隐式转换为取值范围大的类型,需要显式调用。

    • toByte()
    • toShort()
    • toInt()
    • toLong()
    • toFloat()
    • toDouble()
    • toChar()
    fun main(args: Array) {
    
        var a: Byte = 1
        var b: Short = 2
    
        b = a // 报错,Java允许
        a = b.toByte() // 可以,注意溢出
        b = a.toShort() // 可以
    
        var c = 1.0f
        var d = 2.2
    
        d = c // 报错,Java允许
        c = d.toFloat() // 可以,注意溢出
        d = c.toDouble() // 可以
    }
    
  2. 与Java一致,虽然Kotlin中缺乏隐式转换,但在表达式中可以自动转换。通过javaclass查看数据类型。

    fun main(args: Array) {
    
        val a: Byte = 1
        val b: Short = 2
        val c = 1.0
    
        val total = a + b
        // javaClass属性来自Any类型,是Kotlin所有类型但根父类
        println(total.javaClass) // int
    
        val total2 = a.toLong() + b.toByte()
        println(total2.javaClass) // long
    
        val total3 = a + b + c
        println(total3.javaClass) // double
    }
    
  3. 与Java一致,将浮点型强转为整数型,小数部分会被截断;将整数型强转为浮点型没有问题。

  4. Kotlin中Char型虽然不能当成整数进行算术运算,但是可以Char型值加、减一个整数值,也可以两个Char相减,但不能相加。

    fun main(args: Array) {
    
        val a = 'a'
        val b = 'b'
    
        println(a + 2) // c
        println(b + 2) // d
        println(b - a) // 1
        println(a + b) // 报错
    }
    

8. Boolean类型

与Java一致。

9. 空安全

  1. 非空类型和可空类型

    fun main(args: Array) {
    
        val str = "abc"
    
        val num: Int = str.toIntOrNull() // 报错
        val num2: Int? = str.toIntOrNull() // 通过
        val num3 = str.toIntOrNull() // 通过,类型推断为Int?类型
    }
    

    那么Kotlin是如何保证空安全呢

    fun main(args: Array) {
    
        val a: String = "abc"
        val b: String? = "abc"
    
        println(a.length) // a非null,不可能出现空指针
        println(b.length) // b可以为null,但是如果不判断非空,编译报错
    }
    
  2. 先判断后使用
    可空类型的变量不允许直接调用方法或属性,必须判断是否为null。

    fun main(args: Array) {
        
        val a: String? = "abc"
        // 可以使用安全调用和Elvis简化
        val len = if (a != null) a.length else -1
        
        if (a != null && a.isNotEmpty()) {
            println(a.length)
        } else {
            println("空字符串")
        }
    }
    
  3. 安全调用

    • 可以使用?.进行安全调用,避免出现空指针。
    fun main(args: Array) {
    
        var a: String? = "abc"
    
        println(a?.length) // 打印4
    
        a = null
    
        println(a?.length) // 打印null
    }
    
    • 与Spring EL类似,Kotlin的安全调用也支持链式调用。
    fun main(args: Array) {
    
        // 安全的获取user的dog的name,如果user或者user.dog为null,整个表达式返回null
        user?.dog?.name
    }
    
    • 安全调用还可与let全局函数结合使用,例如下面只打印非空元素。
    fun main(args: Array) {
    
        val arr: Array = arrayOf("abc", "JamFF", "Tom", null, "Tony")
        for (s in arr) {
            s?.let { println(it) }
        }
    }
    
  4. Elvis运算
    ?:运算符就是Elvis,如果?:左边不为null返回左边表达式的值,否则返回?:右边表达式的值。

    fun main(args: Array) {
        
        val a: String? = "abc"
        
        val len = if (a != null) a.length else -1
        
        val len2 = a?.length ?: -1 // 上面语句的简写
        
        if (a != null && a.isNotEmpty()) {
            println(a.length)
        } else {
            println("空字符串")
        }
    }
    

    Kotlin的returnthrow都属于表达式,可以灵活使用。

  5. 强制调用
    !!.不管变量是否为null强制调用,可以编译通过,运行可能引发空指针,谨慎使用。

    fun main(args: Array) {
    
        var a: String? = "abc"
        println(a!!.length) // 输出3
    
        a = null
        println(a!!.length) // 空指针
    
        val arr: Array = arrayOf("abc", "JamFF", "Tom", null, "Tony")
        for (s in arr) {
            s!!.let { println(it) } // 空指针
        }
    }
    

10. 字符串

  1. 遍历字符串中每一个字符

    fun main(args: Array) {
    
        val str = "JamFF"
    
        for (c in str){
            println(c)
        }
    }
    
  2. 字符串分类

    • 转义字符串,可以包含转义字符,类似Java中的字符串。
    • 原始字符串,可以包含换行符和任意文本,需要三个引号包裹。
    fun main(args: Array) {
    
        val str = "abc" // 转移字符串
    
        // 原始字符串
        val txt = """
            但行好事,
            勿问前程。
        """
    
        println(txt)
    
        // trimIndent去除字符串前面的缩进
        val txt2 = """
            但行好事,
            勿问前程。
        """.trimIndent()
        println(txt2)
    
        val txt3 = """
            |但行好事,
            |勿问前程。
        """
        println(txt3)
    
        // trimMargin去除边界符,Kotlin默认是"|",
        val txt4 = """
            |但行好事,
            |勿问前程。
        """.trimMargin()
        println(txt4)
    
        // 去除自定义边界符
        val txt5 = """
            ^但行好事,
            ^勿问前程。
        """.trimMargin("^")
        println(txt5)
    }
    

    输出结果

    Kotlin快速入门(一)——基础类型_第2张图片
    输出结果
  3. 字符串模版
    Kotlin允许在字符串(转移字符串、原始字符串)中嵌入变量或表达式,只要放入${}中即可。

    fun main(args: Array) {
    
        val a = 2018
        var s = "今年是${a}年"
        println(s)
    
        s = "随机数:${java.util.Random().nextInt(10)}"
        println(s)
    }
    
  4. Kotlin字符串的方法
    Kotlin的String和Java的不是同一个类,有更多便捷的API。

11. 类型别名

  • 类似于C语言的typedef的功能,Kotlin可以使用typealias定义类型别名。
    fun main(args: Array) {
    
        // Kotlin: Nested and local type aliases are not supported
        typealias StringSet = Set // 报错,别名不能写在方法中
        val set: StringSet
        var table: FileTable
    }
    // 正确定义位置
    typealias StringSet = Set
    typealias FileTable = MutableMap>
    
  • 也可以给内部类定义别名。
    class A {
        inner class Inner
    }
    
    class B {
        inner class Inner
    }
    
    typealias AInner = A.Inner
    typealias BInner = B.Inner
    
    fun main(args: Array) {
        val a: AInner = A().Inner()
        val b = B().Inner()
    
        println(a.javaClass) // 输出class A$Inner
        println(b.javaClass) // 输出class B$Inner
    }
    
  • Kotlin的Lambda表达式的类型直接就是函数类型,而Java的是函数是接口,因此Kotlin也允许为Lambda表达式的类型指定别名。
    // 为(T) -> Boolean类型指定别名Predicate
    typealias Predicate = (T) -> Boolean
    
    fun main(args: Array) {
    
        // 使用Predicate定义变量,该变量的值是一个Lambda表达式
        val p: Predicate = { it.length > 4 }
        // 为filter()方法传入p参数,只保留长度大于4的字符串
        println(arrayOf("Java", "PHP", "Python", "Go", "Kotlin").filter(p))
        // 输出[Python, Kotlin]
    }
    

重点

  • 每行语句建议不以分号结束,换行即可。
  • 可变变量var和不可变变量val
  • 基本数据类型
  • 空安全
  • 字符串和字符串模版
  • 类型别名

你可能感兴趣的:(Kotlin快速入门(一)——基础类型)