kotlin集合高效使用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kotlin集合高效使用相关的知识,希望对你有一定的参考价值。

参考技术A 1、来了老弟?
2、映射为List: map,mapIndexed,mapNotNull,mapIndexedNotNull

val numbers = setOf(1, 2, 3)

println(numbers.map it * 3 )

//[3, 6, 9]

println(numbers.mapIndexed idx, value -> value * idx )

//[0, 2, 6]

3、双路合并

(1)zip()将两个集合中具有相同位置的元素构建配对。

val list1 = listOf(1, 2, 3)

val list2 = listOf("a", "b", "c")

val list = list1.zip(list2)

println(list)

//[(1, a), (2, b), (3, c)]

val list3 = list1.zip(list2) l1, l2 -> "$l1----$l2"

println(list3)

//[1----a, 2----b, 3----c]

(2)反向转换unzip(),list.unzip()得到一个Pair对象

val numberPairs = listOf("one" to 1, "two" to 2, "three" to 3, "four" to 4)

println(numberPairs.unzip())

//([one, two, three, four], [1, 2, 3, 4])

4、关联

根据集合元素和与其关联的某些值构建 Map。

(1) Map associateWith() 。其中原始集合的元素是键,值来自给定的转换函数。 如果两个元素相等,则仅保留最后一个。

val numbers = listOf("one", "two", "three", "four")

val map = numbers.associateWith it.length

println(map)

//one=3, two=3, three=5, four=4

(2) associateBy()。 键来自给定的转换函数,原始集合中的元素是值。也可以使用keySelector和valueTransform设置键和值。两个元素相等,则仅保留最后一个。

val numbers = listOf("one", "two", "three", "four")

println(numbers.associateBy it.first().toUpperCase() )

//O=one, T=three, F=four

println(numbers.associateBy(keySelector = it.first().toUpperCase() , valueTransform = it.length ))

//O=3, T=5, F=4

(3)associate()。键和值都是根据集合元素生成的。associate() 会生成临时的 Pair 对象,这可能会影响性能。

data class FullName(val firstName: String, val lastName: String)

fun parseFullName(fullName: String): FullName

    val nameParts = fullName.split(" ")

    if (nameParts.size == 2)

        return FullName(nameParts[0], nameParts[1])

    else throw Exception("Wrong name format")



val names = listOf("Alice Adams", "Brian Brown", "Clara Campbell")

println(names.associate name -> parseFullName(name).let it.lastName to it.firstName )

//Adams=Alice, Brown=Brian, Campbell=Clara

5、打平

flatMap()可以打平集合中对象的某个类型为list的字段的值。

data class StringContainer(val values: List<String>)

val containers = listOf(

        StringContainer(listOf("one", "two", "three")),

        StringContainer(listOf("four", "five", "six")),

        StringContainer(listOf("seven", "eight"))

)

println(containers)

//[StringContainer(values=[one, two, three]), StringContainer(values=[four, five, six]), StringContainer(values=[seven, eight])]

println(containers.flatMap it.values )

//[one, two, three, four, five, six, seven, eight]

//即可以打平集合中对象的某个类型为list的字段的值

6、字符串表示

(1)joinToString() 根据提供的参数从集合元素构建单个 String。

val numbers = listOf("one", "two", "three", "four")

println(numbers)

//[one, two, three, four]

println(numbers.joinToString())

//one, two, three, four

println(numbers.joinToString("-", "开始", "结束"))

//开始one-two-three-four结束

println(numbers.joinToString("-", "开始", "结束", 3))

//开始one-two-three-...结束

println(numbers.joinToString("-", "开始", "结束", 3, "等等"))

//开始one-two-three-等等结束

println(numbers.joinToString("-", "开始", "结束", 3, "等等", it -> it.toUpperCase() ))

//开始ONE-TWO-THREE-等等结束

(2)joinTo() 执行相同的操作,但将结果附加到给定的 Appendable (可追加的)对象。

val numbers = listOf("one", "two", "three", "four")

val listString = StringBuffer("The list of numbers: ")

numbers.joinTo(listString, "-", "开始", "结束", 3, "等等", it -> it.toUpperCase() )

println(listString)

//The list of numbers: 开始ONE-TWO-THREE-等等结束

