Kotlin學(xué)習(xí)筆記

項目未來可能需要使用kotlin開發(fā),所以特此記錄一下學(xué)習(xí)筆記冕象,僅供參考墓律,方便后期查詢。已同步到GitHub上:KotlinTest

Kotlin 簡介

kotlin 的目標(biāo)是成為一門全棧語言低斋,主要有以下的特點:

  • 已經(jīng)成為Android的官方推薦語言
  • 百分百的和java兼容,兩者可以相互轉(zhuǎn)換
  • JS讽挟、JVMNative多平臺開發(fā)

數(shù)據(jù)類型

1. 基本類型

Boolean true/false
Double 64
Float  32
Long   64
Int    32
Short  32
Byte   8

val aChar = '0'
val bChar = '我'
val cChar = '\u000f'

Char類型的轉(zhuǎn)義字符

\t          制表符
\b          光標(biāo)后退一個字符
\n          回車
\r          光標(biāo)回到行首
\'          單引號
\"          雙引號
\\          反斜杠
\$          美元符號丸冕,Kotlin 支持美元符號開頭的字符串模板

2. 基本類型的轉(zhuǎn)換

不可隱式轉(zhuǎn)換

val anInt: Int = 5
val aLong: Long = anInt.toLong()

必須得通過.to類型的方式進(jìn)行數(shù)據(jù)的轉(zhuǎn)換

字符串

  • 一串Char

  • 用雙引號""引起來

    val aString: String = "Hello World!"

  • 字符串比較

    a == b 表示比較內(nèi)容 類似 Java 中的 equals
    a === b 表示比較對象是否相同

  • 字符串模板

    println("hello, $name") -> "hello, 小明"

3. Koltin 中的類和對象初始化

類的定義

  • 類耽梅,一個抽象的概念
  • 具有某些特征的事物的概括
  • 不特定指代任何一個具體的事物

一般寫法:

/**
* 其中類參數(shù)如果加上 var 修飾,那么他便是成員變量胖烛,反之則是普通的參數(shù)
*/
class Student(var name: String, var age: Int){
    init {
        // ... 相當(dāng)于構(gòu)造函數(shù)中的代碼
    }
}

對象

  • 是一個具體的概念眼姐,與類相對

  • 描述某一個類的具體個體

  • 舉例:

    某些人、領(lǐng)導(dǎo)的車等等

類和對象的關(guān)系

  • 一個類通撑宸可以有很多歌具體的對象
  • 一個對象本質(zhì)上只能從屬一個類
  • 某一個人众旗,他是工程師,但本質(zhì)上還是屬于人這一類

一般寫法:

val student: Student = Student("xiaweizi", 23)

類的繼承

  • 提取多個類的共性得到一個更為抽象的類趟畏,即父類
  • 子類擁有父類的一切特征
  • 子類也可以定義自己的特征
  • 所有的類最終繼承自Any,類似于java中的Object

4. 空類型和智能轉(zhuǎn)換

空類型

// 定義
val notNull: String = null // 錯誤贡歧,不可能為空
val nullanle: String? = null // 正確,可以為空
// 使用
notNull.length // 正確拱镐,不可能為空所以可以直接使用
nullable.length // 有可能為空艘款,不能直接獲取長度
// 要想獲取長度持际,可以通過以下兩者方式
nullable!!.length // 正確沃琅,強制認(rèn)定 nullable 不可能為空,如果為空則會拋出空指針異常
nullable?.length // 正確蜘欲,若 nullable 為空益眉,則返回 null

智能類型轉(zhuǎn)換

val child: Child = parent as Child // 類似于 Java 的類型轉(zhuǎn)換,失敗則拋出異常
val child: Child = parent as? Child // 如果轉(zhuǎn)換失敗姥份,返回 null

編譯器智能識別轉(zhuǎn)換:

