Kotlin基础(四):函数

前言

本文主要讲解高阶函数、内联函数、几个有用的高阶函数、集合变换与序列、SAM转换、案例:统计字符个数、案例:HTML DSL、实践:体验 Gradle Kotlin DSL


Kotlin文章列表

Kotlin文章列表: 点击此处跳转查看


目录

在这里插入图片描述


(一)高阶函数

(1)高阶函数的定义

参数类型包含函数类型或返回值类型为函数类型的函数为高阶函数

fun needsFunction(block: () -> Unit) {
    block()
}

fun returnsFunction(): () -> Long {
    return { System.currentTimeMillis() }
}

(2)高阶函数的调用

public inline fun IntArray.forEach(action: (Int) -> Unit): Unit {
    for (element in this) action(element)
}

调用:

val intArray = IntArray(5){ it + 1 }

intArray.forEach {
    println(it)
}

intArray.forEach(::println)

intArray.forEach {
    println("Hello $it")
}
fun main() {
    cost {
        val fibonacciNext = fibonacci()
        for (i in 0..10) {
            println(fibonacciNext())
        }
    }
}


fun cost(block: () -> Unit) {
    val start = System.currentTimeMillis()
    block()
    println("${System.currentTimeMillis() - start}ms")
}


fun fibonacci(): () -> Long {
    var first = 0L
    var second = 1L
    return {
        val next = first + second
        val current = first
        first = second
        second = next
        current
    }
}

结果:

0
1
1
2
3
5
8
13
21
34
55
7ms

(二)内联函数

(1)内联函数的定义

被inline标记的函数就是内联函数,其原理就是:在编译时期,把调用这个函数的地方用这个函数的方法体进行替换

val ints = intArrayOf(1, 2, 3, 4)
ints.forEach { // forEach是内联函数,该处的代码应该替换成forEach内部的方法体,即for循环
    println("Hello $it")
}

// forEach是内联函数
public inline fun IntArray.forEach(crossinline action: (Int) -> Unit): Unit {
    for (element in this) action(element)
}


// 上面代码可以写成下面这样
val ints = intArrayOf(1, 2, 3, 4)
for (element in ints) {
    println("Hello $element")
}

(2)内联函数的return

val ints = intArrayOf(1, 2, 3, 4)
ints.forEach {
    if (it == 3) return@forEach // 仅仅是it == 3没有执行,跳出这一次内联函数的调用
    println("Hello $it")
}

// 等同于上面代码
for (element in ints) {
    if (element == 3) continue
    println("Hello $element")
}

结果:

Hello 1
Hello 2
Hello 4


Hello 1
Hello 2
Hello 4

(3)内联函数的non-local return

inline fun nonLocalReturn(block: () -> Unit) {
    block()
}

nonLocalReturn {
    return // 从外部函数返回
}


例如:
fun main() {
   nonLocalReturn {
     return // 从main函数中返回
   }
}
inline fun Runnable(block: () -> Unit): Runnable {
    return object : Runnable {
        override fun run() {
            block()
        }
    }
}
// 有可能存在不合法的non- -local return  因为block的调用处与定义处不在同一个调用上下文

改进:加上noinline,禁止函数参数被内联

inline fun Runnable(noinline block: () -> Unit): Runnable {
    return object : Runnable {
        override fun run() {
            block()
        }
    }
}

(4)内联属性

var pocket: Double = 0.0
var money: Double
    inline get() = pocket
    inline set(value) {
        pocket = value
    }

编译之后:
在这里插入图片描述

(5)内联函数的限制

public/protected的内联方法只能访问对应类的public成员
内联函数的内联函数参数不能被存储(赋值给变量)
内联函数的内联函数参数只能传递给其他内联函数参数


(三)几个有用的高阶函数

(1)几个有用的高阶函数的简介

在这里插入图片描述
在这里插入图片描述

(2)几个有用的高阶函数的使用

import java.io.File

class Person(var name: String, var age: Int)

fun main() {
    val person = Person("benny", 20)

    person.let(::println)
    person.run(::println)

    val person2 = person.also {
        it.name = "hhh"
    }

    val person3 = person.apply {
        name = "xxx"
    }

    File("build.gradle").inputStream().reader().buffered()
        .use {
            println(it.readLines())
        }
}

(四)集合变换与序列

(1)for i…

java:

for (int i = 0; i < 10; i++) {
    System.out.println(i);
}

kotlin:

for (i in 0..10) {
    println(i)
}

(2)forEach

java:

list.forEach((e) -> {
    System.out.println(e);
});


list.forEach((e) -> {
    if (e == 2) return;
    System.out.println(e);
});

kotlin:

list.forEach {
    println(it);
}

list.forEach {
    if (it == 2) {
        return@forEach
    }
    println(it)
}

注意forEach函数不能continue或者break

(3)集合的映射操作举例

在这里插入图片描述

(4)filter操作

在这里插入图片描述
保留满足条件的元素,构成一个新的集合
java:

list.stream()
        .filter(e -> e % 2 == 0)
        .forEach(System.out::println);