7、过滤

(1)filter()。只能检查集合中元素的值。

val numbers = listOf("one", "two", "three", "four")

val longerThan3 = numbers.filter it.length > 3

println(longerThan3)

//[three, four]

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)

val filteredMap = numbersMap.filter (key, value) -> key.endsWith("1") && value > 10

println(filteredMap)

//key11=11

(2)filterIndexed()。可以检查元素的索引和元素的值。

val numbers = listOf("one", "two", "three", "four")

val filteredIdx = numbers.filterIndexed index, value -> (index != 0) && (value.length < 5)

println(filteredIdx)

//[two, four]

(3) filterNot()。使用否定条件来过滤集合。

val numbers = listOf("one", "two", "three", "four")

val filteredNot = numbers.filterNot it.length <= 3

println(filteredNot)

//[three, four]

(4)filterIsInstance<T>() 返回给定类型的集合元素。

val numbers = listOf(null, 1, "two", 3.0, "four")

println(numbers.filterIsInstance<String>())

//[two, four]

(5)filterNotNull() 返回所有的非空元素。在一个 List<T?> 上被调用时,filterNotNull() 返回一个 List<T: Any>。

val numbers = listOf(null, "one", "two", null)

println(numbers.filterNotNull())

//[one, two]

8、划分

partition() – 根据集合中元素的值进行过滤,并且返回一个Pair<List,List>。第一个list表示符合条件的集合;第二个list表示不符合条件的集合。

val numbers = listOf("one", "two", "three", "four")

val (match, rest) = numbers.partition it.length > 3

println(match)

//[three, four]

println(rest)

//[one, two]

9、集合元素检查

(1)

如果至少有一个元素匹配给定谓词,那么 any() 返回 true。

如果没有元素与给定谓词匹配,那么 none() 返回 true。

如果所有元素都匹配给定谓词,那么 all() 返回 true。注意,在一个空集合上调用 all() 始终都会返回 true 。

val numbers = listOf("one", "two", "three", "four")

println(numbers.any it.endsWith("e") )

//true

println(numbers.none it.endsWith("a") )

//true

println(numbers.all it.endsWith("e") )

//false

println(emptyList<Int>().all it > 5 )

//true

(2)当any() 和 none()不设置条件时, 它们只是用来检查集合是否为空。 如果集合中有元素(即使是null),any() 返回 true,否则返回 false;none() 则相反

10、集合加减:plus与minus

val numbers = listOf("one", "two", "three", "three", "four")

//集合加和,第二个操作数可以是集合,也可以是元素

val plusList = numbers + "five"

println(plusList)

//[one, two, three, three, four, five]

//如果第二个操作数是一个集合,那么移除其元素在原始集合中的 所有 出现。

val minusList1 = numbers - listOf("three")

println(minusList1)

//[one, two, four]

//如果第二个操作数是一个元素,那么 minus 移除其在原始集合中的 第一次 出现

val minusList2 = numbers - "three"

println(minusList2)

//[one, two, three, four]

11、分组

(1) groupBy()

val numbers = listOf("one", "two", "three", "four", "five")

//根据转换函数得到key,value来自于集合的元素

println(numbers.groupBy it.first().toUpperCase() )

//O=[one], T=[two, three], F=[four, five]

//根据转换函数得到key,value来自于对原有集合元素的转换结果

println(numbers.groupBy(keySelector = it.first() , valueTransform = it.toUpperCase() ))

//O=[one], T=[two, three], F=[four, five]

(2) grouping()

在分组后,对所有的分组进行一次操作。eachCount() 计算每个组中的元素。还有fold()、reduce()、aggregate()等。

val numbers = listOf("one", "two", "three", "four", "five", "six")

println(numbers.groupingBy it.first() .eachCount())

//o=1, t=2, f=2, s=1

12、取集合的一部分

(1)slice() 返回给定索引处的集合元素列表。

val numbers = listOf("one", "two", "three", "four", "five", "six")

println(numbers.slice(1..3))

//[two, three, four]

println(numbers.slice(0..4 step 2))

//[one, three, five]

println(numbers.slice(setOf(3, 5, 0)))

//[four, six, one]

(2)take和drop