val parent: Parent = Child()
if (parent is Child) {
    // parent 直接調(diào)用子類方法,不需要再進(jìn)行強制轉(zhuǎn)換
}

val string: String = null
if (string != null) {
    // string.length 可以直接調(diào)用length 方法
}

5. 區(qū)間

一個數(shù)學(xué)上的概念郭脂,表示范圍, ClosedRange的子類澈歉,IntRange最常用

基本用法:

0..100 --> [0, 100]
0 until 100 --> [0, 100)
i in 0..100 表示 i 是否在區(qū)間[0, 100]中

6. 數(shù)組

基本寫法:

val ints: IntArray = IntArrayOf(1,2,3,5)
var charArray: CharArray = charArrayOf('a', 'b', 'c', 'd', 'e')
var stringArray: Array<String> = arrayOf("aa", "bb", "cc", "dd", "e")

基本操作:

print(charArray[index])
ints[0] = 2
ints.length
cahrArray.joinToString("") // 講 char 數(shù)組轉(zhuǎn)換成字符串
stringArray.slice(1..4) // 取出區(qū)間里的值

程序結(jié)構(gòu)

1. 常亮和變量

常量

val a = 2
類似 Java 中的 final
不可被重復(fù)賦值
運行時常量:val x = getX()
編譯期常量:const val x = 2

變量

var a = 2
a = 3 // 可以被再次賦值

類型推導(dǎo)

val string = "Hello" // 推導(dǎo)出 String 類型
val int = 5 // 推導(dǎo)出 Int 類型
var x = getString() + 5 // String 類型

2. 函數(shù) Function

以特定功能組織起來的代碼塊

// 最簡單的打印信息展鸡,無返回的方法
fun printMessage(message: String):Unit{
    println("$message")
}
// 擁有返回值得方法
fun sum(first: Int, second: Int):Int {
    return first + second
}
// 可以簡化成:
fun sum(first: Int, second: Int) = first + second
// 或者更簡單的匿名函數(shù)
val result = fun(first: Int, second: Int) = first + second

3. Lambda 表達(dá)式

其實又是匿名函數(shù)

一般形式

{傳入?yún)?shù) -> 函數(shù)體,最后一行是返回值}
// 例如
val sum = {first: Int, second: Int -> first + second}
val printMessage = {message: String -> println(message)}

類型標(biāo)識

() -> Unit // 無參埃难,返回值為 null
(Int) -> Int // 傳入整型莹弊,返回一個整型
(String, (String) -> String) -> Boolean // 傳入字符串、Lambda 表達(dá)式涡尘,返回Boolean

Lambda 表達(dá)式的簡化

  • 函數(shù)參數(shù)調(diào)用時最后一個Lambda可以移出去
  • 函數(shù)參數(shù)只有一個Lambda忍弛,調(diào)用時小括號可以省略
  • Lambda只有一個參數(shù)可默認(rèn)為it
  • 入?yún)ⅰ⒎祷刂蹬c形參一致的函數(shù)可以用函數(shù)引用方式作為實參傳入

4. 成員變量和成員方法

成員變量的聲明

