美文网首页
Kotlin 的常用语法习惯

Kotlin 的常用语法习惯

作者: 因为我的心 | 来源:发表于2021-08-07 23:10 被阅读0次

    1、创建 DTOs(POJOs/POCOs)

    data class Customer(val name: String, val email: String)
    

    会为 Customer 类提供以下功能:

    • 所有属性的 getters (对于 var 定义的还有 setters)
    • equals()
    • hashCode()
    • toString()
    • copy()
    • 所有属性的 component1()component2()……等等(参见数据类

    2、 函数的默认参数

    //调用方可以不传任何参数,采用默认值
    foo()
    //方法
    fun foo(a: Int = 0, b: String = "") { …… }
    

    3、过滤 list

    //数组
    val list = arrayListOf<Int>(1,2,3,4,5,6,7,8)
    //方法 1:
    //val positives = list.filter { x -> x > 5 }
    //方法 2:
    val positives = list.filter { it > 5 }
    //结果:
    positives.forEach {
        Log.d("LUO", "it=====$it")
    }
    

    4、检测元素是否存在于集合中(也支持字符串)

     //集合
    val list = arrayListOf<String>("a","b","c","d")
    //1、在集合中判断
    if ("a" in list) {
         Log.d("LUO", "1=====")
    }
    //2、不在集合中判断
    if ("m" !in list) {
        Log.d("LUO", "2=====")
    }
    

    5、字符串内插

    println("Name $name")
    

    6、类型判断

    when (x) {
        is Foo //-> ……
        is Bar //-> ……
        else   //-> ……
    }
    

    7、遍历 map/pair型list

     //map 集合
    var map = HashMap<String,Int>()
      map.put("小明",22);
      map.put("小刚",25);
      map.put("小红",28);
    
    //遍历,
    for ((k, v) in map) {
      Log.d("LUO", "$k -> $v")
    }
    

    注意:k、v 可以改成任意名字。

    8、使用区间

    for (i in 1..100) { …… }  // 闭区间:包含 100
    for (i in 1 until 100) { …… } // 半开区间:不包含 100
    for (x in 2..10 step 2) { …… }
    for (x in 10 downTo 1) { …… }
    if (x in 1..10) { …… }
    

    9、只读 list

    val list = listOf("a", "b", "c")
    

    10、只读 map

    val map = mapOf("a" to 1, "b" to 2, "c" to 3)
    

    11、访问 map

    println(map["key"])
    map["key"] = value
    
     //map 集合
    var map = HashMap<String,Int>()
    map.put("小明",22);
    map.put("小刚",25);
    map.put("小红",28);
    //打印
    val aa = map["小红"]
    Log.d("LUO", "==== $aa")
    

    12、延迟属性

    val p: String by lazy {
        // 计算该字符串
    }
    

    13、扩展函数

     fun String.spaceToCamelCase() {
                Log.d("LUO", "==执行了扩展函数==")
            }
    "Convert this to camelcase".spaceToCamelCase()
    

    14、创建单例

    object Resource {
        val name = "Name"
    }
    

    15、If not null 缩写

    val files = File("Test").listFiles()
    println(files?.size)
    

    16、If not null and else 缩写

    val files = File("Test").listFiles()
    println(files?.size ?: "empty")
    

    17、if null 执行一个语句

    val values = ……
    val email = values["email"] ?: throw IllegalStateException("Email is missing!")
    

    18、在可能会空的集合中取第一元素

    val emails = …… // 可能会是空集合
    val mainEmail = emails.firstOrNull() ?: ""
    

    19、if not null 执行代码

    val value = ……
    value?.let {
        …… // 代码会执行到此处, 假如data不为null
    }
    

    20、映射可空值(如果非空的话)

    val value = ……
    val mapped = value?.let { transformValue(it) } ?: defaultValue 
    // 如果该值或其转换结果为空,那么返回 defaultValue。
    

    21、返回 when 表达式

    fun transform(color: String): Int {
        return when (color) {
            "Red" -> 0
            "Green" -> 1
            "Blue" -> 2
            else -> throw IllegalArgumentException("Invalid color param value")
        }
    }
    

    22、“try/catch”表达式

    fun test() {
        val result = try {
            count()
        } catch (e: ArithmeticException) {
            throw IllegalStateException(e)
        }
        // 使用 result
    }
    

    23、“if”表达式

    fun foo(param: Int) {
        val result = if (param == 1) {
            "one"
        } else if (param == 2) {
            "two"
        } else {
            "three"
        }
    }
    

    24、返回类型为 Unit 的方法的 Builder 风格用法

    fun arrayOfMinusOnes(size: Int): IntArray {
        return IntArray(size).apply { fill(-1) }
    }
    

    25、单表达式函数

    fun theAnswer() = 42
    //等价于
    fun theAnswer(): Int {
        return 42
    }
    //单表达式函数与其它惯用法一起使用能简化代码,例如和 when 表达式一起使用:
    fun transform(color: String): Int = when (color) {
        "Red" -> 0
        "Green" -> 1
        "Blue" -> 2
        else -> throw IllegalArgumentException("Invalid color param value")
    }
    

    26、对一个对象实例调用多个方法 (with)

    class Turtle {
        fun penDown()
        fun penUp()
        fun turn(degrees: Double)
        fun forward(pixels: Double)
    }
    
    val myTurtle = Turtle()
    with(myTurtle) { // 画一个 100 像素的正方形
        penDown()
        for (i in 1..4) {
            forward(100.0)
            turn(90.0)
        }
        penUp()
    }
    

    27、配置对象的属性(apply)

    val myRectangle = Rectangle().apply {
        length = 4
        breadth = 5
        color = 0xFAFAFA
    }
    

    这对于配置未出现在对象构造函数中的属性非常有用。

    28、对于需要泛型信息的泛型函数的适宜形式

    //  public final class Gson {
    //     ……
    //     public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
    //     ……
    
    inline fun <reified T: Any> Gson.fromJson(json: JsonElement): T = this.fromJson(json, T::class.java)
    

    29、 使用可空布尔

    val b: Boolean? = ……
    if (b == true) {
        ……
    } else {
        // `b` 是 false 或者 null
    }
    

    30、交换两个变量

    var a = 1
    var b = 2
    a = b.also { b = a }
    

    31、TODO():将代码标记为不完整

    Kotlin 的标准库有一个 TODO() 函数,该函数总是抛出一个 NotImplementedError。 其返回类型为 Nothing,因此无论预期类型是什么都可以使用它。 还有一个接受原因参数的重载:

    fun calcTaxes(): BigDecimal = TODO("Waiting for feedback from accounting")
    

    IntelliJ IDEA 的 kotlin 插件理解 TODO() 的语言,并且会自动在 TODO 工具窗口中添加代码指示。

    32、每个数字类型支持如下的转换:

    - toByte(): Byte
    - toShort(): Short
    - toInt(): Int
    - toLong(): Long
    - toFloat(): Float
    - toDouble(): Double
    - toChar(): Char
    

    33、整数除法

    请注意,整数间的除法总是返回整数。会丢弃任何小数部分。例如:

    val x = 5 / 2
    //println(x == 2.5) // ERROR: Operator '==' cannot be applied to 'Int' and 'Double'
    println(x == 2)
    

    如需返回浮点类型,请将其中的一个参数显式转换为浮点类型。

    fun main() {
        val x = 5 / 2.toDouble()
        println(x == 2.5)
    }
    

    34、字符串

    字符串用 String 类型表示。字符串是不可变的。 字符串的元素——字符可以使用索引运算符访问: s[i]。 可以用 for 循环迭代字符串:

    for (c in str) {
        println(c)
    }
    

    可以用 + 操作符连接字符串。这也适用于连接字符串与其他类型的值, 只要表达式中的第一个元素是字符串:

    val s = "abc" + 1
    println(s + "def")
    

    请注意,在大多数情况下,优先使用字符串模板或原始字符串而不是字符串连接

    35、 字符串模板

    字符串字面值可以包含模板表达式 ,即一些小段代码,会求值并把结果合并到字符串中。 模板表达式以美元符($)开头,由一个简单的名字构成:

    val i = 10
    println("i = $i") // 输出“i = 10”
    

    或者用花括号括起来的任意表达式:

    val s = "abc"
    println("$s.length is ${s.length}") // 输出“abc.length is 3”
    

    36、返回和跳转

    Kotlin 有三种结构化跳转表达式:

    • return。默认从最直接包围它的函数或者匿名函数返回。
    • break。终止最直接包围它的循环。
    • continue。继续下一次最直接包围它的循环。

    所有这些表达式都可以用作更大表达式的一部分:

    val s = person.name ?: return
    

    37、继承

    在 Kotlin 中所有类都有一个共同的超类 Any,这对于没有超类型声明的类是默认超类:

    class Example // 从 Any 隐式继承
    

    Any 有三个方法:equals()、 hashCode() 与 toString()。因此,为所有 Kotlin 类都定义了这些方法。

    默认情况下,Kotlin 类是最终(final)的:它们不能被继承。 要使一个类可继承,请用 open 关键字标记它。

    open class Base // 该类开放继承
    
    //如需声明一个显式的超类型,请在类头中把超类型放到冒号之后:
    open class Base(p: Int)
    class Derived(p: Int) : Base(p)
    

    38、接口

    Kotlin 的接口可以既包含抽象方法的声明也包含实现。与抽象类不同的是,接口无法保存状态。它可以有属性但必须声明为抽象或提供访问器实现。

    使用关键字 interface 来定义接口

    interface MyInterface {
        fun bar()
        fun foo() {
          // 可选的方法体
        }
    }
    //一个类或者对象可以实现一个或多个接口。
    class Child : MyInterface {
        override fun bar() {
            // 方法体
        }
    }
    

    39、接口继承

    一个接口可以从其他接口派生,从而既提供基类型成员的实现也声明新的函数与属性。很自然地,实现这样接口的类只需定义所缺少的实现:

    interface Named {
        val name: String
    }
    
    interface Person : Named {
        val firstName: String
        val lastName: String
        
        override val name: String get() = "$firstName $lastName"
    }
    
    data class Employee(
        // 不必实现“name”
        override val firstName: String,
        override val lastName: String,
        val position: Position
    ) : Person
    

    注意:
    1、我在 android Moudle 中定义的 Kotlin 接口,在 APP 工程中可以看到,单使用不到?
    2、让APP 工程支持 kotlin 编程,在 kt 接口中继承Moudle中的接口,用 kt 接口,就可以实现接口回调;

    40、函数式(SAM)接口

    只有一个抽象方法的接口称为函数式接口或 SAM(单一抽象方法)接口。函数式接口可以有多个非抽象成员,但只能有一个抽象成员。
    可以用 fun 修饰符在 Kotlin 中声明一个函数式接口。

    fun interface KRunnable {
       fun invoke()
    }
    

    SAM 转换

    1、对于函数式接口,可以通过 lambda 表达式实现 SAM 转换,从而使代码更简洁、更有可读性。
    2、使用 lambda 表达式可以替代手动创建实现函数式接口的类。 通过 SAM 转换, Kotlin 可以将其签名与接口的单个抽象方法的签名匹配的任何 lambda 表达式转换为实现该接口的类的实例。

    //例如,有这样一个 Kotlin 函数式接口:
    fun interface IntPredicate {
       fun accept(i: Int): Boolean
    }
    //如果不使用 SAM 转换,那么你需要像这样编写代码:
    // 创建一个类的实例
    val isEven = object : IntPredicate {
       override fun accept(i: Int): Boolean {
           return i % 2 == 0
       }
    }
    通过利用 Kotlin 的 SAM 转换,可以改为以下等效代码:
    // 通过 lambda 表达式创建一个实例
    val isEven = IntPredicate { it % 2 == 0 }
    

    41、类和接口

    对于类内部声明的成员:

    • private 意味着只在这个类内部(包含其所有成员)可见;
    • protected—— 和 private一样 + 在子类中可见。
    • internal —— 能见到类声明的 本模块内 的任何客户端都可见其 internal 成员;
    • public —— 能见到类声明的任何客户端都可见其 public 成员。

    请注意在 Kotlin 中,外部类不能访问内部类的 private 成员。
    如果你覆盖一个 protected 成员并且没有显式指定其可见性,该成员还会是 protected 可见性。

    42、泛型

    与 Java 类似,Kotlin 中的类也可以有类型参数:

    class Box<T>(t: T) {
        var value = t
    }
    
    //一般来说,要创建这样类的实例,我们需要提供类型参数:
    val box: Box<Int> = Box<Int>(1)
    //但是如果类型参数可以推断出来,例如从构造函数的参数或者从其他途径,允许省略类型参数:
    val box = Box(1) // 1 具有类型 Int,所以编译器知道我们说的是 Box<Int>。
    

    43、

    42、

    42、

    42、

    42、

    42、

    相关文章

      网友评论

          本文标题:Kotlin 的常用语法习惯

          本文链接:https://www.haomeiwen.com/subject/vtigvltx.html