val numbers = listOf("one", "two", "three", "four", "five", "six")

//从头开始获取指定数量的元素

println(numbers.take(3))

//[one, two, three]

//从尾部开始获取指定数量的元素

println(numbers.takeLast(3))

//[four, five, six]

//从头开始去除给定数量的元素

println(numbers.drop(1))

//[two, three, four, five, six]

//从尾部开始去除给定数量的元素

println(numbers.dropLast(5))

//[one]

(3)takeWhile()和dropWhile()

val numbers = listOf("one", "two", "three", "four", "five", "six")

//不停地获取元素,直到遇到使表达式为false的首个元素。如果首个集合元素便使表达式为false,则结果为空。

println(numbers.takeWhile !it.startsWith('f') )

//[one, two, three]

//从尾部开始,如上

println(numbers.takeLastWhile it != "three" )

//[four, five, six]

//不停地删除元素,直到遇到使表达式为false的首个元素,然后返回剩余的元素。如果首个集合元素便使表达式为false,则返回集合所有的元素。

println(numbers.dropWhile it.length == 3 )

//[three, four, five, six]

//从尾部开始,如上

println(numbers.dropLastWhile it.contains('i') )

//[one, two, three, four]

(4)chunked()

将集合分为指定大小的子集

val numbers = (0..13).toList()

println(numbers.chunked(3))

//[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13]]

val numbers = (0..13).toList()

//将集合切割成指定大小的子集后,对子集元素进行转换

println(numbers.chunked(3) it.sum() )

//[3, 12, 21, 30, 25]

(5)windowed()

val numbers = listOf("one", "two", "three", "four", "five")

//检索指定大小的所有可能子集

println(numbers.windowed(3))

//[[one, two, three], [two, three, four], [three, four, five]]

//设置步长

println(numbers.windowed(3, 2))

//[[one, two, three], [three, four, five]]

//partialWindows为true时,即使剩余的元素数量小于窗口长度,也会返回结果

println(numbers.windowed(3, 2, true))

//[[one, two, three], [three, four, five], [five]]

//对得到的所有子集进行转换

println(numbers.windowed(3, 2, true, list -> list.map it.toUpperCase() ))

//[[ONE, TWO, THREE], [THREE, FOUR, FIVE], [FIVE]]

(6)zipWithNext()

val numbers = listOf("one", "two", "three", "four", "five")

//从头开始,返回所有的相邻元素对(Pair)

println(numbers.zipWithNext())

//[(one, two), (two, three), (three, four), (four, five)]

//s1,s2即相邻元素对

println(numbers.zipWithNext s1, s2 -> s1.length > s2.length )

13、取单个元素

(1)elementAt()获取指定索引处的元素

val str = linkedSetOf("one", "two", "three", "four", "five").elementAt(3)

(2)elementAtOrNull()

val numbers = listOf("one", "two", "three", "four", "five")

//越界后返回null

println(numbers.elementAtOrNull(5))

//null

(3)elementAtOrElse()

val numbers = listOf("one", "two", "three", "four", "five")

//越界后返回lambda表达式的结果

println(numbers.elementAtOrElse(5) index -> "The value for index $index is undefined" )

//The value for index 5 is undefined

(4)first()和last()

first()和last()也可以根据表达式查找。但是如果没有查找到目标元素,将会抛出异常。用 firstOrNull() 和 lastOrNull()替代,如果没有找到,会返回null。

可以使用find() 代替 firstOrNull();使用 findLast() 代替 lastOrNull()

val numbers = listOf("one", "two", "three", "four", "five", "six")

println(numbers.first it.length > 3 )

//three

println(numbers.last it.startsWith("f") )

//five

(5) random()

随机返回一个元素。对于空集合会抛出异常。可以使用randomOrNull()替代,会返回null。

14、排序

(1)sortedWith(comparator: Comparator<in T>)

//compareBy()可根据给定的lambda表达式返回Comparator

println(listOf("aaa", "bb", "c").sortedWith(compareBy it.length ))

//[c, bb, aaa]

(2) sorted() 和 sortedDescending()

val numbers = listOf("one", "two", "three", "four")

//自然升序

println(numbers.sorted())

//[four, one, three, two]

//自然降序

println(numbers.sortedDescending())