// 第一種是在構(gòu)造函數(shù)中聲明
class Student(var age: Int, name: String){
    // age 是成員變量 name 是局部變量
}
// 第二種是在函數(shù)體內(nèi)聲明
var a = 0
    get() {
        field += 1
        return field
    }
    set(value) {
        println("set)
        field = value + 1
    }
// 可以進(jìn)行對 get 和 set 方法的重新定義

// 屬性的初始化盡量在構(gòu)造方法中完成
// var 用 lateinit 延遲初始化考抄, val 用 lazy

lateinit var sex: String
val person: Person by lazy {
    Person()
}

成員方法

在類中直接聲明方法可以直接調(diào)用,包括lambda表達(dá)式

// 方法的聲明
fun sum(a: Int, b: Int) = a + b
val sum1 = {a: Int, b: Int -> a + b}
// 方法的調(diào)用
println(person.sum(1,2))
println(person.sum1(3,5))

5. 運算符

java中運算符是不能重新定義重載的细疚,只能按照原先的邏輯進(jìn)行計算

Kotlin則可以重新定義運算符,使用operator關(guān)鍵字川梅,舉了例子:

// 定義一個用于計算復(fù)數(shù)的類
class Complex(var real: Double, var imaginary: Double) {
    operator fun plus(other: Complex): Complex{
        return Complex(real+other.real, imaginary+other.imaginary)
    }
    
    // 重新 toString 方法
    overrride fun toString(): String {
        return "$real + ${imaginary}i"
    }
}
// 使用
val complex1 = Complex(1, 2)
val complex2 = Complex(2, 3)
println(complex1 + complex2)
// 輸出結(jié)果為
"3 + 5i"

關(guān)鍵就是這個方法疯兼,方法名必須是plus或者其他官方定義的運算符然遏,參數(shù)有且僅有一個,類型自定義吧彪,返回值意識可以自定義的.

operator fun plus(other: Complex): Complex{
        return Complex(real+other.real, imaginary+other.imaginary)
}

6. 表達(dá)式

中綴表達(dá)式

通過infix關(guān)鍵字修復(fù)方法啦鸣,那么就可以不用通過 對象.方法() 的方式調(diào)用,而是直接 對象 方法名 參數(shù)的方式調(diào)用来氧。舉了例子

class Student(var age: Int){
    infix fun big(student: Student): Boolean {
        return age > student.age
    }
}
// 如果沒有 infix 的調(diào)用方式:
println(Student(23).big(Student)(12))
// 如果使用 infix 修飾的調(diào)用方式:
println(Student(23) big Student(12))

if表達(dá)式

直接來個例子

val a = 20
val b = 30
val flag: Int = if(a > b) a else b

When 表達(dá)式

加強版的 switch诫给,支持任意類型, 支持純粹表達(dá)式條件分支(類似if)啦扬,舉個栗子:

val a = 5
when(a) {
    is Int -> println("$a is Int")
    in 1..6 -> println("$a is in 1..6")
    !in 1..4 -> println("$a is not in 1..4")
    else -> {
        println("null")
    }
}

for循環(huán)

基本寫法

for (element in elements)

while循環(huán)

基本寫法

while() {
}
do {
} while()

跳過和終止循環(huán)

跳過當(dāng)前循環(huán)用 continue
終止循環(huán)用 break

6. 異常捕獲

同樣也是表達(dá)式中狂,可以用來賦值,舉個例子

return try{
            x/y
        }
        catch(e: Exception) {
            0
        } finally {
            //...
        }

如果沒有異常則返回x/y,否則返回0,finally中的代碼無論如何還是要執(zhí)行的扑毡。

7. 具名參數(shù)胃榕、變長參數(shù)和默認(rèn)參數(shù)

具名參數(shù):給函數(shù)的實參附上形參

fun sum(first: Int, second: Int) = first + second
sum(second = 2, first = 1)

變長參數(shù):varary修飾,使用起來是和數(shù)組一樣瞄摊,某個參數(shù)可以接收多個值勋又,可以不作為最后一個參數(shù),如果傳參時有歧義换帜,需要使用具名參數(shù)楔壤。

fun hello(vararg ints: Int, string: String) = ints.forEach(println(it))
hello(1,3,4,5,string = "hello")
// 如果最后一個參數(shù)也是 Int
fun hello(varary ints: Int, anInt: Int)
// 創(chuàng)建數(shù)組
val arrayInt: IntArray = intArrayOf(1, 2, 3, 4)
hello(ints = *arrayInt, anInt = 2)

默認(rèn)參數(shù):就是給參數(shù)傳入一個默認(rèn)的值

fun hello(anInt: Int = 1, string: String)
hello(string = "aaa")

面向?qū)ο?/h2>

