Kotlin學習手記——集合變換、序列、聚合、SAM轉換、DSL
val list = listOf(1, 2, 3, 4)
list.filter { it % 2 == 0 }
list.flatMap {
0 until it
}
.joinToString().let(::println)
list.asSequence()
.flatMap {
(0 until it).asSequence()
}
.joinToString().let(::println)
val newList = list.flatMap {
ArrayList<String>(it)
}
- sequence的概念
sequence類似java8裡面的stream流,或者RxJava裡面的流概念
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")
}
上面程式碼list
呼叫asSequence
後每個元素會依次呼叫filter
和map
, 不加asSequence
每個元素會先呼叫filter
再呼叫map
。
加asSequence
最後不加forEach
的話,不會有輸出,不加asSequence
的話,去掉forEach
也會有輸出。即加上asSequence
變成了流一樣。
asSequence
被稱為懶序列,使用asSequence
效能會優化一些,因為每個元素只需要走一遍每個操作,而不是每個操作中將每個元素走一遍。
sum
val list = listOf(1, 2, 3, 4)
val s = list.sum()
println("list.sum() $s")//10
val list = listOf(1, 2, 3, 4)
//acc是上次的計算結果,初始值為StringBuffer(),返回值跟初始值型別一樣
val foldStrBuf = list.fold(StringBuffer()){
acc, i -> acc.append(i)
}
println("list.fold() $foldStrBuf")//1234
reduce
val list = listOf(1, 2, 3, 4)
val r = list.reduce() { acc, i ->
acc + i
}
println("list.reduce() $r")//10
fold和reduce有點遞迴的意思在裡面,每次的結果都是基於上次的結果。
zip
val list = listOf(1, 2, 3, 4)
val array = arrayOf(2, 2)
val z = list.zip(array) { a: Int, b: Int ->
a * b
}
z.forEach {
println(it)
} // 2 4
val array2 = arrayOf("x", "y")
val z2 = list.zip(array2) { a: Int, b: String ->
"$a$b"
}
z2.forEach {
println(it)
} // 1x 2y
看原始碼,zip其實就是將兩個集合遍歷執行某個操作,只不過最終集合大小是以最小長度的那個集合為準:
public inline fun <T, R, V> Iterable<T>.zip(other: Array<out R>, transform: (a: T, b: R) -> V): List<V> {
val arraySize = other.size
val list = ArrayList<V>(minOf(collectionSizeOrDefault(10), arraySize))
var i = 0
for (element in this) {
if (i >= arraySize) break
list.add(transform(element, other[i++]))
}
return list
}
集合變換應用例子:
統計文字檔案中非空格字元出現的次數
import java.io.File
fun main() {
File("build.gradle").readText() // 1. read file
.toCharArray() // 2.
//.filter{ !it.isWhitespace() } // 3. filter white space
.filterNot(Char::isWhitespace) // 等價上面一行
.groupBy { it } //分組
.map {
it.key to it.value.size
}.let {
println(it)
}
}
SAM轉換
val executor: ExecutorService = Executors.newSingleThreadExecutor()
//匿名內部類的寫法
executor.submit(object : Runnable {
override fun run() {
println("run in executor.")
}
})
//匿名內部類簡寫
executor.submit(Runnable {
println("run in executor.")
})
//匿名內部類簡寫
executor.submit { println("run in executor.") }
kotlin中SAM目前只支援只有一個方法的java介面
fun submitRunnable(runnable: Runnable){
runnable.run()
}
submitRunnable {
println("Hello")
}
kotlin中SAM不支援只有一個方法的kotlin介面, 但是可以直接定義一個函式引數
下面這樣寫法是不行的:
interface Invokable {
fun invoke()
}
fun submit(invokable: Invokable) {
invokable.invoke()
}
//報錯
submit {
println("Hello")
}
下面這樣寫法是可行的:
typealias FunctionX = ()->Unit
//函式引數傳遞一個lambda表示式
fun submit(block: FunctionX){
block()
}
//等價這種直接傳lambda表示式的寫法
//fun submit(()->Unit){
//
//}
//這樣是可以的
submit {
println("Hello啊啊啊")
}
一個例子,新增和移除監聽的正確kotlin寫法:
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);
}
}
使用上面的java類:
fun main() {
val eventManager = EventManager()
//匿名內部類的寫法
val onEvent = EventManager.OnEventListener { event -> println("onEvent $event") }
//等價上面的寫法
val onEvent2 = object : EventManager.OnEventListener{
override fun onEvent(event: Int) {
println("onEvent $event")
}
}
// DO NOT use this.
//錯誤的寫法,這樣還是一個函式型別,傳到removeOnEventListener方法裡不能移除,
// 還是會呼叫方法建立一個物件
// val onEvent3 = { event: Int ->
// println("onEvent $event")
// }
eventManager.addOnEventListener(onEvent)
eventManager.removeOnEventListener(onEvent)
}
DSL: 領域特定語言
如sql語言、gradle中的groovy語言等,kotlin可以方便的實現這些語言的寫法
例子: 通過拼接操作生成一個html檔案
import java.io.File
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() {
//變數後面跟東西相當於傳遞一個lambda表示式
val htmlContent = html {
head {
"meta" { "charset"("UTF-8") } //字串後面跟東西相當於運算子過載 invoke
}
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)
}
這個例子主要有兩點:
- 一個是如果是變數後面跟東西相當於傳遞一個lambda表示式,那定義的時候其實就是定義一個函式來實現;
- 二是如果字串後面跟l東西相當於運算子過載
invoke
,跟{}
相當於引數是一個ambda表示式,跟()
就是普通引數,定義String類的擴充套件函式即可實現。
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
}
+"Hello HTML DSL!!"
這種也是字串的運算子過載:
operator fun String.unaryPlus(){
this@BlockNode.children += StringNode(this)
}
字串前面後面跟操作符好像基本都是運算子過載
另外擴充套件方法中如果想訪問除了自身以外的其他Receiver的話,只需將擴充套件方法定義到對應的類內部即可,如上面的String相關擴充套件方法直接定義到了BlockNode類的內部,就可以引用BlockNode類的成員屬性來使用了。
相關文章
- Java 8 Stream API 轉換到 Kotlin 集合APIJavaAPIKotlin
- Python——格式轉換的學習筆記Python筆記
- RxJava 學習筆記 -- 變換操作符RxJava筆記
- 快速傅立葉變換 學習筆記筆記
- android kotlin dp 轉換工具AndroidKotlin
- Solidity語言學習筆記————11、隱式轉換和顯式轉換Solid筆記
- 圖形學學習筆記二:觀測變換筆記
- 快速沃爾什變換 (FWT)學習筆記筆記
- 學習-Java順序結構之字元變換之大小寫字母轉換Java字元
- 陣列轉換成List集合陣列
- Java2Kotlin轉換自查表JavaKotlin
- OpenCV計算機視覺學習(11)——影像空間幾何變換(影像縮放,影像旋轉,影像翻轉,影像平移,仿射變換,映象變換)OpenCV計算機視覺
- 小波變換與深度學習深度學習
- 【演算法學習筆記】快速傅立葉變換演算法筆記
- OpenCV計算機視覺學習(3)——影像灰度線性變換與非線性變換(對數變換,伽馬變換)OpenCV計算機視覺
- 機器學習-- 資料轉換機器學習
- Java 集合與陣列互相轉換Java陣列
- kotlin學習筆記-異常好玩的list集合總結Kotlin筆記
- 變數型別轉換變數型別
- 快速傅立葉變換複習筆記筆記
- 學習和配置頁面轉換模型模型
- Gradle Kotlin DSL 1.0GradleKotlin
- 演算法學習筆記(46): 離散餘弦變換(DCT)演算法筆記
- 腦圖學習 JavaScript 之犀牛書【三 · 二】型別轉換、變數JavaScript型別變數
- OpenGL 學習 07 向量 矩陣變換 投影矩陣
- Pytorch變數型別轉換PyTorch變數型別
- Python pytorch 座標系變換與維度轉換PythonPyTorch
- 自學PHP筆記 (三) 型別轉換PHP筆記型別
- 自學PHP筆記(三) 型別轉換PHP筆記型別
- Java學習--xml文字轉換成Java物件JavaXML物件
- 學習 XSLT:XML文件轉換的關鍵XML
- Java基礎之IO轉換流學習Java
- JAVA型別轉換怎麼變Java型別
- iOS學習筆記04 檢視切換iOS筆記
- 重拾Kotlin(10)-型別的檢查與轉換Kotlin型別
- 初學java進位制轉換方面補充學習Java
- 視覺化學習:CSS transform與仿射變換視覺化CSSORM
- z變換與s變換之間的轉換(一些零碎且不嚴謹的想法)