//[two, three, one, four]

(3) sortedBy(lambda表达式) 和 sortedByDescending(lambda表达式)

val numbers = listOf("one", "two", "three", "four")

val sortedNumbers = numbers.sortedBy it.length

println(sortedNumbers)

//[one, two, four, three]

val sortedByLast = numbers.sortedByDescending it.last()

println(sortedByLast)

//[four, two, one, three]

(4)reversed()和asReversed()

var numbers = mutableListOf("one", "two", "three", "four")

//返回原有集合的倒序副本,且和原有集合没有关联

println(numbers.reversed())

//[four, three, two, one]

//返回原有集合的倒序视图,且和原有集合相关联。即改变原有的集合,已得到的倒序视图会发生改变。

val reversedNumbers = numbers.asReversed()

println(reversedNumbers)

//[four, three, two, one]

numbers.add("five")

println(reversedNumbers)

//[five, four, three, two, one]

(5)shuffled()

返回一个以随机顺序排列的含有原有集合元素的新list

val numbers = listOf("one", "two", "three", "four")

println(numbers.shuffled())

15、聚合

(1)聚合操作如min()、max()、average()、sum()这些都只是对于数字类型的集合可用。count()计算集合中元素数量。

minBy、maxBy接收一个表达式;minWith、maxWith接收一个Comparator对象,可以由compareBy产生。

sumBy、sumByDouble接收一个表达式。前者对int类型的元素求和,并返回int。后者对Double类型的元素求和,并返回Double。

(2)fold()和reduce()。以及OrNull版本。

val numbers = listOf(5, 1, 3, 2)

//第一步的两个操作数分别是集合中第一个和第二个元素。(则第一个元素无法乘以2)

println(numbers.reduce sum, element -> sum + element * 2 )

//17

//为sum设置了初始值。每一次的操作数都是sum和当前的集合元素。(可以保证每一个元素都乘以2)

println(numbers.fold(0) sum, element -> sum + element * 2 )

//22

(3) reduceRight() 和 foldRight()从尾部开始进行计算。以及OrNull版本。

(4)foldIndexed()和reduceIndexed()将元素索引作为参数进行操作。以及OrNull版本。

val numbers = listOf(5, 2, 10, 4)

println(numbers.foldIndexed(0) idx, sum, element -> if (idx % 2 == 0) sum + element else sum )

//15

println(numbers.reduceIndexed idx, sum, element -> if (idx % 2 == 0) sum + element else sum )

//15

(5)reduceRightIndexed() 与 foldRightIndexed()从尾部开始进行计算。以及OrNull版本。

16、List操作

(1)getOrElse()、getOrNull()

val numbers = listOf(1, 2, 3, 4)

//越界时,返回null

println(numbers.getOrNull(5))

//越界时,返回表达式的结果,it等于index

println(numbers.getOrElse(6, it ))

(2) indexOf() 返回元素第一个位置。 lastIndexOf() 返回元素最后一个位置。

(3)indexOfFirst() 和 indexOfLast() 可以接收一个表达式。

(4)二分查找 binarySearch()

要求该列表按照一定的顺序(自然排序或函数参数中提供的另一种排序)按升序排序过。

查询失败将返回 (-insertionPoint - 1),其中 insertionPoint 为应插入此元素的索引,以便列表保持排序。

如果存在多个目标元素返回其任一索引。

val numbers = mutableListOf("one", "two", "three", "four")

numbers.sort()

println(numbers)

//four, one, three, two]

println(numbers.binarySearch("two"))

// 3

println(numbers.binarySearch("z"))

// -5

println(numbers.binarySearch("two", 0, 2))

// -3

(5)通过Comparator使用二分查找

data class Product(val name: String, val price: Double)

val productList = listOf(

        Product("WebStorm", 49.0),

        Product("AppCode", 99.0),

        Product("DotTrace", 129.0),

        Product("ReSharper", 149.0))

println(productList.binarySearch(Product("AppCode", 99.0), compareBy<Product> it.price .thenBy it.name ))

(6)fill()将集合中所有元素更新为指定值

val numbers = mutableListOf(1, 2, 3, 4)

numbers.fill(3)

println(numbers)

//[3, 3, 3, 3]

17、set操作