1. 繼承

繼承語法要點:

  • 父類需要open才可以被繼承
  • 父類方法、屬性需要open才可以被覆寫
  • 接口惯驼、接口方法蹲嚣、抽象類默認(rèn)為open
  • 覆寫父類(接口)成員需要override關(guān)鍵字

語法要點:

  • class A: B(), C, D
  • 繼承類時實際上調(diào)用了父類的構(gòu)造方法
  • 類只能單繼承,接口可以多實現(xiàn)

接口代理:

一個類可以直接將自己的任務(wù)委托給接口的方法實現(xiàn)祟牲,舉個例子:

interface Drive{
    fun drive()
}

interface Sing{
    fun sing()
}

class CarDrive: Drive{
    override fun drive() {
        println("我會開車呦")
    }
}

class LoveSing: Sing{
    override fun sing() {
        println("我會唱歌呦")
    }
}

class Manager(drive: Drive, sing: Sing): Drive by drive, Sing by sing

fun main(args: Array<String>) {
    val carDrive = CarDrive()
    val loveSing = LoveSing()
    val manager = Manager(carDrive, loveSing)
    manager.drive()
    manager.sing()
}

這樣隙畜,manager不用做任何事情,完全交付給接口實現(xiàn).

接口方法沖突:

接口方法可以有默認(rèn)實現(xiàn)说贝,通過super<父類名>.方法名

interface A{
    fun a() = 0
}

interface B{
    fun a() = 1
}

interface C{
    fun a() = 2
}

class D(var aInt: Int): A,B,C{
    override fun a(): Int {
        return when(aInt){
            in 1..10 ->{
                super<A>.a()
            }
            in 11..100 ->{
                 super<B>.a()
             }
            else -> {
                println("dd")
                super<C>.a()
            }
        }
    }
}

2. 類及成員的可見性

java類似议惰,private、protected乡恕、public言询,其中internal代表的是模塊內(nèi)可見

3. Object

相當(dāng)于Java中的單例模式,有以下特點

  • 只有一個實例的類

  • 不能自定義構(gòu)造方法

  • 可以實現(xiàn)接口几颜、繼承父類

  • 本質(zhì)上就是單例模式最基本的實現(xiàn)

      interface getDataSuccess{
          fun success()
      }
      
      abstract class getDataField{
          abstract fun failed()
      }
      
      object NetUtil: getDataField(), getDataSuccess{
          override fun success() {
              println("success")
          }
      
          override fun failed() {
              println("failed")
          }
      
          val state: Int = 0
          fun getData(): String = "請求成功"
      }
    

3. 伴生對象和靜態(tài)成員

相當(dāng)于java中的靜態(tài)方法

  • 每個類可以對應(yīng)一個伴生對象

  • 伴生對象的成員全局獨一份

  • 如果java中想直接調(diào)用kotlin中的靜態(tài)方法或者靜態(tài)變量倍试,可以考慮使用JvmField JvmStatic.

      open class Util private constructor(var anInt: Int) {
          companion object {
              @JvmStatic
              fun plus(first: Int, second: Int) = first + second
      
              fun copy(util: Util) = Util(util.anInt)
              @JvmField
              val tag = "tag"
          }
      }
    

4. 方法的重載

通過給方法的參數(shù)配置默認(rèn)值,即可實現(xiàn)方法的重載蛋哭,按理說县习,一切可以擁有默認(rèn)值的方法重載才是合理的方法重載。

名稱形同、參數(shù)不同躁愿,跟返回值沒有關(guān)系

class OverLoadTest {
    @JvmOverLoads
    fun a(anInt: Int = 0, string: String="") = 1
}

val test = OverLoadTest()
test.a(1, "")
test.a()
test.a(anInt = 2)
test.a(string = "")

使用JvmOverLoads是為了方便Java中調(diào)用方法的重載.

5. 擴展方法

