Kotlin 的常用语法习惯

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(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("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()
  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()
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 fromJson(JsonElement json, Class classOfT) throws JsonSyntaxException {
//     ……

inline fun  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) {
    var value = t
}

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

43、

42、

42、

42、

42、

42、

你可能感兴趣的:(Kotlin 的常用语法习惯)