(1)union()获取并集。对于有序集合,操作数顺序决定元素顺序。a union b

(2)intersect()获取交集。a intersect b

(3)subtract()获取差集。a subtract b 

18、map操作

filter()、filterKeys()、filterValues()

val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)

println(numbersMap.filter (key, value) -> key.endsWith("1") && value > 10 )

//key11=11

println(numbersMap.filterKeys it.endsWith("1") )

//key1=1, key11=11

println(numbersMap.filterValues it < 10 )

//key1=1, key2=2, key3=3

Kotlin学习与实践 fun 函数

通过例子来学习如何高效的在Kotlin中定义使用函数。

1、命名参数、默认参数、顶层函数、扩展函数

* 展示几种创建集合类的方法和扩展的简单操作集合类的方法
fun createCollection() {
    val set = hashSetOf(1, 12, 26)
    println("hashSetOf -- > ${set.javaClass}")
    val list = arrayListOf(12, 24, 66)
    println("arrayListOf -- > ${list.javaClass}")
    val map = hashMapOf(1 to "one", 2 to "two", 3 to "three")
    println("hashMapOf -- > ${map.javaClass}")

    val list1 = listOf("dsa", "ccc", "ddd")
    println("listOf -- > ${list1.javaClass}")
}


fun easyOptCollection() {
    val strings = listOf("ss", "this", "is", "string ArrayList")
    println(strings.last())

    val numbers = listOf(1, 200, 20, 30)
    println(numbers.max())
}

  Kotlin并没有采用它自己的集合类,而是采用标准的Java集合类,这样Kotlin就能与Java交互。

 

再看一个示例:

fun demand() {
    val list = listOf(1, 2, 25)
    println(list)
}
* 上面函数直接输入 list 是调用了集合的默认的toString方法,为了动态修改输入的样子,下面的几个函数是
* 自己的扩展,再扩展中探讨如何让Kotlin 的方法更简单 更高效 更舒服

下面首先按照Java的习惯和风格定义一个自定义格式化输出集合的方法
/**
 * 通过再元素中间加分隔符,在最前面加前缀,再最后面加后缀把集合转成可输出的String
 * @param collection  集合
 * @param separator 分隔符
 * @param prefix 前缀
 * @param postfix 后缀
 */
fun <T> joinToString(collection: Collection<T>,
                     separator: String,
                     prefix: String,
                     postfix: String): String {
    val result = StringBuilder(prefix)
    for ((index, element) in collection.withIndex()) {
        if (index > 0) result.append(separator) //第一个元素之前不用加分隔符
        result.append(element)
    }
    result.append(postfix)
    return result.toString()
}

 

* 为了提高代码的可读性
* Kotlin支持 命名参数 --> 调用函数时 显式地指定参数名称 (牛叉的是:显示指定名称之后就可以打乱参数的传递顺序了)
* 注意:为了避免混淆指明了一个参数的名称之后,后面的参数必须都要标明名称
* 警告:使用Kotlin 调用Java函数时,不能采用命名参数
fun callExplicitly() {
    val list = listOf(1, 3, 5)
    println(joinToString(list, prefix = "{", separator = "\\", postfix = "}"))
}

 

* 为了避免像Java那样过多的重载与重复
* Kotlin 支持默认参数值 --> 在声明函数的时候,指定参数的默认值,在调用的时候不传该参数时就使用默认的参数
* 这样就可以避免创建很多的重载函数
*
* Java中如果想调用指定默认参数的函数必须全部传递参数,如果想像在Kotlin中一样使用其省略参数的调用方式就需要给
* Kotlin中声明的 指定默认参数的函数 添加“@JvmOverloads”注解,原理是编译器会带有"@JvmOverloads"的方法自动生成重载函数
@JvmOverloads
fun <T> joinToStringWithDefaultParams(collection: Collection<T>,
                                      separator: String = ",",
                                      prefix: String = "",
                                      postfix: String = ""): String {
    return joinToString(collection, separator = separator, prefix = prefix, postfix = postfix)
}

fun callWithDefaultParams() {
    val list = listOf(1, 3, 5)
    println(joinToStringWithDefaultParams(list))
    println(joinToStringWithDefaultParams(list, "-"))
    println(joinToStringWithDefaultParams(list, "-", "【", "】"))
    println(joinToStringWithDefaultParams(list, postfix = "!"))
}

  