kotlin中的擴展方法叛本,我認(rèn)為相當(dāng)于java中的代理模式,拿到被代理的對象彤钟,然后進(jìn)行一系列的操作来候。

fun String.add(anInt: Int): String {
    var sb = StringBuilder()
    for (i in 0 until anInt) {
        sb.append(this)
    }
    return sb.toString()
}

operator fun String.times(anInt: Int): String {
    var sb = StringBuilder()
    for (i in 0 until anInt) {
        sb.append(this)
    }
    return sb.toString()
}

// 使用
var string = "xiaweizi"
println(string.add(5))
println(string * (3))

6. 屬性代理

類似之前說的var anInt: Int by lazy{2},懶賦值就是使用的屬性代理,來看個例子:

fun main(args: Array<String>) {
    val a: Int by DelegatesTest()
    println(a)

    var b: Int by DelegatesTest()
    b = 3
    println(b)
}

class DelegatesTest {
    private var anInt: Int? = null
    operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
        println("getValue")
        return anInt?:0
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int): Unit {
        println("setValue")
        this.anInt = value
    }
}

val 對應(yīng) getValue逸雹,var對應(yīng)getValue和setValue方法营搅,這個時候聲明的屬性就全權(quán)交付給DelegatesTest類中的anInt代理,當(dāng)anInt為空的時候返回0梆砸,否則返回anInt.

7. JavaBean

使用data修飾類转质,類似java中的javaBean,默認(rèn)實現(xiàn)了set get toString等方法,并擁有componentN方法.

不過有個缺點就是帖世,無法被繼承休蟹,沒有無參構(gòu)造函數(shù),可以通過安裝allOpennoArg插件解決這個問題.

data class UserBean(var name: String, var age: Int)

val userBean: UserBean = UserBean("小芳", 23)
println(userBean.name)
println(userBean.toString())

println(userBean.component1())
println(userBean.component2())

val (name, age) = userBean
println("name: $name")
println("age: $age")

至于這種寫法val (name, age) = userBean日矫,是因為定義了component1的運算符

class Complex{
    operator fun component1() = "你好呀"
    operator fun component2() = 2
    operator fun component3() = 'a'
}

val complex = Complex()
val (a, b, c) = complex
println(a + b + c)

使用起來也是很簡單的

8. 內(nèi)部類

  • 定義在類內(nèi)部的類
  • 與類成員有相似的訪問控制
  • 默認(rèn)是靜態(tài)內(nèi)部類赂弓,非靜態(tài)用 inner 關(guān)鍵字
  • this@Outter this@Inner 的用法
  • 匿名內(nèi)部類
    • 沒有定義名字的內(nèi)部類
    • 類名編譯時生成,類似Outter$1.class
    • 可繼承父類哪轿,實現(xiàn)多個接口盈魁,與Java注意區(qū)別

舉個例子:

class Outer{
    var string: String = "outer"
    class Inner1{
        var string: String = "inner1"
        fun sum(first: Int, second: Int) = first + second
    }

    inner class Inner2{
        var string: String = "inner2"
        fun cha(first: Int, second: Int) = first - second
        fun getInnerField() = this.string
        fun getOuterField() = this@Outer.string
    }
}

fun main(args: Array<String>) {
    val inner1 = Outer.Inner1()
    val inner2 = Outer().Inner2()

    println(inner1.sum(1, 2))

    println(inner2.cha(2, 1))
    println(inner2.getInnerField())
    println(inner2.getOuterField())
}

匿名內(nèi)部類:

val listener: onClickListener = object : Father(), Mother, onClickListener{
    override fun sing() {
        println("mother sing")
    }

    override fun teach() {
        println("father teach")
    }

    override fun onClick() {
        println("匿名內(nèi)部類")
    }
}

使用Object實現(xiàn)匿名內(nèi)部類

9. 枚舉和密封類

