Kotlin的高阶函数与泛型
来一个demo:带返回函数的函数
data class Person (
val firstName :String,
val lastName :String,
val phoneNumber:String?
)
class ContactListFilters{
var prefix:String=""
var onlyWithNumber:Boolean=false
fun getPredicate():(Person) -> Boolean{
val startsWithPrefix={
p: Person ->
p.firstName.startsWith(prefix)||p.lastName.startsWith(prefix)
}
if (!onlyWithNumber){
return startsWithPrefix
}
return {
startsWithPrefix(it) && it.phoneNumber!=null
}
}
}
fun main(args: Array<String>) {
val contacts= listOf(Person("dsfd","ddfs","112233"),
Person("kjk","wqrre","65644"),
Person("awqq","pioi",null)
)
val contactListFilters=ContactListFilters()
with(contactListFilters){
prefix="kj"
onlyWithNumber=true
}
println(contacts.filter(
contactListFilters.getPredicate()
))
}
Lambda筛选demo
/**
*
* @author ll
* @Description:记录站点数据
* @date Created in 2018/04/07 09:55 AM
*/
data class SiteVisit (
val path:String,//路径
val duration:Double,//访问时长
val os:OS //系统
)
enum class OS{
WINDOWS,LINUX,MAC,IOS,ANDROID
}
计算Windows时间
val log= listOf(
SiteVisit("/",34.0,OS.WINDOWS),
SiteVisit("/dfdf",22.0,OS.MAC),
SiteVisit("/dfgg",12.0,OS.WINDOWS),
SiteVisit("/ryyy",8.0,OS.IOS),
SiteVisit("/wtyty",16.3,OS.ANDROID)
)
//Windows平均访问时间
val avgWindows=log
.filter { it.os==OS.WINDOWS }
.map (SiteVisit::duration )
.average()
println(avgWindows)
抽取公共函数:
fun List<SiteVisit>.avgDurationFor(os:OS)=
filter { it.os==os }
.map (SiteVisit::duration)
.average()
//Windows
println(log.avgDurationFor(OS.WINDOWS))
只要移动平台(Android 和 IOS数据)
val avgMobilePlatform=log
.filter { it.os in setOf(OS.IOS,OS.ANDROID) }
.map (SiteVisit::duration)
.average()
println(avgMobilePlatform)
显然需要更新公共函数了
fun List<SiteVisit>.avgDuration(predicate: (SiteVisit) -> Boolean)=
filter(predicate)
.map(SiteVisit::duration)
.average()
测试:
//Windows
println(log.avgDuration { it.os==OS.WINDOWS })
//mobile platform
println(log.avgDuration { it.os==OS.IOS || it.os ==OS.ANDROID })
println(log.avgDuration { it.os==OS.IOS && it.path =="/ryyy" })
内联函数inline:消除lambda的开销
inline fun<T> synchronized(lock: Lock, action:() ->T) :T{
lock.lock()
try {
return action()
} finally {
lock.unlock()
}
}
fun foo(l:Lock){
println("before sync")
synchronized(l){
println("Action")
}
println("after action")
}
/**
*函数类型做参数,不是lambda,inline失效
*/
class LockOwner(val lock:Lock){
fun runUnderLock(body:() ->Unit){
synchronized(lock,body)
}
}
class LockOwner2(val lock:Lock){
fun _runUnderLock_(body: () -> Unit){
lock.lock()
try {
body()
} finally {
lock.unlock()
}
}
}
kotlin中,filter,map函数被声明为内联函数。当出现大量数据处理时,可以通过 在链式后加asSequence(),用序列代替集合,但kotlin建议在处理大数据时用。
inline只能提高带有lambda参数的函数的性能.
java中try-with-resources在kotlin中的替代。
//java代码
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader bufferedReader=new BufferedReader(new FileReader(path))){
return bufferedReader.readLine();
}
}
//kotlin中使用use代替,use在kotlin中是内联函数
fun readFirstLineFromFile(path:String):String{
BufferedReader(FileReader(path)).use {
br -> return br.readLine()
}
}
lambda中的返回语句
data class Person2(val name: String ,val age:Int)
fun lookFofJim(people :List<Person2>){
for (person in people){
if (person.name=="Jim") {
println("找到了")
return
}
}
println("jim 没找到")
}
fun main(args: Array<String>) {
val people= listOf(Person2("fdaaf",34), Person2("trrt",73))
lookFofJim(people)
}
forEach依旧适用
people.forEach {
if (it.name=="Jim") {
println("找到了")
return
}
}
引入便签局部返回:@一定要有,边签名任意
fun lookFofJim2(people :List<Person2>){
people.forEach label@{
if (it.name=="Jim") {
println("找到了")
return@label
}
}
//总会执行
println("jim ...")
}
函数名也可以作为标签
fun lookFofJim(people :List<Person2>){
/* for (person in people){
if (person.name=="Jim") {
println("找到了")
return
}
}
*/
people.forEach {
if (it.name=="Jim") {
println("找到了")
return@forEach
}
}
println("jim 没找到")
}
注意,当匿名函数中有return时,返回最近的匿名函数
fun lookFofJim3(people :List<Person2>){
people.forEach(fun(person) {
if (person.name=="trrt") {
println("找到了")
return
}
})
//总会执行
println("jim ...")
}
此时return是从fun(person)返回。
泛型:Kotlin泛型要求类型实参被显示地说明,或者能被编译器推导出来。
fun <T : Number> oneHalf(value :T) :Double{
return value.toDouble()/2.0
}
val nums= oneHalf(65.32)
println(nums)
fun <T: Comparable<T>> max (first:T,second:T):T{
return if (first>second) first else second
// return if (first.compareTo(second)>0) first else second
}
println(max(23,546))
参数约定:
fun<T> ensureTrailingPeriod(seq:T) where T:CharSequence,T:Appendable{
if(!seq.endsWith('.')){
seq.append('.')
}
}
val hello=StringBuilder("fafd fafddadf hello")
ensureTrailingPeriod(hello)
println(hello)
形参可空
class Processor<T> {
fun process(value :T){
value?.hashCode()
}
}
val nullProcess=Processor<String?>()
nullProcess.process(null)
Any代替Any?形参非空
class Processor2<T : Any>{
fun process(value : T){
value.hashCode()
}
}
声明带实例化参数的函数
inline fun <reified T> isA(value: Any) =value is T
println(isA<String>("ffdafadfadfadfadfd"))
结果:true
标准库函数:filterIsInstance
val items= listOf("faafd","fdf",122,"fddf1","113423")
println(items.filterIsInstance<String>())
关于reified。带reified类型参数的inline函数不能再java中调用。普通的inline可以被调用,但不能被内联。
filterIsInstances被标记为inline,但它并不期望lambda作为实参 。
目前,还不能把类,属性和非内联函数的类型参数标记为reified。当lambda因为性能被内联时,可以使用noinline标记。
.
inline fun<reified T : Activity> Context.startActivity(){
val intent= Intent(this,T::class.java)
startActivity(intent)
}
Handler().postDelayed({
startActivity<MainActivity>()
},3000)
一个编译器通过不了的demo
fun addAnswer(list: MutableList<Any>){
list.add(43)
}
val strings= mutableListOf("adf","dfadf")
addAnswer(strings)
kotlin中List是只读集合
超类型概念:A是B的子类型,那么B就是A的超类型。
非空类型A是可空类型A?的子类型,但反过来不是。
不变型:对于任意类型A和B,MutableList<A>既不是MutableList<B>的子类型,也不是超类型,它就被称为该类型参数是不变型的。
协变:如果A是B的子类型,那么List<A>是List<B>的子类型,这样的类或者接口被称为协变。声明协变用out关键字。
逆变:反转子类型化关系。in关键字。
interface Produce<out T>{
fun produce():T
}
interface Function1<in p,out R>{
operator fun invoke(p:p) :R
}