在Java 中一些无法从属任何类又可能会被很多类频繁的调用的方法通常会抽取到专门的一个类中,以 public static final sss()最终会形成包含很多这种方法的工具类

* 在Kotlin中根本不需要去创建这样无意义的类。
* 可以把这样的不从属于任何类的函数放到代码文件的顶层,这些放在文件顶层的函数依然是包内的成员
* 如果要从外部访问它,直接导入包就可以用,不要额外包一层类名
*
* 其实编译器会.kt 文件编译成Java类,类名为.kt文件名+Kt 例如:join.kt ---> JoinKt.class
* 因此在Java中调用顶层函数也很简单直接导入编译的包含顶层文件的类就行了
*
* 如果要改变包含Kotlin 顶层函数的文件被编译生成的类名,需要为这个文件添加 “@JvmName”的注解,将其放到文件的开头,位于包名的前面
* 比如本类执行的名称“@file:JvmName("StringsFunctions")”
import com.mauiie.kotlin.chapter2fun.K4ExtendPropertyKt;
import com.mauiie.kotlin.chapter2fun.StringsFunctions;

public class JavaCallTest { public static void main(String[] args) { ArrayList<String> strings = new ArrayList<>(5); strings.add("dsada"); strings.add("adsa"); strings.add("jklj"); strings.add("dsada"); System.out.println(StringsFunctions.joinToStringWithDefaultParams(strings)); TopFunAndProperty.performOperation(); TopFunAndProperty.performOperation(); TopFunAndProperty.reportOperationCount(); System.out.println(TopFunAndProperty.getUNIX_LINE_SEPARATOR()); System.out.println(TopFunAndProperty.UNIX_LINE_SEPARATOR_CONSTANTS); System.out.println(TopFunAndProperty.getOpCount()); System.out.println(K3ExtendFunAndPropertyKt.lastChar_("this is a")); /** * 扩展函数和扩展方法在Java中调用的时候都必须显示的调用 */ String testStr = "test"; System.out.println(K4ExtendPropertyKt.getLastChar(testStr)); System.out.println(K4ExtendPropertyKt.lastChar(testStr)); Button button = new Button(); System.out.println(button.getCurrentState()); ; }

  

* 在使用JDK、Android的时候,有时会面临代码不能转成Kotlin的时候,Kotlin支持扩展函数让Kotlin支持不能转的代码
* 理论上来说扩展函数非常简单,它就是一个类的成员函数,不过定义在类的外面。
* 做法很简单:把要扩展的类或接口的名称,放到即将添加的函数前面。

* 这个类的名称叫 “接收者类型”;用来调用这个扩展函数的那个对象叫做“接收者对象”
* 接收者类型 是由扩展函数定义的,接收者对象是该类型的一个实例
fun String.lastChar_(): Char = this.get(this.length - 1)
* String 是定义的接收者类型
* this 是定义的接收这对象 也就是String的一个实例
* 在扩展函数中,可以像其他成员函数一样访问类的其他变量和属性,就好像是在这个类自己的方法中访问他们一样。
* 注意:扩展函数不能打破类的封装性。???????
* 和类的成员变量不同的是,扩展函数不能访问类的私有或者受保护的成员。

* 在扩展函数中,可以像其他成员函数一样使用“this”,而且也可以像其他成员函数一样省略它
fun String.easyLastChar(): Char = get(length - 1)

fun main(args: Array<String>) {
    //定义好扩展函数之后就可以像普通的成员函数一样去使用了
    println("kotlin".lastChar_())
    println("test".easyLastChar())
}

  

*  在Kotlin中,重写成员函数是很平常的事情,但是,不能重写扩展函数。
* 但是,但是, 不能重写扩展函数
* 扩展函数并不是类的一部分,它是声明在类之外的。尽管可以给基类和子类都分别定义一个同名的扩展函数,当这个函数被调用时
* 它是由该变量的静态类型所决定的,而不是这个变量的运行时类型

* 注意 如果一个类的成员函数和扩展函数有相同的签名,成员函数往往会被优先使用。
* 记住: 如果添加一个和扩展函数一样名字的成员函数,那么对应类定义的消费者将会重新编译代码,这将会改变它的意义开始指向新的成员函数!
open class View {
    open fun click() = println("View clicked")
}
class Button : View() {
    override fun click() = println("Button clicked")
}

fun View.showOff() = println("View showOff")
fun Button.showOff() = println("Button showOff")

fun main(args: Array<String>) {
    val v: View = Button()
    val v2: View = View()
    val v3 = View()
    //具体调用哪个方法是由view的实际值来决定的,
    v.click()
    v2.click()
    v3.click()
    //但是, 不能重写扩展函数
    v.showOff()
    v2.showOff()
    v3.showOff()

    val button = Button()
    button.showOff()
}