枚舉是對象可數(shù),每個狀態(tài)相當(dāng)于每個對象缔逛,是可以傳構(gòu)造參數(shù)的

密封類時子類可數(shù)备埃,在kotlin大于1.1子類只需要與密封類在同一個文件加姓惑,保護子類的位置

sealed class SealedClassTest{
    class sum(first: Int, seocnd: Int): SealedClassTest()
    class cha(first: Int, seocnd: Int): SealedClassTest()

    object Bean: SealedClassTest()
}

enum class HttpStatus(val anInt: Int){
    SUCCESS(0), FAILED(1), LOADING(2)
}

fun main(args: Array<String>) {
    val class1 = SealedClassTest.cha(1, 2)
    println(HttpStatus.SUCCESS)
}

高階函數(shù)

1. 基本概念

  • 傳入或者返回函數(shù)的函數(shù)
  • 函數(shù)引用 ::println
  • 帶有Receiver的引用 pdfPrinter::println

有三種顯示

// 1. 包級函數(shù)
intArray.forEach(::print)

// 2. 類.方法
intArray.forEach(Int::addOne)
fun Int.addOne(): Unit {
    println("addOne:$this")
}

// 3. 對象.方法
intArray.forEach(AddTwo()::addTwo)
class AddTwo {
    fun addTwo(anInt: Int): Unit {
        println("addTwo:$anInt")
    }
}

2. 常用的高階函數(shù)

常用的高階函數(shù)還是有很多的褐奴,會簡單的使用例子即可:

// 遍歷
fun forEachTest() {
    val strings: Array<String> = arrayOf("aa", "ee", "bb", "ll")

    strings.forEach { println(it) } // 遍歷每一個值
    strings.forEachIndexed { index, s -> println("index:$index,String:$s") } // 遍歷 下標(biāo)和值一一對應(yīng)

}

// 重新拷貝一個值
fun mapTest() {
    val strings: Array<String> = arrayOf("aa", "ee", "bb", "ll")
    var map = strings.map { "$it-test" }
    map.forEach { print("$it\t") }
}

// 將集合合體
fun flatMapTest() {
    val lists = listOf(1..10,
            2..11,
            3..12)

    var flatMap = lists.flatMap {
        it.map {
            "No.$it"
        }
    }
    flatMap.forEach(::println)
}

fun reduceTest() {
    val ints = listOf(2, 3, 4, 5)
    println(ints.reduce { acc, i ->
        acc + i
    })
}

// 字符串連接
fun foldTest(){
    val ints = listOf(2, 3, 4, 5)
    println(ints.fold(StringBuffer(), { acc, i -> acc.append("$i,") }))
    println(ints.joinToString(","))
}

fun filterTest() {
    val ints = listOf(1, 2, 3, 4, 5, 6)
    println(ints.filter { element -> element % 2 == 0 })
}

// 當(dāng)值不是奇數(shù)就去,遇到偶數(shù)就停止了
fun takeWhileTest() {
    val ints = listOf(1, 3, 3, 4, 5, 6)
    println(ints.takeWhile { it % 2 != 0 })
}

fun letTest() {
    findPerson()?.let { (name, age) -> println("name:$name, age:$age") }
    findPerson()?.apply { println("name:$name, age:$age") }
    with(findPerson()!!) { println("name:$name, age:$age") }
}

data class Person(val name: String, val age: Int)

fun findPerson(): Person? {
    return Person("aa", 23)
}

3. 復(fù)合函數(shù)

有點類似數(shù)據(jù)中的f(g(x))

fun main(args: Array<String>) {
    val add1 = {int: Int ->
        println("add1")
        int + 1}
    val add2 = {int : Int ->
        println("add2")
        int + 2}
    var add3 = add1 addThen (add2)
    println(add3(4))
}


infix fun <P1, P2, R> Function1<P1, P2>.addThen(function: Function1<P2, R>): Function1<P1, R> {
    return fun(p: P1): R{
        return function.invoke(this.invoke(p))
    }
}