kotlin:

list.filter { it % 2 == 0 }

list.asSequence()
    .filter { it % 2 == 0 }

(5)map操作

在这里插入图片描述
经过一定变换,转化为另外一个集合

java:

list.stream()
        .map(e -> e * 2 + 1);

kotlin:

list.asSequence()
    .map { it * 2 + 1 }

综合小应用:
java:

public class JavaStreams {
    public static void main(String... args) {
        
        var list = new ArrayList<Integer>();
        list.addAll(Arrays.asList(1, 2, 3, 4));

        list.stream()
                .filter(e -> {
                    System.out.println("filter: " + e); // 1,3不符合要求,直接输出,2,4符合要求进行往下走
                    return e % 2 == 0;
                })
                .map(e -> {
                    System.out.println("map: " + e);
                    return e * 2 + 1;
                })
                .forEach(e -> {
                    System.out.println("forEach: " + e);
                });
    }
}

结果:

filter: 1
filter: 2
map: 2
forEach: 5
filter: 3
filter: 4
map: 4
forEach: 9

kotlin:

fun main() {
    val list = listOf(1, 2, 3, 4)

    list.asSequence()
        .filter {
            println("filter: $it")
            it % 2 == 0
        }.map {
            println("map: $it")
            it * 2 + 1
        }.forEach {
            println("forEach: $it")
        }
}

结果:

filter: 1
filter: 2
map: 2
forEach: 5
filter: 3
filter: 4
map: 4
forEach: 9
fun main() {
    val list = listOf(1, 2, 3, 4)

    // region sequence
    list.filter {
            println("filter: $it")
            it % 2 == 0
        }.map {
            println("map: $it")
            it * 2 + 1
        }.forEach {
            println("forEach: $it")
        }
}

结果:

filter: 1
filter: 2
filter: 3
filter: 4
map: 2
map: 4
forEach: 5
forEach: 9

asSequence()将list序列转化为懒序列,即获取list中的一个数据,经过整套流程的处理,然后才获取list的下一个数据进行流程处理
如果没有asSequence(),list的全部数据会经过filter处理,然后是map处理,最后forEeach处理

(6)flatMap操作

在这里插入图片描述
所有元素一一映射到新集合,然后合并所有的新集合,最终得到一个集合
java:

list.stream().flatMap(e -> {
    ArrayList<Integer> integers = new ArrayList<>(e);
    for (int i = 0; i < e; i++) {
        integers.add(i);
    }
    return integers.stream();
});

// [1,2,3] -> [0,0,1,0,1,2]

kotlin:

list.flatMap {
        0 until it
    }
    .joinToString().let(::println)


list.asSequence()
    .flatMap {
        (0 until it).asSequence()
    }
    .joinToString().let(::println)

(7)集合的聚合操作

在这里插入图片描述
fold:
在这里插入图片描述
kotlin:

list.fold(StringBuilder()) { acc, i ->
    acc.append(i)
}

acc是上一次拼接的结果,i是list遍历的元素

(7)Zip变换

在这里插入图片描述


(五)SAM转换

(1)java的SAM

java的匿名内部类:

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(new Runnable() {

    @Override
    public void run() {
        System.out.println("run in executor.");
    }

});

java的SAM:

executor.submit(() -> System.out.println("run in executor."));

(2)kotlin的SAM

kotlin的匿名内部类:

executor.submit(object : Runnable {
    override fun run() {
        println("run in executor.")
    }
})

匿名内部类简写:

executor.submit(Runnable {
    println("run in executor.")
})

kotlin的SAM:

executor.submit { println("run in executor.") }

在这里插入图片描述

(3)SAM转换支持对比

在这里插入图片描述

(4)SAM小案例

java:

public class EventManager {
    interface OnEventListener {
        void onEvent(int event);
    }

    private HashSet<OnEventListener> onEventListeners = new HashSet<>();

    public void addOnEventListener(OnEventListener onEventListener) {
        this.onEventListeners.add(onEventListener);
    }

    public void removeOnEventListener(OnEventListener onEventListener) {
        this.onEventListeners.remove(onEventListener);
    }
}

kotlin:

fun main() {
    val eventManager = EventManager()

    val onEvent = object : EventManager.OnEventListener {
        override fun onEvent(event: Int) {
            println("onEvent $event")
        }
    }

    val onEvent2 = EventManager.OnEventListener{
        println("onEvent $it")
    }

    eventManager.addOnEventListener(onEvent)

    eventManager.removeOnEventListener(onEvent)

}

(六)案例:统计字符个数

fun main() {
    File("build.gradle").readText() // 1. read file
        .toCharArray() // 2. 字符串转成字符数组
        .filter { !it.isWhitespace() } // 3. filter white space 去掉空白字符
        // isWhitespace()方法用于判断指定字符是否为空白字符,空白符包含:空格、tab 键、换行符
        .groupBy { it } // 分组,得到结果(未统计个数的情况下): {p=[p, p, p, p, p, p, p, p, p, p, p, p, p], l=[l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l, l]
        .map {
            it.key to it.value.size
        }.let {
            println(it)
        }
}