  执行结果:

Button clicked
View clicked
View clicked
View showOff
View showOff
View showOff
Button showOff

Kotlin中直接在文件函数叫做顶层的函数,再Kotlin中看起来不从属任何类从属于包直接导入可以使用,但是从编译之后的字节码看会自动编译xxxKT.Java,顶层函数从属于编译的文件类

@file:JvmName("TopFunAndProperty")
package com.mauiie.kotlin.chapter2fun

/** * 这样就声明了一个顶层属性 */ var opCount = 0 //会生成getter和setter /** * 声明一个顶层函数 */ fun performOperation() { opCount++ } fun reportOperationCount() { println("Operation performed $opCount times ") } val UNIX_LINE_SEPARATOR = "\n" //只会生成getter const val UNIX_LINE_SEPARATOR_CONSTANTS = "\n" //相当于Java中的 public static final String ...l /** * 现在我们可以将joinToString 函数写出终极状态了 ---> 作为扩展函数的工具函数 */ fun <T> Collection<T>.joinToString( separator: String, prefix: String, postfix: String ): String { val result = StringBuilder(prefix) // withIndex 省去了this this.withIndex() for ((index, element) in withIndex()) { if (index > 0) result.append(separator) result.append(element) } result.append(postfix) return result.toString() }

  2、扩展属性

* 扩展属性提供了一种方法,用来扩展类的API,可以用类访问属性,用的是属性语法而不是函数的语法。
* 尽管它被称为属性,但是他们可以没有任何状态,因为没有适合的地方来存储它,不可能给现有的Java对象实例添加额外的字段。
* 但有时段语法仍然是便于使用的。

先扔出来一个扩展函数
fun String.lastChar(): Char = get(length - 1)
* 上面是为String 扩展的方法 lastChar() 现在把它转成属性试试
* 可以看到扩展属性也像接收者的一个普通成员属性一样。
* 这里,必须定义getter函数,因为没有支持字段,因此没有默认的getter实现。
* 同理,初始化也不可以:因为没有地方可以存储初始值
val String.lastChar: Char
    get() = get(length - 1)


var StringBuilder.lastChar: Char
    get() = get(length - 1)
    set(value: Char) {
        this.setCharAt(length - 1, value)
    }

fun main(args: Array<String>) {
    println("Kotlin".lastChar)

    val sb: StringBuilder = StringBuilder("Kotlin")
    sb.lastChar = ‘a‘
    println(sb.lastChar)
}

 注意 

* 如果要从Java中访问扩展属性,应该显示地调用它的getter函数  K4ExtendPropertyKt.getLastChar("Java")

 *对于定义的扩展函数,不会自动在整个项目中生效,使用的时候需要像其他函数和类一样导入
* 可以使用 as 关键字来修改导入的类或者名称 同样在Java也可以使用定义好的扩展函数 参照 java.JavaCallKotlin
package com.mauiie.kotlin.chapter2fun

//import com.mauiie.kotlin.chapter2fun.*
import com.mauiie.kotlin.chapter2fun.lastChar_ as last

val c = "Kotlin".last()