4. Currying

簡單來說就是多元函數(shù)變換成一元函數(shù)調(diào)用鏈?zhǔn)接诒校e個簡單的例子敦冬,這是優(yōu)化之前:

fun log(tag: String, out: OutputStream, message: String){
    out.write("[$tag], $message".toByteArray())
}

優(yōu)化之后

fun log(tag: String)
    = fun(out: OutputStream)
    = fun(message: String)
    = out.write("[$tag], $message".toByteArray())

5. 計算文件字符串個數(shù)的小例子

首先將字符串轉(zhuǎn)換成字符串?dāng)?shù)組:

val map: HashMap<Char, Int> = HashMap()
var toCharArray = File("build.gradle").readText().toCharArray()

通過分組的方式,統(tǒng)計每個字符串的個數(shù)唯沮,并打硬焙怠:

toCharArray.groupBy { it }.map { it.key to  it.value.size }.forEach { println(it) }

kotlinjava的混合開發(fā)

1. 基本的交互操作

屬性讀寫

  • Kotlin自動識別 Java Getter/Setter
  • Java操作Kotlin屬性通過Getter/Setter

空安全類型

  • Kotlin空安全類型的原理
  • 平臺類型Platform Type
  • Java可以通過@Nullable、@NotNull

幾類函數(shù)的調(diào)用

  • 包級函數(shù):靜態(tài)方法
  • 擴展方法:帶Receiver的靜態(tài)方法
  • 運算符重載:帶Receiver的對應(yīng)名稱的靜態(tài)方法

幾個常用的注解

  • @JvmField:將屬性編譯為Java變量
  • @JvmStatic:將對象的方法編譯成功Java靜態(tài)方法
  • @JvmOverloads:默認(rèn)參數(shù)生成重載方法
  • @JvmName:制定Kotlin文件編譯后的類名

NoArg 和 AllOpen

  • NoArg為被標(biāo)注的類生成無參構(gòu)造
  • AllOpen為被標(biāo)注的類去掉final介蛉,允許被繼承

正則表達(dá)式

  • Raw字符串定義正則表達(dá)式
  • JavaPattern
  • KotlinRegex

舉個例子:

val source = "Hello This my phone number: 010-12345678."
val pattern = """.*(\d{3}-\d{8}).*"""

Regex(pattern).findAll(source).toList().flatMap(MatchResult::groupValues).forEach(::print)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末萌庆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子币旧,更是在濱河造成了極大的恐慌践险,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異巍虫,居然都是意外死亡彭则,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門占遥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來俯抖,“玉大人,你說我怎么就攤上這事瓦胎》移迹” “怎么了?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵搔啊,是天一觀的道長担忧。 經(jīng)常有香客問我,道長坯癣,這世上最難降的妖魔是什么瓶盛? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮示罗,結(jié)果婚禮上惩猫,老公的妹妹穿的比我還像新娘。我一直安慰自己蚜点,他們只是感情好轧房,可當(dāng)我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著绍绘,像睡著了一般奶镶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上陪拘,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天厂镇,我揣著相機與錄音,去河邊找鬼左刽。 笑死捺信,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的欠痴。 我是一名探鬼主播迄靠,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼喇辽!你這毒婦竟也來了掌挚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤菩咨,失蹤者是張志新(化名)和其女友劉穎吠式,沒想到半個月后舅世,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡奇徒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年雏亚,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摩钙。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡罢低,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出胖笛,到底是詐尸還是另有隱情网持,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布长踊,位于F島的核電站功舀,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏身弊。R本人自食惡果不足惜辟汰,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望阱佛。 院中可真熱鬧帖汞,春花似錦、人聲如沸凑术。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伤为。三九已至蚁趁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泄鹏,已是汗流浹背郎任。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留命满,地道東北人涝滴。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像胶台,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子杂抽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容