结果:

[(p, 13), (l, 18), (u, 10), (g, 12), (i, 36), (n, 36), (s, 18), ({, 6), (d, 6), (', 16), (j, 9), (a, 16), (v, 9), (o, 33), (r, 21), (., 14), (e, 35), (t, 28), (b, 5), (k, 7), (m, 14), (1, 7), (3, 1), (6, 1), (0, 2), (}, 6), (c, 7), (y, 2), (h, 1), (-, 5), (S, 3), (N, 2), (A, 2), (P, 1), (H, 1), (O, 3), (T, 4), (C, 5), (=, 4), ((, 1), (), 1), (", 10), (:, 6), (8, 3), (,, 3), (4, 1), (2, 1), (K, 3), (f, 2), ([, 1), (X, 4), (L, 2), (+, 2), (w, 1), (I, 1), (F, 2), (], 1)]

(七)案例:HTML DSL

代码:

interface Node {
    fun render(): String
}

class StringNode(val content: String) : Node {
    override fun render(): String {
        return content
    }
}

class BlockNode(val name: String) : Node {

    val children = ArrayList<Node>()
    val properties = HashMap<String, Any>()

    override fun render(): String {
        return """<$name ${properties.map { "${it.key}='${it.value}'" }
            .joinToString(" ")}>${children.joinToString("") { it.render() }}</$name>"""
    }

    operator fun String.invoke(block: BlockNode.() -> Unit): BlockNode {
        val node = BlockNode(this)
        node.block()
        this@BlockNode.children += node
        return node
    }

    operator fun String.invoke(value: Any) {
        this@BlockNode.properties[this] = value
    }

    operator fun String.unaryPlus() {
        this@BlockNode.children += StringNode(this)
    }

}

fun html(block: BlockNode.() -> Unit): BlockNode {
    val html = BlockNode("html")
    html.block()
    return html
}

fun BlockNode.head(block: BlockNode.() -> Unit): BlockNode {
    val head = BlockNode("head")
    head.block()
    this.children += head
    return head
}

fun BlockNode.body(block: BlockNode.() -> Unit): BlockNode {
    val head = BlockNode("body")
    head.block()
    this.children += head
    return head
}

fun main() {
    val htmlContent = html {
        head {
            "meta" { "charset"("UTF-8") }
        }
        body {
            "div" {
                "style"(
                    """
                    width: 200px;
                    height: 200px;
                    line-height: 200px;
                    background-color: #C9394A;
                    text-align: center
                    """.trimIndent()
                )
                "span" {
                    "style"(
                        """
                        color: white;
                        font-family: Microsoft YaHei
                        """.trimIndent()
                    )
                    +"Hello HTML DSL!!"
                }
            }
        }
    }.render()

    File("Kotlin.html").writeText(htmlContent)
}

得到Kotlin.html文件:

<html ><head ><meta charset='UTF-8'></meta></head><body ><div style='width: 200px;
height: 200px;
line-height: 200px;
background-color: #C9394A;
text-align: center'><span style='color: white;
font-family: Microsoft YaHei'>Hello HTML DSL!!</span></div></body></html>

使用谷歌浏览器打开Kotlin.html文件
在这里插入图片描述


(八)实践:体验 Gradle Kotlin DSL

将一个Groovy DSL的Gradle改造成Kotlin DSL配置的Gradle

(1)改名

settings.gradle改为settings.gradle.kts
build.gradle改为build.gradle.kts

(2)修改内容

settings.gradle

rootProject.name = 'HelloWorld'

settings.gradle.kts(修改内容)

rootProject.name = "HelloWorld"

build.gradle

plugins {
    id 'java'
    id 'org.jetbrains.kotlin.jvm' version '1.3.60'
}

group 'com.lzacking.kotlin'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8

repositories {
    maven {
        url "https://maven.aliyun.com/repository/central"
    }
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    implementation "org.jetbrains.kotlin:kotlin-reflect"
    implementation "com.google.code.gson:gson:2.8.1"
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

build.gradle.kts(修改 )

import org.lzacking.kotlin.gradle.tasks.KotlinCompile

plugins {
    java
    //id ("java")
    kotlin("jvm") version ("1.3.60")
    //id("org.jetbrains.kotlin.jvm") version ("1.3.60")
}

group = "com.bennyhuo.kotlin"
version = "1.0-SNAPSHOT"

java {
    sourceCompatibility = JavaVersion.VERSION_1_8
}

repositories {
    maven("https://maven.aliyun.com/repository/central")
}

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("com.google.code.gson:gson:2.8.1")
    testCompile(group = "junit", name = "junit", version = "4.12")
}

val compileKotlin: KotlinCompile by tasks

compileKotlin.kotlinOptions {
    jvmTarget = "1.8"
}

val compileTestKotlin: KotlinCompile by tasks

compileTestKotlin.kotlinOptions {
    jvmTarget = "1.8"
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值