Kotlin学习笔记(Kotlin编程实战)
编译命令行
- kotlinc-jvm -d d.jar XX.kt
- java -jar d.jar
- kotlinc-jvm XX.kt
- javap -p XX.class
- javap -c XX.class
- kotlinc-jvm -classpath d.jar -script aa.kts
参考
协程
- 异步
- 并发
- 同时进行,但可能时间片不同
- 并行
- 同时进行,时间片也相同,在不同的cpu核上.
- 并发
在脚本中使用协程
#!/usr/bin/env kotlinc-jvm -classpath "/opt/kotlin-learn/kotlinx-coroutines-core-1.2.2.jar" -script
import kotlinx.coroutines.*
jar包的地址需要使用绝对地址,这样脚本才能找到相应的jar包
import kotlin.system.measureTimeMillis
import kotlinx.coroutines.*
println("sync")
// suspend ,launch ,withContext
suspend fun task1() {
println("start task1 in Thread ${Thread.currentThread()}")
yield()
println("end task1 in Thread ${Thread.currentThread()}")
}
suspend fun task2() {
println("start task2 in Thread ${Thread.currentThread()}")
yield()
println("end task2 in Thread ${Thread.currentThread()}")
}
GlobalScope.launch {
withContext(Dispatchers.IO) {
delay(100)
task1()
}
println("call task1 in Thread ${Thread.currentThread()}")
}
GlobalScope.launch(Dispatchers.Default) {
task2()
println("call task2 in Thread ${Thread.currentThread()}")
}
//async And await
GlobalScope.launch {
val count = async(Dispatchers.IO) {
println("fetching in ${Thread.currentThread()}")
Runtime.getRuntime().availableProcessors()
}
println("Called the function in ${Thread.currentThread()}")
println("Number of cores is ${count.await()}")
}
递归和记忆
- 递归
- 尾递归
- 记忆,Compose中的remember应该用的就是这个
//递归
fun fast_sort(numbers:List<Int>) :List<Int> {
if(numbers.isEmpty()) {
return numbers
}else {
val first = numbers.first()
val tail = numbers.drop(1)
val lessAndEq = tail.filter { it -> it <= first }
val more =tail.filter{it -> it > first }
// println(lessAndEq)
// println(more)
return fast_sort(lessAndEq)+first+fast_sort(more)
}
}
println(fast_sort(listOf(3,8,20,9,6,30)))
println(listOf(1,2,3,4)+listOf(4,5,6))
//尾递归
tailrec fun factorialRec(n:Int) :BigInteger = if(n <= 0) 1.toBigInteger() else n.toBigInteger()*factorialRec(n-1)
println(factorialRec(5000))
println(factorialIterative(50000))
fun factorialIterative(n:Int) = (1..n).fold(BigInteger("1")) { result,e -> result*e.toBigInteger()}
println(factorialIterative(5000))
println(factorialIterative(50000))
//记忆
fun fib(n:Int):Long {
println(n)
return when(n) {
0,1 -> 1
else -> fib(n-1)+fib(n-2)
}
}
println(fib(5))
// println(fib(40))
// println(fib(45))
// println(measureTimeMillis { fib(40)})
// println(measureTimeMillis { fib(45)})
// println(measureTimeMillis { fib(100)})
fun <T,R> ((T)->R).memoize():((T)->R) {
val original = this
val cache = mutableMapOf<T,R>()
val result = {n:T -> cache.getOrPut(n) {original(n)}}
// println(result)
return result
}
lateinit var fib2:(Int)->Long
fib2 = { n:Int ->
when(n) {
0,1 -> 1L
else -> fib2(n-1)+fib2(n-2)
}
}.memoize()
println(fib2(40))
println( fib2(45))
println( fib2(145))
println(measureTimeMillis { fib2(40)})
println(measureTimeMillis { fib2(45)})
println(measureTimeMillis { fib2(145)})
class Memoize<T,R>(val func:(T) -> R) {
val cache = mutableMapOf<T,R>()
operator fun getValue(thisRef:Any?,property:KProperty<*>) = { n:T ->
cache.getOrPut(n) { func(n) }
}
}
val fib3:(Int) -> Long by Memoize { n:Int ->
when(n) {
0,1->1L
else -> fib3(n-1)+fib3(n-2)
}
}
//钢条切割问题
val prices = mapOf(1 to 2,2 to 4,3 to 6,4 to 7,5 to 10,6 to 17, 7 to 17)
val maxPrice:(Int)->Int by Memoize { length:Int ->
val priceAtLength = prices.getOrDefault(length,0)
(1 until length).fold(priceAtLength) { max,cutLength ->
val cutPrice = maxPrice(cutLength)+maxPrice( length - cutLength)
Math.max(cutPrice,max)
}
}
for(i in 1..7) {
println("For length $i max price is ${maxPrice(i)}")
}
Kotlin DSL
infix fun Int.days(timing:Tense) = DateUtil(this,timing)
enum class Tense {
ago,from_now
}
class DateUtil(val number:Int,val tense:Tense) {
override fun toString():String {
val today = Calendar.getInstance()
when(tense) {
Tense.ago -> today.add(Calendar.DAY_OF_MONTH,-number)
Tense.from_now -> today.add(Calendar.DAY_OF_MONTH,number)
else -> {}
}
return today.getTime().toString()
}
}
println(2 days Tense.ago)
println(3 days Tense.from_now)
//带有方法的DSL
class Meeting(val title:String) {
var startTime = ""
var endTime = ""
val start = this
val end = this
private fun convertToString(time:Double) = String.format("%.02f",time)
infix fun at(time:Double) {
startTime = convertToString(time)
}
infix fun by(time:Double) {
endTime = convertToString(time)
}
override fun toString() = "$title Meeting starts $startTime ends $endTime"
}
infix fun String.meeting(block:Meeting.() -> Unit) {
val meeting = Meeting(this)
meeting.block()
println(meeting)
}
"Release Planning" meeting {
start at 14.30
end by 15.20
println("With in lambda: $this")
}
//xml解析器
@DslMarker
annotation class XMLMarker
fun xml(block:XMLBuilder.()->Node):Node = XMLBuilder().run(block)
@XMLMarker
class XMLBuilder {
fun root(rootElementName:String,block:Node.()->Unit):Node = Node(rootElementName).apply(block)
}
@XMLMarker
class Node(val name:String) {
var attributes:Map<String,String> = mutableMapOf()
var children:List<Node> = listOf()
var textValue:String = ""
fun text(value:String) { textValue = value }
fun element(childName:String, vararg attributeValues:Pair<String,String>, block:Node.() -> Unit):Node {
val child = Node(childName)
attributeValues.forEach {
child.attributes+=it
}
children +=child
return child.apply(block)
}
fun toString(indentation:Int) :String {
val attributesValues = if(attributes.isEmpty()) "" else attributes.map {
"${it.key}='${it.value}'"}.joinToString(" "," ")
val DEPTH = 2
val indent = " ".repeat(indentation)
return if(!textValue.isEmpty()) "$indent<$name$attributesValues>$textValue</$name>"
else
"""$indent<$name$attributesValues>
|${children.joinToString("\n") { it.toString(indentation + DEPTH)}}
|$indent</$name>""".trimMargin()
}
override fun toString() = this.toString(0)
}
val langsAndAuthors = mapOf("JavaScript" to "Eich","Java" to "Gosling","Ruby" to "Matz")
val xmlString = xml {
root("languages") {
langsAndAuthors.forEach { name,author ->
element("language","name" to name) {
element("author") {
text(author)
// this@xml.root("hahahaha"){}
}
}
}
}
}
println(xmlString)
Kotlin其他特性
- 操作符重写
- 扩展方法
- 扩展属性
- 中缀操作符
- 只能一个参数
- 不能使用vararg
- 常用的lambda
- let
- run
- also
- apply
- 使用特点
- □所有四个方法都执行传给它们的lambda。
- □let()和run()执行lambda,并将lambda的结果返回给调用方。
- □also()和apply()忽略lambda的结果,而是将context对象返回给它们的调用方。
- □run()和apply()在调用它们的context对象的上下文this的执行过程中运行lambda。
操作符重写
operator fun String.times(n:Int):String {
var r = this
repeat(n) {
r+=this
}
return r
}
println("message "*10)
支持的操作符
+x x.unaryPlus()
-x x.unaryMinus()
!x x.not()
x+y x.plus(y)
x-y x.minus(y)
x*y x.times(y)
x/y x.div(y)
x%y x.rem(y)
++y x.inc()
--x x.dec()
x==y x.equals(y)
x!=y !(x.equals(y))
x<y x.compareTo(y)
x[i] x.get(i)
x[i]=y x.set(i,y)
y in x x.contains(y)
x..y x.rangeTo(y)
x() x.invoke()
x(y) x.invoke(y)
扩展方法
data class Point(val x:Int,val y:Int)
data class Circle(val cx:Int,val cy:Int,val radius:Int)
//扩展方法+操作符重写
operator fun Circle.contains(point:Point):Boolean {
return (point.x - cx) * (point.x - cx) + (point.y -cy)*(point.y - cy) < radius*radius
}
val circle = Circle(100,100,24)
val point1 = Point(110,100)
println(circle.contains(point1))
println(point1 in circle)
//扩展属性
val Circle.area :Double
get() = kotlin.math.PI * radius * radius
println(circle.area)
for(word in 1..10) {
println(word)
}
operator fun ClosedRange<String>.iterator() = object:Iterator<String> {
private var next = start
private val last = endInclusive
override fun hasNext():Boolean {
println("last[0]:${last[0]},next[0]:${next[0]}")
return last[0]>next[0]
}
override fun next():String {
println("next:$next,last:$last")
val b = (next[0]+1).toString()
next = b
return b
}
}
for(word in "a".."z") {
println(word)
}
//类内注入扩展函数
data class Point(val x:Int,val y:Int) {
val pair = Pair(x,y)
private val firstSign = if(pair.first < 0) "" else "+"
private val secondSign = if(pair.second < 0) "" else "+"
override fun toString() = pair.point2String()
//两个this的使用
fun Pair<Int,Int>.point2String() = "(${firstSign}${first}, ${this@Point.secondSign}${this.second})"
}
val p = Point(10,-10)
println(p)
//我们的高级函数g(f(x))
fun <T,U,R> ((T)->U).andThen(next:(U)->R):(T)->R = { input:T -> next(this(input))}
fun increment(number:Int):Double = number+1.toDouble()
fun double(number:Double) = number*2
val incrementAndDouble = ::increment.andThen(::double)
println(incrementAndDouble(5))
// 中缀操作符
infix fun Circle.sameCenterPoint(circle:Circle):Boolean {
return this.cx == circle.cx && this.cy == circle.cy
}
val c1 = Circle(100,100,300)
val c2 = Circle(100,100,40)
println(c1 sameCenterPoint c2)
函数编程
- 高阶参数
- 函数引用
- 函数参数
- 函数返回函数
- lambda,闭包和词法作用域
- inline,noinline,crossline
- 迭代器
- 内部迭代器
- 外部迭代器
- 序列
序列
val nameOfFirstAdult2 = people.asSequence().filter(::isAdult).map(::fetchFirstName).take(10)
println(nameOfFirstAdult2.toList())
fun nextOod(n:Int):Int = if(n % 2 == 0) n+2 else n+1
val oods = generateSequence(100,::nextOod)
println(oods.take(8).toList())
// fun nextRandom(seed:Int):Int = Random(seed).nextInt()
// val randoms = generateSequence(10,::nextRandom)
// println(randoms.take(10).toList())
val oods2 = sequence {
var i:Int = 0
while(true) {
i++
if(i % 2 == 0) {
yield(i)
}
}
}
println(oods2.drop(2).take(10).toList())
迭代器
- 内部迭代器
- filter
- map
- reduce
- flatMap
- fltten
- sorted
- groupby
val numbers = listOf(1,4,5,9,10,20,40)
numbers.filter{ e -> e % 2 == 0 }.forEach {
println(it)
}
val doubleEven = numbers.filter{ e -> e % 2 == 0 }.map{ e -> e * 2 }
println(doubleEven)
data class Person(val name:String,val age:Int)
val people = listOf(
Person("Kotlin",5),
Person("Java",10),
Person("C",20),
Person("C#",10),
Person("Python",20),
Person("JavaScript",15),
Person("C++",20)
)
println(people)
val result = people.filter{ person -> (person.age > 10) }
.map { person -> person.name }
.map { name -> name.toUpperCase() }
.reduce { names, name -> "$names # $name"}
val totalAge = people.map { person -> person.age }.reduce { total,age -> total + age}
val m = people.filter{person -> person.age > 10}.first().name
val takeSample = people.filter{person -> person.age > 10}.take(10)
println(m)
println(result)
println(totalAge)
println(takeSample)
val animals = listOf(
listOf(Person("Dog1",2),Person("Cat1",3)),
listOf(Person("Dog2",2),Person("Cat2",4))
)
println(animals.flatten())
val namesAndReversed = people.map { person -> person.name }
.map(String::toLowerCase)
.map { name -> listOf(name,name.reversed())}
println(namesAndReversed)
println(namesAndReversed.flatten())
val namesAndReversed2 = people.map { person -> person.name }
.map(String::toLowerCase)
.flatMap { name -> listOf(name,name.reversed())}
println(namesAndReversed2)
val namesSortedByAge = people.sortedBy{person -> person.age }
.map{person -> person.name }
println(namesSortedByAge)
val groupBy1stLetter = people.groupBy { person -> person.name.first() }
println(groupBy1stLetter)
lambda,闭包和词法作用域
- 什么是lambda
- lambda是无状态的,输出取决于输入参数的值
- 什么是闭包
- 依赖外部状态。这样的lambda被称为闭包——这是因为它关闭了定义范围,来绑定到非局部的属性和方法
- 什么是词法作用域
- 外部变量闭包的定义范围——即,闭包的主体是在哪里定义的,这称为词法作用域
- factor如果是可变量,闭包会有不同预期,尽量避免
//lambda
val doubleIt = { e:Int -> e * 2}
//闭包
val factor = 2
val doubleIt2 = {e:Int -> e* factor}
//factor2是变量的情况下的输出
var factor2 = 2
factor2 = 3
val doubled = listOf(1,2).map{it * factor2}
doubled.forEach { print(it)}
println("line")
factor2 = 0
doubled.forEach { print(it)}
println("line")
函数返回函数
val names = listOf("Pam","Ppam","Paul","Paula")
println(names.find {name -> name.length == 5})
fun predicateOfLength(length:Int):(String)->Boolean {
return {input:String -> input.length == length}
}
println(names.find(predicateOfLength(4)))
函数引用
fun walkTo(n:Int,action:(Int)->Unit) {
(1..n).forEach{
action(it)
}
}
walkTo(5) {
println(it)
}
walkTo(10,System.out::println)
object Terminal {
fun write(value:Int) = println(value)
}
walkTo(5,Terminal::write)
面向对象
- 泛型类
- 匿名对象
- 单例对象
- 接口和抽象类
- 内部类
- 派生类
- 委托方式
- 类委托
- 属性委托
- 延迟加载
- 短路求值
- Observable
委托方式
- 委托方式是低耦合,继承方式是高耦合
- 委托方式相比较传入对象的方式,减少了很多模板代码
- 委托方式可以重写方法
- 继承是可替代的.委托是不可替代的.
interface Worker {
fun work()
fun takeVacation()
}
class JavaWorker:Worker {
override fun work() = println("write Java...")
override fun takeVacation() = println("code at the beach....")
}
class KotlinWorker:Worker {
override fun work() = println("write Kotlin ....")
override fun takeVacation() = println("branch at the ranch...")
}
class ManagerBefore(val worker:Worker) {
fun work() = worker.work()
fun takeVacation() = worker.takeVacation()
}
class ManagerBy:Worker by JavaWorker()
class ManagerByV2(val staff:Worker):Worker by staff {
fun meeting() = println("the worker's class ${staff.javaClass.simpleName}")
override fun takeVacation() = println("handle by Manager")
}
val doe = ManagerByV2(KotlinWorker())
val roe = ManagerByV2(JavaWorker())
doe.work()
doe.meeting()
doe.takeVacation()
roe.work()
roe.meeting()
属性委托
var comment:String = "Some nice message"
println(comment)
comment = "This is Stupid"
println(comment)
import kotlin.reflect.KProperty
class PoliteString(var content:String) {
operator fun getValue(thisRef:Any?,property:KProperty<*>) = content.replace("stupid","s****")
operator fun setValue(thisRef:Any,property:KProperty<*>,value:String) {
content = value
}
}
var comment2:String by PoliteString(comment)
println(comment2)
Observable监控值修改
var count by observable(0) { property ,oldValue,newValue ->
println("Property: $property,old:$oldValue,new:$newValue")
}
println("count:$count")
count++
println("count:$count")
count--
println("count:$count")
var message by observable("") { property ,oldValue,newValue ->
println("Property: $property,old:$oldValue,new:$newValue")
}
println("message:$message")
message = "message1"
println("message:$message")
vetoable支持拒绝修改
var message2 by vetoable("") { property ,oldValue,newValue ->
println("Property: $property,old:$oldValue,new:$newValue")
newValue != "message2"
}
println("message2:$message2")
message2 = "message1"
println("message2:$message2")
message2 = "message2"
println("message2:$message2")
派生类和枚举
在Kotlin中,存在一种极端情况,我们有final类——即未标记为open的类,它们不能有任何派生类。在另一种极端情况,我们有open类和abstract类,不知道哪个类可以继承它们。最好能有一个中间地带,让一个类只作为几个类的基,这几个类是由类的创建者指定的。
- 枚举和派生类都知道有几种类型
- 派生类可以有很多实例
- 枚举每种类型只有一个实例
- 枚举可以定义定义方法
- 枚举可以重写方法
enum class Suit(val symbol:Char) {
CLUBS('\u2663'),DIAMONDS('\u2666'){
override fun display() = "${super.display()}-${symbol}"
} ,HEARTS('\u2665'),SPADES('\u2660');
open fun display() = "$symbol $name"
}
sealed class Card(val suit:Suit)
class Ace(suit:Suit):Card(suit)
class King(suit:Suit):Card(suit)
class Queen(suit:Suit):Card(suit)
class Jack(suit:Suit):Card(suit)
class OtherCard(suit:Suit):Card(suit)
object OtherObject : Card(Suit.DIAMONDS) {
}
for(suit in Suit.values()) {
println(suit.display())
}
println(Ace(Suit.DIAMONDS).suit.display())
println(OtherObject.suit)
内部类
class TVV2 {
private var volumn = 0
inner class TVRemoteV2:Remote {
override fun up() {
volumn++
}
override fun down() {
volumn--
}
}
val remote:Remote
get() = TVRemoteV2()
override fun toString():String = "Volumn :${volumn}"
}
val tv_v2 = TVV2()
val remote_v2 = tv_v2.remote
println("$tv_v2")
remote_v2.up()
println("$tv_v2")
remote_v2.down()
println("$tv_v2")
接口和抽象类
- 接口可以实现多个,抽象类只能继承一个
- 接口不能有属性,抽象类可以有属性
- 类更多的是继承状态,处理状态
- 接口更多的行为和契约.
interface Remote {
fun up()
fun down()
fun doubleUp() {
up()
up()
}
}
class TV {
var volumn = 0
override fun toString():String {
return "The TV's volumn is ${volumn}"
}
}
class TVRemote(val tv:TV):Remote {
override fun up() {
tv.volumn ++
println(tv)
}
override fun down() {
tv.volumn --
myPrintln(tv)
}
}
fun myPrintln(msg:Any) {
println(msg)
}
val tv = TV()
val remote = TVRemote(tv)
remote.up()
remote.down()
remote.doubleUp()
abstract class Muiscian(val name:String ,val activeFrom:Int) {
abstract fun instrumentType():String
}
open class Cellist(name:String,activeFrom:Int):Muiscian(name,activeFrom) {
override fun instrumentType():String = "instrumentType"
}
class CellistChild(name:String,activeFrom:Int):Cellist(name,activeFrom) {
override fun instrumentType():String = "instrumentType from Child"
}
val ma = Cellist("YoyoMa",1986)
val maChild = CellistChild("HahaMa",1982)
println(ma.instrumentType())
println(maChild.instrumentType())
泛型类
class PriorityPair<T:Comparable<T>>(member1:T,member2:T) {
val first:T
val second :T
init {
if(member1 >= member2) {
first = member1
second = member2
}else {
first = member2
second = member1
}
}
override fun toString() = "${first} ${second}"
}
println(PriorityPair(2,1))
println(PriorityPair("A","B"))
匿名对象
fun drawCircle() {
val circle = object {
val x = 100
val y = 100
val radius = 100
override fun toString():String {
return "($x,$y) $radius"
}
}
println(circle)
}
drawCircle()
单例对象
object Util {
fun numberOfProcessors() = Runtime.getRuntime().availableProcessors()
}
println(Util.numberOfProcessors())
使用工厂创建对象
class MachineOperator private constructor(val name:String) {
private fun checkin() {
println("checkin $name")
}
companion object {
fun create(name:String) :MachineOperator {
val instance = MachineOperator(name)
instance.checkin()
return instance
}
}
}
val operator = MachineOperator.create("Master")
println(operator.name)
泛型学习
- 普通的函数参数传入
- 带有集合泛型的参数传入
- 什么是使用点协变
- 什么是声明点协变
- 什么是逆变
- 协变是读
- out
- 允许接受子类的集合
- 什么是逆变
- 逆变是写
- in
- 允许接受父类的集合
- Where来实现多个接口的对象限定
- 类型擦除
逆变和协变
//函数
fun copyFromTo(from:Array<out Fruit>,to:Array<in Fruit>) {
for(i in 0 until from.size) {
to[i] = from[i]
}
}
val fruits1 = Array<Fruit>(3) { _ -> Fruit()}
val bananas3 = Array<Banana>(3) { _ -> Banana()}
//协变
copyFromTo(bananas3,fruits1)
// copyFromToNoOut(bananas3,fruits1)
//逆变
val things = Array<Any>(3) { _ -> Fruit()}
copyFromTo(bananas3,things)
Where限定符
interface AutoClosable {
fun close()
}
fun <T:AutoClosable> useAndClose(input:T) {
input.close()
}
fun <T> useAndCloseAndAppend(input:T ) where T:AutoClosable,T:Appendable {
input.append("there")
input.close()
}
*限定符
- 只能读
- 不能写
- 可以传入所有类型的Array
fun printAllValues(values:Array<*>) {
for(value in values) {
println(value)
}
}
printAllValues(arrayOf(2,3,4))
类型擦除
java中因为类型擦除,通过传入类型来查找对象
abstract class Book(val name:String)
class Fiction(name:String):Book(name)
class NonFiction(name:String):Book(name)
val books = listOf(Fiction("book1"),Fiction("book2"),NonFiction("nobook1"))
fun <T> findFirst(books:List<Book>,ofClass:Class<T>):T {
val selected = books.filter { book -> ofClass.isInstance(book)}
if(selected.size == 0) {
throw RuntimeException("Not Found")
}
return ofClass.cast(selected[0])
}
println(findFirst(books,NonFiction::class.java).name)
kotlin通过reified 来保留类型.
inline fun <reified T> findFirstByKotlin(books:List<Book>):T {
val selected = books.filter { book -> book is T }
if(selected.size == 0) {
throw RuntimeException("Not Found")
}
return selected[0] as T
}
println(findFirstByKotlin<NonFiction>(books).name)