Kotlin实用小技巧

236 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情

reified

项目中我们经常遇到将一个list的Json字符串转换成List对象,每次传写object : TypeToken<ArrayList<T>>(){}.type,确实有点繁琐,我们可以定义一个扩展函数

fun <T> String.toTypedArray():ArrayList<T>{
    return Gson().fromJson(this, object : TypeToken<ArrayList<T>>() {}.type)
}

这样就可以直接json.toTypedArray()获取转换的结果

val users = mutableListOf<User>()
users.add(User("张三",20))
users.add(User("李四",21))
val array = Gson().toJson(users).toTypedArray<User>()

运行之后会发现并没有那么简单,最后List里面存的不是我们需要的User对象,而是LinkedTreeMap,

微信图片_20220417222506.png

这是由于Java泛型在运行时会被类型擦除,如何解决这个问题呢?就需要用到reified

reified是kotlin提供的一个关键字,意在具体化泛型,它必须结合inline使用。因为内联函数在编译期间会吧字节码拷贝到调用它的地方,所以编译器就会知道当前方法中的泛型对应的具体类型是什么,修改下扩展函数

inline fun <reified T> String.toTypedArray():ArrayList<T>{
    return Gson().fromJson(this, object : TypeToken<ArrayList<T>>() {}.type)
}

这时候在调用数据就正常了

微信截图_20220417223524.png

Sequences

在项目中,我们经常会对数据集进行处理,对于List,kotlin给我们提供了很多方便的api,比如filter,map等, 这些操作符的实现也比较简单

public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
    return filterTo(ArrayList<T>(), predicate)
}
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

可以看到,无论是filter还是map,他们都使通过创建一个新的ArrayList用来接受符合结果的数据,然后返回这个新的列表,这意味着调用一次这些api就会创建新的对象,如果在同一时间大量调用的话,就会引起内存暴涨,频繁GC,所以kotlin提供了序列(Sequences)来优化集合(List)在一些场景的缺陷。 Sequences操作被称之为惰性操作,因为他的中间操作不会创建临时对象,而是返回一个序列(Sequences),只有执行到末端操作的时候才会进行计算

判断一个操作符是不是末端操作符也很简单,看返回值是不是一个序列就可以了,如果是的话就说明这个操作符是中间操作符,否则就是末端操作符。

集合转序列很简单,直接调用asSequencef()方法就可以了,操作用到的api也和集合类似。

//集合
val count1 = users
    .filter { it.age > 0 }
    .map { "${it.name} ${it.age}" }
    .count()
//序列
val count2 = users.asSequence()
    .filter { it.age > 0 }
    .map { "${it.name} ${it.age}" }
    .count()