【Android】Kotlin教程(7)

总结:Kotin这门语言是谁设计的,语法很辣鸡,纯属是为了造门语言而造语言。

文章目录

1.函数式编程

Kotlin 是一种现代的多范式编程语言,支持面向对象编程(OOP)和函数式编程(FP)。函数式编程是一种编程范式,它强调使用纯函数、不可变数据和高阶函数来构建程序。Kotlin 提供了许多特性来支持函数式编程风格,这些特性使得代码更加简洁、易读和易于测试。

2.变换函数map

map变换函数会遍历接受者集合,让变换器函数作用于集合里的各个元素,返回结果是包含已修改元素的集合,会作为链上下一个函数的输入。

map变换函数和定义的变换器函数做完事情后,返回的是一个新集合,原始集合没有被修改。

kotlin 复制代码
fun main() {
    val animals = listOf("zebra", "giraffe", "elephant", "rat")
    val babies = animals.map { animal -> "A baby $animal is so cute" }
    println(babies)
    // [A baby zebra is so cute, A baby giraffe is so cute, A baby elephant is so cute, A baby rat is so cute]
}

可以将多个 map 操作链接在一起,以实现更复杂的转换。

kotlin 复制代码
val numbers = listOf(1, 2, 3, 4, 5)
val result = numbers.map { it * it }  // 计算平方
    .map { "Square of $it" }  // 转换为描述性字符串
println(result)  // 输出: [Square of 1, Square of 4, Square of 9, Square of 16, Square of 25]

3.flatMap

flatMap函数操作一个集合的集合,将其中多个集合中的元素合并后返回一个包含所有元素的单一集合。

kotlin 复制代码
    val result = listOf(listOf(1, 2, 3), listOf(4, 5, 6), listOf(7, 8, 9))
    val flatMap = result.flatMap { it }
    println(flatMap)
    // [1, 2, 3, 4, 5, 6, 7, 8, 9]

4.过滤函数filter

filter 函数是一个非常有用的高阶函数,用于从集合中筛选出满足特定条件的元素。它返回一个新的集合,其中只包含那些通过给定谓词(predicate)测试的元素。filter 函数是函数式编程中的一个基本工具,可以帮助你以一种简洁和声明式的方式处理数据。

kotlin 复制代码
fun main() {
    val list = listOf(1,2,3,4,5,6,7,8,9,10)
    val result = list.filter { it % 2 == 0 }
    println(result) // [2, 4, 6, 8, 10]
}
kotlin 复制代码
fun isEven(number: Int): Boolean {
    return number % 2 == 0
}

val numbers = listOf(1, 2, 3, 4, 5, 6)
val evenNumbers = numbers.filter(::isEven)
println(evenNumbers)  // 输出: [2, 4, 6]

5.合并函数zip

zip 函数用于将两个集合(如列表)中的元素配对,生成一个新的列表。每个新列表的元素是一个包含两个原集合对应位置元素的 Pair。如果两个集合的长度不同,那么结果列表的长度将与较短的那个集合相同。

kotlin 复制代码
fun main() {
    val numbers1 = listOf(1, 2, 3)
    val numbers2 = listOf(4, 5, 6)

    val zipped1 = numbers1.zip(numbers2)
    println(zipped1)  // 输出: [(1, 4), (2, 5), (3, 6)]


    val names = listOf("Alice", "Bob", "Charlie")
    val ages = listOf(30, 25, 35)

    val zipped2 = names.zip(ages)
    println(zipped2)  // 输出: [(Alice, 30), (Bob, 25), (Charlie, 35)]
}

6.合并函数fold

fold 函数是一个非常强大的高阶函数,用于对集合中的元素进行累积操作。它从一个初始值开始,依次应用一个函数到每个元素上,并将结果累积起来。fold 是一种减少(reduce)操作,常用于计算总和、乘积、最大值、最小值等。

kotlin 复制代码
fun main() {
    val numbers1 = listOf(1, 2, 3, 4, 5)
    val sum1 = numbers1.fold(0) { acc, i -> acc + i }
    println(sum1)  // 输出: 15


    val numbers2 = listOf(1, 2, 3, 4, 5)
    val product = numbers2.fold(1) { acc, i -> acc * i }
    println(product)  // 输出: 120
}

7.序列

在Kotlin中,序列(Sequence)是一个强大的工具,用于处理大数据集或进行复杂的数据转换。

