前言
本文主要讲解高阶函数、内联函数、几个有用的高阶函数、集合变换与序列、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"
}