 3、可变参数、中缀表示、解构声明

* a.可变参数的关键字 vararg,可以用来声明一个函数可能有任意数量的参数
* b.一个中缀表示法,当你在调用一些只有一个参数的函数时,使用它会让代码更简练
* c.解构声明,用来把一个单独的组合值展开到多个变量中

首先看可变参数 vararg的使用:
fun kebiancanshu() {
    val list = listOf(1, 45, 36)
   //listOf源码 //public fun <T> listOf(vararg elements: T): List<T> = if (elements.size > 0) elements.asList() else emptyList() }
* 上面可以看在Kotlin使用了 vararg 代替了 Java中的... 声明了可变参数
* 与Java不用的一点是如果在传入参数是已经包装在数组中的参数时,在Java中会原样传递数组,而Kotlin则要求你显示着解包数组,以便于每个数组元素能作为单独的参数来调用
* 从技术角度讲这个功能被称为"展开运算符",而在使用的时候不过是在参数前面放一个 “*”
fun testVararg(args: Array<String>) {
    val list = listOf("test", * args)
    println(list)
}

fun main(args: Array<String>) {
    testVararg(listOf("ds", "dsa", "111").toTypedArray())  //toTypedArray Returns a *typed* array containing all of the elements of this collection.
}

  

* 声明map的代码中的to,不是内置解构,而是一种特殊函数调用,被称为中缀调用。
* 在中缀调用中,没有添加额外的分隔符,函数名称是直接放在目标对象名称参数之间的。
* 1 to "one" 和 1.to("one")是等价的
fun testMap() {
    val map = mapOf(1 to "one", 2 to "two", 3.to("three"))
// 源码   public fun <K, V> mapOf(vararg pairs: Pair<K, V>): Map<K, V> = if (pairs.size > 0) pairs.toMap(LinkedHashMap(mapCapacity(pairs.size))) else emptyMap()

    val list = listOf(1.45)
    //这也是一种解构声明
    for ((index, element) in list.withIndex()) {
        println("this $index is $element")
    }
}

 

* 中缀调用可以与之哟普一个参数的参数的函数一起使用,无论是普通的函数还是扩展函数。
* 要允许使用中缀符号调用函数,需要使用infix修饰符来标记它。
* 下面是一个简单的to函数的声明

* Pair 是Kotlin标准库中的类,它表示已对元素。Pair和to 都使用了泛型,这里为了简单都省略了他们
infix fun Any.to(other: Any) = Pair(this, other)

fun testPair() {
    val (number, name) = 1 to "one"
    println("this is $number and $name")
}

 

4、局部函数

为了让代码更简洁,Kotlin提供了局部函数的功能:
* 局部函数指的是 可以在函数中嵌套这些提取的函数,这样既可以获得所需的结构,也无须额外的语法开销

先看下一个简单的例子,稍后使用局部函数改造,体验局部函数:
class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User) {
    if (user.name.isEmpty()) {
        throw IllegalArgumentException("Can‘t save user[${user.id}] with empty name")
    }
    if (user.address.isEmpty()) {
        throw IllegalArgumentException("Can‘t save user[${user.id}] with empty address")
    }
    println("save user successful!")
}
* 提取局部函数避免重复
fun saveUser1(user: User) {
    fun validate(user: User, value: String, fieldName: String) {
        if (value.isEmpty()) {
            throw IllegalArgumentException("Can‘t save user[${user.id}] with empty $fieldName ")
        }
    }
    validate(user, user.name, "Name")
    validate(user, user.address, "address")
    println("save user successful!")
}
* 可以在局部函数总直接访问外部函数的参数!!
fun saveUser2(user: User) {
    fun validate(value: String, fieldName: String) {
        if (value.isEmpty()) {
            //可以在局部函数总直接访问外部函数的参数!!
            throw IllegalArgumentException("Can‘t save user[${user.id}] with empty $fieldName ")
        }
    }
    validate(user.name, "Name")
    validate(user.address, "address")
    println("save user successful!")
} 
* 提取逻辑到扩展函数
fun User.validateBeforSave() {
    fun validate(value: String, fieldName: String) {
        if (value.isEmpty()) {
            throw IllegalArgumentException("Can‘t save user[${this.id}] with empty $fieldName ")
        }
    }
    validate(name, "Name")
    validate(address, "Address")
}

  



 

以上是关于kotlin集合高效使用的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin学习与实践 fun 函数

Kotlin——集合

Kotlin——数组

每天学一点 Kotlin -- 集合:Array 数组

Kotlin常用Collection集合操作整理

Kotlin 协程真的比 Java 线程更高效吗?