Kotlin 高阶函数

400 阅读4分钟

forEach

遍历所有Element执行传入的action匿名函数,没有返回值

源码如下所示:
@kotlin.internal.HidesMembers
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
    for (element in this) action(element)
}
代码示例如下所示:
val list = listOf(1, 2, 3, 4, 5)
list.forEach(::println)

map

遍历所有Element执行传入的transform匿名函数,返回转换后的类型实例的集合

源码如下所示:
public inline fun <T, R> Iterable<T>.map(transform: (T)-> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
    for (item in this)
        destination.add(transform(item))
    return destination
}
代码示例如下所示:
val list = listOf(1, 2, 3, 4, 5)
val newList = list.map {
    it * 2
}
newList.forEach(::println)

flatMap

遍历集合的集合,返回一个转换后的集合

源码如下所示:
public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
    return flatMapTo(ArrayList<R>(), transform)
}

public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {
    for (element in this) {
        val list = transform(element)
        destination.addAll(list)
    }
    return destination
}
代码示例如下所示:
val list = listOf(
    1..10,
    12..24)
list.flatMap { intRange ->
    intRange.map { intElement ->
        "$intElement"
    }
}.forEach(::println)

reduce

求和或求阶乘等,返回结果类型有要求

源码如下所示:
public inline fun <S, T : S> Iterable<T>.reduce(operation: (acc: S, T) -> S): S {
    val iterator = this.iterator()
    if (!iterator.hasNext()) throw UnsupportedOperationException("Empty collection can't be reduced.")
    var accumulator: S = iterator.next()
    while (iterator.hasNext()) {
        accumulator = operation(accumulator, iterator.next())
    }
    return accumulator
}
代码示例如下所示:
val list = listOf(1 ,2, 3, 4, 5)
    val sum = list.reduce { acc, i ->
        acc + i
    }
    println(sum)
    
    val factorialNum = (1..5).reduce { acc, i -> acc * i }
    println(factorialNum)
}

fold

可以是加强版的带初始值的,不限制返回结果类型的reduce,也可以做变换

源码如下所示:
public inline fun <T, R> Iterable<T>.fold(initial: R, operation: (acc: R, T) -> R): R {
    var accumulator = initial
    for (element in this) accumulator = operation(accumulator, element)
    return accumulator
}
代码示例如下所示:
fun factorial(n: Int): Int {
    if (n == 0) return 1
    return (1..n).reduce { acc, i -> acc * i }
}

fun main(args: Array<String>) {
    val sum = (1..3).map(::factorial).fold(5) { acc, i ->
        acc + i
    }
    println(sum)
    // 嫌弃字符串最后还有`,`可使用foldIndexed处理
    val str = (1..6).map(::factorial).fold(StringBuilder()) { acc, i ->
        acc.append(i).append(",")
    }
    println(str)
    println((1..6).map(::factorial).joinToString(","))
}

filter

过滤一些数据,为true则保留,为false则被过滤掉

源码如下所示:
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}

public inline fun <T, C : MutableCollection<in T>> Iterable<T>.filterTo(destination: C, predicate: (T) -> Boolean): C {
    for (element in this) if (predicate(element)) destination.add(element)
    return destination
}
代码示例如下所示:
val list = listOf("a", "b", "", "c")
list.filter(String::isNotEmpty).forEach(::println)

takeWhile

当遇到第一个不符合条件的立马结束迭代,把前面的符合条件的数据存入集合并返回

源码如下所示:
public inline fun <T> Iterable<T>.takeWhile(predicate: (T) -> Boolean): List<T> {
    val list = ArrayList<T>()
    for (item in this) {
        if (!predicate(item))
            break
        list.add(item)
    }
    return list
}
代码示例如下所示:
val list = listOf(2, 4, 6, 8, 1, 2, 3, 4)
list.takeWhile {
    it % 2 == 0
}.forEach(::println)

let

实际上是一个作用域函数,如定义一个变量在一个特定的作用域范围内。let函数另一个作用就是可以避免写一些判断null的操作。

源码如下所示:
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}
代码示例如下所示:
fun main(args: Array<String>) {
    val city = getCityById(110101)
    println(city?.id)
    println(city?.name)
    println(city?.country)
    city?.let {
        println(city.id)
        println(city.name)
        println(city.country)
    }
}

data class City(val id: Long, val name: String, val country: String = "China")

fun getCityById(id: Long): City? {
    return City(id, "Beijing")
}

apply

传入的是扩展的lambda表达式,在调用对象的作用域内直接调用属性或方法,不同于let函数

源码如下所示:
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}
代码示例如下所示:
fun main(args: Array<String>) {
    val city = getCityById(110101)
    city?.apply {
        println(id)
        println(name)
        println(country)
    }
}

data class City(val id: Long, val name: String, val country: String = "China")

fun getCityById(id: Long): City? {
    return City(id, "Beijing")
}

with

不同于apply,主要区别在于receiver是传入进来的

源码如下所示:
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}
代码示例如下所示:
fun main(args: Array<String>) {
    val br = BufferedReader(FileReader("build.gradle"))
    with(br) {
        var line: String?
        while (true) {
            line = readLine()?:break
            println(line)
        }
        close()
    }
}

use

传入closable接口,封装关闭的功能

源码如下所示:
@InlineOnly
@RequireKotlin("1.2", versionKind = RequireKotlinVersionKind.COMPILER_VERSION, message = "Requires newer compiler version to be inlined correctly.")
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
    var exception: Throwable? = null
    try {
        return block(this)
    } catch (e: Throwable) {
        exception = e
        throw e
    } finally {
        when {
            apiVersionIsAtLeast(1, 1, 0) -> this.closeFinally(exception)
            this == null -> {}
            exception == null -> close()
            else ->
                try {
                    close()
                } catch (closeException: Throwable) {
                    // cause.addSuppressed(closeException) // ignored here
                }
        }
    }
}
代码示例如下所示:
fun main(args: Array<String>) {
    val br = BufferedReader(FileReader("build.gradle"))
    br.use {
        var line: String?
        while (true) {
            line = readLine()?:break
            println(line)
        }
    }
}