定义:序列是Kotlin标准库中的一个接口,表示一个元素序列。与普通的集合不同,序列的操作是惰性的,即元素不会在创建序列时立即被处理,而是会在序列被遍历或消费时才按需生成。这种延迟执行的方式允许我们编写出更高效的数据处理逻辑。

序列的操作:

  • 中间操作:序列支持多种中间操作,如过滤(filter)、映射(map)、扁平化(flatMap)等。这些操作都是惰性的,只有在序列被消费(如通过toList()、forEach等方法)时,这些操作才会被执行。
  • 末端操作:序列的末端操作会执行原来中间操作的所有延迟计算,并返回一个结果,如集合、数字或其他对象。
kotlin 复制代码
// 扩展函数 Int.isPrime(),用于判断一个整数是否是质数
fun Int.isPrime(): Boolean {
    // 遍历从 2 到当前整数减 1 的所有整数
    (2 until this).forEach {
        // 如果当前整数能被任何一个遍历到的整数整除,则返回 false,表示不是质数
        if (this % it == 0) {
            return false
        }
    }
    // 如果没有找到任何能整除当前整数的数,则返回 true,表示是质数
    return true
}


fun main() {
    // 1-5000之内 可以找到1000个素数
    val toList = (1..5000).toList().filter { it.isPrime() }.take(1000)
    println(toList.size) // 670


    val sequence = generateSequence(2) { value -> value + 1 }.filter { it.isPrime() }.take(1000)
    println(sequence.toList().size) // 1000
}

通过使用 Sequence,你可以高效地处理大量数据或无限序列,而不需要一次性加载所有数据到内存中。这对于性能敏感的应用程序非常有用。

8.互操作性与可空性

互操作性是指不同系统、软件或编程语言之间能够无缝协作的能力。对于 Kotlin 来说,这意味着 Kotlin 代码可以轻松地与用其他语言(如 Java)编写的代码一起工作。

java 复制代码
public class Jhava {
    
    @NotNull
    public String getHello() {
        return "Hello World";
    }


    @Nullable
    public String determineFriendShipLevel(){
        return null;
    }
}
kotlin 复制代码
fun main() {
    val adversary = Jhava()
    println(adversary.hello)
    val level = adversary.determineFriendShipLevel()
    println(level?.toLowerCase())
}

9.类型映射

代码运行时,所有的映射类型都会重新映射回对应的Java类型。

kotlin 复制代码
    println(adversary.hitPoints.javaClass) // int

10.属性访问

不需要调用相关的setter方法,可以使用赋值语句来设置一个Java字段值。

11.@JvmName

@JvmName 是 Kotlin 提供的一个注解,用于在生成的 Java 字节码中指定方法或属性的具体名称。这在你需要控制 Kotlin 代码生成的 Java 方法名时非常有用,特别是在与 Java 代码互操作的情况下。

java 复制代码
    public static void main(String[] args) {
        System.out.println(Hero.makeProclamation());
    }
kotlin 复制代码
@file:JvmName("Hero")

fun main() {
    val adversary = Jhava()
    println(adversary.hello)
    val level = adversary.determineFriendShipLevel()
    println(level?.toLowerCase())

    println(adversary.hitPoints.javaClass) // int
}

fun makeProclamation() = "Greeting,beast!"

12.@JvmField

@JvmField 是 Kotlin 提供的一个注解,用于在生成的 Java 字节码中直接暴露一个属性为字段(field),而不是通过 getter 和 setter 方法。这在你需要与 Java 代码进行互操作时特别有用,因为它允许 Java 代码直接访问 Kotlin 属性,就像访问普通字段一样。

kotlin 复制代码
class Spellbook {
    @JvmField
    val spells = listOf("Magic Ms. L","Lay on hans")
}
java 复制代码
    public static void main(String[] args) {
        Spellbook spellbook = new Spellbook();
        for (String spell : spellbook.spells){
            System.out.println(spell);
        }
    }

13.@JvmOverloads

@JvmOverloads 是 Kotlin 提供的一个注解,用于生成具有默认参数值的方法的多个重载版本。在 Java 中,方法不支持默认参数,因此 Kotlin 会为每个可能的参数组合生成一个单独的方法。这使得 Kotlin 的默认参数功能可以与 Java 代码无缝集成。

