preface

This article mainly explains higher-order functions, inline functions, several useful higher-order functions, set transformation and sequence, SAM transformation, case: count the number of characters, case: HTML DSL, practice: Experience Gradle Kotlin DSL


List of Kotlin articles

List of Kotlin articles: Click here to jump to see


directory


(1) Higher-order functions

(1) The definition of higher-order functions

A function whose parameter type contains a function type or whose return value type is a function type is a higher-order function

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

fun returnsFunction(a): () - >Long {
    return { System.currentTimeMillis() }
}
Copy the code

(2) Call of higher-order functions

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

Call:

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

intArray.forEach {
    println(it)
}

intArray.forEach(::println)

intArray.forEach {
    println("Hello $it")}Copy the code
fun main(a) {
    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(a): () - >Long {
    var first = 0L
    var second = 1L
    return {
        val next = first + second
        val current = first
        first = second
        second = next
        current
    }
}
Copy the code

Results:

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

(2) inline function

(1) Definition of inline function

A function marked inline is an inline function, which is replaced at compile time with the body of the function’s method where the function is called

val ints = intArrayOf(1.2.3.4)
ints.forEach { // forEach is an inline function, where the code should be replaced with the body of the method inside forEach, i.e. the for loop
    println("Hello $it")}// forEach is an inline function
public inline fun IntArray.forEach(crossinline action: (Int) - >Unit): Unit {
    for (element in this) action(element)
}


// The above code can be written as follows
val ints = intArrayOf(1.2.3.4)
for (element in ints) {
    println("Hello $element")}Copy the code

(2) Return of the inline function

val ints = intArrayOf(1.2.3.4)
ints.forEach {
    if (it == 3) return@forEach // Only it == 3 is not executed, jumping out of this inline function call
    println("Hello $it")}// Equivalent to the above code
for (element in ints) {
    if (element == 3) continue
    println("Hello $element")}Copy the code

Results:

Hello 1
Hello 2
Hello 4


Hello 1
Hello 2
Hello 4
Copy the code

(3) The non-local return of the inline function

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

nonLocalReturn {
    return // Returns from an external function} such as:fun main(a) {
   nonLocalReturn {
     return // Return from main}}Copy the code
inline fun Runnable(block: () -> Unit): Runnable {
    return object : Runnable {
        override fun run(a) {
            block()
        }
    }
}
// There may be an invalid non-local return because the block is not called in the same call context as the definition
Copy the code

Improved: add noinline to prevent function arguments from being inlined

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

(4) Inline attributes

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

After compiling:

(5) Limitation of inline function

Public /protected inline methods can only access the corresponding class’s public members. Inline function arguments cannot be stored (assigned to variables). Inline function arguments can only be passed to other inline function arguments


(3) several useful higher-order functions

(1) An introduction to several useful higher-order functions

(2) Use of several useful higher-order functions

import java.io.File

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

fun main(a) {
    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())
        }
}
Copy the code

(4) Set transformation and sequence

(1) For I…

Java:

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

Kotlin:

for (i in 0.10.) {
    println(i)
}
Copy the code

(2) the forEach

Java:

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


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

Kotlin:

list.forEach {
    println(it);
}

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

Note that forEach cannot continue or break

(3) Examples of mapping operations for collections

(4) Filter operation

The elements that meet the conditions are retained to form a new setJava:

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

Kotlin:

list.filter { it % 2= =0 }

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

(5) Map operation

After some transformation, it becomes another set

Java:

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

Kotlin:

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

Integrated applets: 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); // if 1,3 does not meet the requirements, direct output; if 2,4 do not meet the requirements, proceed down
                    return e % 2= =0;
                })
                .map(e -> {
                    System.out.println("map: " + e);
                    return e * 2 + 1;
                })
                .forEach(e -> {
                    System.out.println("forEach: "+ e); }); }}Copy the code

Results:

filter: 1
filter: 2
map: 2
forEach: 5
filter: 3
filter: 4
map: 4
forEach: 9
Copy the code

Kotlin:

fun main(a) {
    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")}}Copy the code

Results:

filter: 1
filter: 2
map: 2
forEach: 5
filter: 3
filter: 4
map: 4
forEach: 9
Copy the code
fun main(a) {
    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")}}Copy the code

Results:

filter: 1
filter: 2
filter: 3
filter: 4
map: 2
map: 4
forEach: 5
forEach: 9
Copy the code

AsSequence () converts the list sequence into a lazy sequence, that is, it obtains one data in the list, processes the whole process, and then obtains the next data in the list for process processing. If there is no asSequence(), all data in the list will be processed by filter and then map. Finally, forEeach processes

(6) flatMap operation

All the elements are mapped to the new set one by one, and then all the new sets are merged to get one setJava:

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]
Copy the code

Kotlin:

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


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

(7) Aggregation operation of collection

A fold: Kotlin:

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

Acc is the result of the last concatenation, and I is the element traversed by the list

(7) Zip transformation


(5) SAM conversion

(1) Java SAM

Java’s anonymous inner classes:

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

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

Java SAM:

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

(2) SAM of Kotlin

Kotlin’s anonymous inner class:

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

Short for anonymous inner class:

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

Kotlin SAM:

executor.submit { println("run in executor.")}Copy the code

(3) SAM conversion supports comparison

(4) Small case of 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); }}Copy the code

Kotlin:

fun main(a) {
    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)

}
Copy the code

(6) Case: Count the number of characters

fun main(a) {
    File("build.gradle").readText() // 1. read file
        .toCharArray() // 2. String is converted to an array of characters.filter { ! it.isWhitespace() }// 3. Filter white space
        The isWhitespace() method is used to check whether specified characters are whitespace characters, including Spaces, TAB keys, and newlines
        .groupBy { it } // Get the result (if no number is counted) :  {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)
        }
}
Copy the code

Results:

[(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)]
Copy the code

(7) Case: HTML DSL

Code:

interface Node {
    fun render(a): String
}

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

class BlockNode(val name: String) : Node {

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

    override fun render(a): 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(a) {
        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(a) {
    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)
}
Copy the code

Get the kotlin.html file:

<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>Copy the code

Use Google Chrome to open the kotlin.html file


Practice: Experience Gradle Kotlin DSL

Convert a Groovy DSL Gradle to a Kotlin DSL Gradle

(1) Name change

Gradle changed to settings.gradle. KTS build.gradle changed to build.gradle. KTS

(2) Modify the content

settings.gradle

rootProject.name = 'HelloWorld'
Copy the code

Settings.gradle.kts (Modify content)

rootProject.name = "HelloWorld"
Copy the code

build.gradle

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

group 'com.lzacking.kotlin'
version 1.0 the 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"
}
Copy the code

Build.gradle.kts (modified)

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

plugins {
    java
    //id ("java")
    kotlin("jvm") version ("1.3.60")
    / / id (" org. Jetbrains. Kotlin. The JVM ") version (" 1.3.60 ")
}

group = "com.bennyhuo.kotlin"
version = "1.0 the 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"
}
Copy the code