kotlin 复制代码
@JvmOverloads
fun handOverFood(leftHand : String = "berrriea", rightHand : String = "beef"){
    println("$leftHand and $rightHand")
}

14.@JvmStatic

1.单例模式:

当你实现单例模式时,可以使用 @JvmStatic 来提供一个静态的方法来获取单例实例。

kotlin 复制代码
object Singleton {
    @JvmStatic
    fun getInstance(): Singleton = this
}

// Java 代码
public class Main {
    public static void main(String[] args) {
        Singleton singleton = Singleton.getInstance();
        // 使用 singleton
    }
}

2.工具类

在工具类中,你可以使用 @JvmStatic 来定义静态方法,这样 Java 代码可以直接调用这些方法而不需要创建类的实例。

kotlin 复制代码
object StringUtils {
    @JvmStatic
    fun isNullOrEmpty(str: String?): Boolean {
        return str == null || str.isEmpty()
    }

    @JvmStatic
    fun reverse(str: String): String {
        return str.reversed()
    }
}
java 复制代码
// Java 代码
public class Main {
    public static void main(String[] args) {
        boolean isEmpty = StringUtils.isNullOrEmpty("test");
        String reversed = StringUtils.reverse("hello");
        // 使用结果
    }
}

3.伴生对象

在 Kotlin 中,伴生对象(companion object)中的成员默认不是静态的。使用 @JvmStatic 可以使这些成员在 Java 中表现为静态成员。

kotlin 复制代码
class Spellbook {

    @JvmField
    val spells = listOf("Magic Ms. L","Lay on hans")


    companion object {
        @JvmStatic
        val MAX_SPELL_COUNT = 10
        fun getSpellbookGreeting() = println("I am the Great Grimoire!")
    }
}
java 复制代码
System.out.println(Spellbook.getMAX_SPELL_COUNT());
Spellbook.Companion.getSpellbookGreeting();

4.枚举类

kotlin 复制代码
enum class Color(val rgb: Int) {
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF);

    companion object {
        @JvmStatic
        fun fromInt(rgb: Int): Color? {
            for (color in values()) {
                if (color.rgb == rgb) {
                    return color
                }
            }
            return null
        }
    }
}
java 复制代码
// Java 代码
public class Main {
    public static void main(String[] args) {
        Color color = Color.fromInt(0xFF0000);
        // 使用 color
    }
}

13.@Throws

@Throws 是 Kotlin 中的一个注解,用于声明一个函数可能会抛出哪些受检异常(checked exceptions)。在 Java 中,受检异常必须在方法签名中声明,而在 Kotlin 中,由于语言设计的原因,默认情况下不需要声明受检异常。然而,在某些情况下,特别是当你的 Kotlin 代码需要与 Java 代码互操作时,使用 @Throws 注解可以明确地指出一个函数可能抛出的异常类型。

kotlin 复制代码
import java.io.File
import java.io.IOException

fun readFile(filePath: String): String {
    val file = File(filePath)
    return file.readText()
}

在这个例子中,readText() 方法可能会抛出 IOException。为了明确这一点,你可以使用 @Throws 注解:

kotlin 复制代码
import java.io.File
import java.io.IOException

@Throws(IOException::class)
fun readFile(filePath: String): String {
    val file = File(filePath)
    return file.readText()
}

如果你希望这个函数能够在 Java 代码中被调用,并且 Java 代码能够捕获 IOException,那么使用 @Throws 是必要的:

java 复制代码
public class Main {
    public static void main(String[] args) {
        try {
            String content = ExampleKt.readFile("path/to/file.txt");
            System.out.println(content);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意:

  • @Throws 注解只适用于受检异常(checked exceptions)。对于运行时异常(unchecked exceptions),如 NullPointerException 或 IllegalArgumentException,不需要使用 @Throws 注解。
  • 如果一个函数可能会抛出多种类型的受检异常,可以在 @Throws 注解中列出所有可能的异常类型
kotlin 复制代码
@Throws(IOException::class, FileNotFoundException::class)
fun readFile(filePath: String): String {
    // 实现
}
相关推荐
Kapaseker2 小时前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴2 小时前
Android17 为什么重写 MessageQueue
android
阿巴斯甜1 天前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker1 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95271 天前
Andorid Google 登录接入文档
android
黄林晴1 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab2 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿2 天前
Android MediaPlayer 笔记
android
Jony_2 天前
Android 启动优化方案
android
阿巴斯甜2 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android