这篇文章为kotlin学习记录,主要针对的是自己的知识盲区,不适用于新手。

文中所有demo均来自于kotlin官网

类型

整形

Type Size (bits) Min value Max value
Byte 8 -128 127
Short 16 -32768 32767
Int 32 -2,147,483,648 (-231) 2,147,483,647 (231 - 1)
Long 64 -9,223,372,036,854,775,808 (-263) 9,223,372,036,854,775,807 (263 - 1)

浮点型

Type Size (bits) Significant bits Exponent bits Decimal digits
Float 32 24 8 6-7
Double 64 53 11 15-16

变量

只读变量使用val,可以被重新赋值的变量使用关键字var

// example of val
val a: Int = 1 // immediate assignment
val b = 2 // `Int` type is inferred
val c: Int // Type required when no initializer is provided
c = 3 // deferred assignment // example of var
var x = 5 // `Int` type is inferred
x += 1

函数

默认参数

fun foo(a: Int = 0, b: String = "") { ... }

函数扩展

fun String.spaceToCamelCase() { ... }

"Convert this to camelcase".spaceToCamelCase()

单行表达式函数

fun theAnswer() = 42

// 同样适用于when
fun transform(color: String): Int = when (color) {
"Red" -> 0
"Green" -> 1
"Blue" -> 2
else -> throw IllegalArgumentException("Invalid color param value")
}

Lambda表达式

匿名函数

带receiver的函数字面量

类似于函数扩展,使得你能够直接在函数体中直接返回到receiver object. 在函数体重,receiver object使用this访问到,你可以通过this来获取到reciver object中的属性和方法。

val sum: Int.(Int) -> Int = { other -> plus(other)

// 匿名函数
val sum = fun Int.(other: Int): Int = this + other

Lambda表达式

基本语法

val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
  • lambda 使用 {} 包围
  • 后面的为函数体
  • 如果lambda的返回值不为空(Unit),那么最后一个表达式即为返回值,上面的例子中,x + y 即为返回值

类型声明可以省略,简略写法为:

val sum = { x: Int, y: Int -> x + y }

lambda为函数的最后一个参数

如果lambda为函数的最后一个参数,那么可以直接简写在函数外面,例如

val product = items.fold(1) { acc, e -> acc * e }

// 如果lambda作为函数的最后一个参数,那么,函数()可以省略
run { println("...") }

隐式的it

如果lambda只有一个参数,那么这个参数可以不必要声明,参数会隐式被it代替

ints.filter { it > 0 } // this literal is of type '(it: Int) -> Boolean'

// 等价于
ints.filter { intVal -> intVal > 0 }

lambda返回值

默认如果lambda的返回值不为空(Unit),那么最后一个表达式即为返回值,但是也可以显示地使用return来进行值的返回,但是要遵循qualified return语法

ints.filter {
val shouldFilter = it > 0
shouldFilter
} ints.filter {
val shouldFilter = it > 0
return@filter shouldFilter
}

跳过lambda的返回值

如果不需要使用到lambda的参数,那么可以使用_代替

map.forEach { _, value -> println("$value!") }

匿名函数

匿名函数和lambda表达式一样,都是函数字面量。

Function literals are functions that are not declared but are passed immediately as an expression.

fun(x: Int, y: Int): Int = x + y

和lambda相比,匿名函数主要有两点不同

  • 匿名函数可以指定返回类型,而lambda不同
  • 如果没有定义返回标签,lambda的返回会直接返回到最近定义了fun关键字的函数,而匿名函数会返回到函数本身

类的继承使用:,类默认是final类型的(即不可修改),如果要让类可继承,使用open关键字

open class Shape

class Rectangle(var height: Double, var length: Double): Shape() {
var perimeter = (height + length) * 2
}

DTOs(POJOs/POCOs)

data class主要用作承载数据的对象,可以用作两个系统之间数据的交换

data class Customer(val name: String, val email: String)
  • getters (and setters in case of var s) for all properties
  • equals()
  • hashCode()
  • toString()
  • copy()
  • component1(), component2() 用作数据解构

实例化一个抽象类

abstract class MyAbstractClass {
abstract fun doSomething()
abstract fun sleep()
} fun main() {
val myObject = object : MyAbstractClass() {
override fun doSomething() {
// ...
} override fun sleep() { // ...
}
}
myObject.doSomething()
}

匿名类

Object表达式 主要用来创建匿名类

val helloWorld = object {
val hello = "Hello"
val world = "World"
// object expressions extend Any, so `override` is required on `toString()`
override fun toString() = "$hello $world"
}

匿名内部类

匿名内部类也叫伴生类,使用关键字companion,通常的作用是为类提供静态属性和方法,类似于java的static关键字

// 一个类中只允许声明一个伴生类
// 下面的例子中,如果同时存在两个伴生类,会报类型错误
class MyClass {
// 也可以声明名字
companion object Factory {
fun create(): MyClass = MyClass()
} // 匿名, Companion
companion object {
fun create(): MyClass = MyClass()
}
} fun main() {
// 调用可以省略掉伴生类名
println(MyClass.create())
println(MyClass.Factory.create())
println(MyClass.Companion.create())
}

字符串模板

var a = 1
// simple name in template:
val s1 = "a is $a" a = 2
// 如果需要计算,则使用${xxx}来表示
// arbitrary expression in template:
val s2 = "${s1.replace("is", "was")}, but now is $a"

条件判断

条件判断采用关键字if / else if / else,需要注意一点的是if也可以作为表达式使用

fun maxOf(a: Int, b: Int) = if (a > b) a else b

if-not-null-else 简写

val files = File("Test").listFiles()

println(files?.size ?: "empty") // if files is null, this prints "empty"

// To calculate the fallback value in a code block, use `run`
val filesSize = files?.size ?: run {
return someSize
}
println(filesSize)

if not null 执行 (let)

val value = ...

value?.let {
... // execute this block if not null
}

Break and continue 标签

loop@ for (i in 1..100) {
for (j in 1..100) {
if (...) break@loop
}
}

Return to 自定义标签

the return -expression returns from the nearest enclosing function

fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return // non-local return directly to the caller of foo()
print(it)
}
println("this point is unreachable")
} // To return from a lambda expression, label it and qualify the return:
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // local return to the caller of the lambda - the forEach loop
print(it)
}
print(" done with explicit label")
} // Often it is more convenient to use implicit labels
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@forEach // local return to the caller of the lambda - the forEach loop
print(it)
}
print(" done with implicit label")
} // Return to anonymous function
fun foo() {
listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
if (value == 3) return // local return to the caller of the anonymous function - the forEach loop
print(value)
})
print(" done with anonymous function")
}

When(更强大的Switch)

fun describe(obj: Any): String =
when (obj) {
1 -> "One"
"Hello" -> "Greeting"
is Long -> "Long"
!is String -> "Not a string"
else -> "Unknown"
}

Ranges

使用in关键字来判断一个变量是否处在这个区间中

val x = 10
val y = 9
if (x in 1..y+1) {
println("fits in range")
}

类型检查和自动转换

fun getStringLength(obj: Any): Int? {
if (obj is String) {
// `obj` is automatically cast to `String` in this branch
return obj.length
} // `obj` is still of type `Any` outside of the type-checked branch
return null
} // 或者
fun getStringLength(obj: Any): Int? {
if (obj !is String) return null // `obj` is automatically cast to `String` in this branch
return obj.length
}

不安全转换

val x: String = y as String

安全转换

val x: String? = y as? String

代理

代理使用关键字by,代表的是将原本应该自己职责代理给其他的类或者属性

类代理

interface Base {
fun printMessage()
fun printMessageLine()
} class BaseImpl(val x: Int) : Base {
override fun printMessage() { print(x) }
override fun printMessageLine() { println(x) }
} // 交给代理类Base去做
class Derived(b: Base) : Base by b {
// 也可以重新override
override fun printMessage() { print("abc") }
} fun main() {
val b = BaseImpl(10)
Derived(b).printMessage()
Derived(b).printMessageLine()
}

属性代理

一个规划化的栗子

class Example {
// set p, get p will delegate by Delegate getValue/setValue
var p: String by Delegate()
}

The syntax is: val/var <property name>: <Type> by <expression>. The expression after by is a delegate, because the get() (and set()) that correspond to the property will be delegated to its getValue() and setValue() methods. Property delegates don’t have to implement an interface, but they have to provide a getValue() function (and setValue() for vars).

import kotlin.reflect.KProperty

class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
} operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
} val e = Example()
println(e.p)

常用的属性代理有lazyobservable

// The first call to get() executes the lambda passed to lazy() and remembers the result.
// Subsequent calls to get() simply return the remembered result.
val lazyValue: String by lazy {
println("computed!")
"Hello"
} fun main() {
// computed!
// Hello
println(lazyValue) // Hello
println(lazyValue)
} // observable
import kotlin.properties.Delegates class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
} fun main() {
val user = User()
// <no name> -> first
user.name = "first" // first -> second
user.name = "second"
}

运算符重载

运算符重载允许你重新自定义已经定义好的操作,比如”+”, “-”等等。实现运算符重载,需要使用到operator关键字

member方式

interface IndexedContainer {
operator fun get(index: Int)
} // 重写时可以忽略operator关键字
class OrdersList: IndexedContainer {
override fun get(index: Int) { /*...*/ }
}

函数扩展方式

data class Point(val x: Int, val y: Int)

operator fun Point.unaryMinus() = Point(-x, -y)

val point = Point(10, 20)

fun main() {
println(-point) // prints "Point(x=-10, y=-20)"
}

Scope functions

作用域函数的目的就是让你在一个特定的object context中执行你的函数体,在这个作用域中,你能获取到这个object而无需知道它的名字

具体的作用域函数主要有:letrunwithapplyalso

Function Object reference Return value Is extension function
let it Lambda result Yes
run this Lambda result Yes
run - Lambda result No: called without the context object
with this Lambda result No: takes the context object as an argument.
apply this Context object Yes
also it Context object Yes

使用this还是it

在作用域函数中,你有两种方式获取到这个context object. lambda receiver(this) 或者 lambda argument(it)

runwithapply使用this指向这个context object,一般情况下,this可以省略。推荐使用this的情况是,需要访问或者设置这个对象的一些属性或者方法。

val adam = Person("Adam").apply {
age = 20 // same as this.age = 20 or adam.age = 20
city = "London"
}
println(adam)

letalso使用it指向这个object. it适用的场景是,这个object作为变量或者参数使用。

fun getRandomInt(): Int {
return Random.nextInt(100).also {
writeToLog("getRandomInt() generated value $it")
}
} val i = getRandomInt()
println(i)

返回值

  • apply 和 also 返回context object(主要适用于进行对象的链式处理)
  • letrun 和 with 返回的是 lambda的执行结果

run

// this, Lambda result

@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}

run的使用场景是:当这个lambda中同时包含对象初始化以及返回值计算

val service = MultiportService("https://example.kotlinlang.org", 80)

val result = service.run {
port = 8080
query(prepareRequest() + " to port $port")
} // the same code written with let() function:
val letResult = service.let {
it.port = 8080
it.query(it.prepareRequest() + " to port ${it.port}")
}

另外,run也可以作为非扩展函数使用,作为非扩展函数时,主要用来通过计算一系列语句声明来得到返回表达式。


@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
} // example
val hexNumberRegex = run {
val digits = "0-9"
val hexDigits = "A-Fa-f"
val sign = "+-" Regex("[$sign]?[$digits$hexDigits]+")
} for (match in hexNumberRegex.findAll("+123 -FFFF !%*& 88 XYZ")) {
println(match.value)
}

let

// it, Lambda result

@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
  • 用来执行一个或者多个函数链式调用后的结果

    val numbers = mutableListOf("one", "two", "three", "four", "five")
    numbers.map { it.length }.filter { it > 3 }.let {
    println(it)
    // and more function calls if needed
    } // 如果一个lambda块中,只有一个函数并且使用it作为它的参数
    // 则可以使用函数引用(::)来代替这个lambda
    numbers.map { it.length }.filter { it > 3 }.let(::println)
  • 用作判空检查

    val str: String? = "Hello"
    //processNonNullString(str) // compilation error: str can be null
    val length = str?.let {
    println("let() called on $it")
    processNonNullString(it) // OK: 'it' is not null inside '?.let { }'
    it.length
    }
  • 提升代码的可阅读性

    val numbers = listOf("one", "two", "three", "four")
    val modifiedFirstItem = numbers.first().let { firstItem ->
    println("The first item of the list is '$firstItem'")
    if (firstItem.length >= 5) firstItem else "!" + firstItem + "!"
    }.uppercase()
    println("First item after modifications: '$modifiedFirstItem'")

apply

// this, Context Object

@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}

apply常用作对象的配置,例如

val adam = Person("Adam").apply {
age = 32
city = "London"
}
println(adam)

also

// it, Context Object

@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
return this
}

also主要用来执行一些需要将object作为参数的操作

val numbers = mutableListOf("one", "two", "three")
numbers
.also { println("The list elements before adding new one: $it") }
.add("four")

with

// this, Lambda result

@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
  • 持有object引用,执行函数,无需返回

    val numbers = mutableListOf("one", "two", "three")
    with(numbers) {
    println("'with' is called with argument $this")
    println("It contains $size elements")
    }
  • object的属性或者方法参与值的计算

    val numbers = mutableListOf("one", "two", "three")
    val firstAndLast = with(numbers) {
    "The first element is ${first()}," +
    " the last element is ${last()}"
    }
    println(firstAndLast)

Kotlin笔记小结(For Java Developer)的更多相关文章

  1. 学习笔记(三)--->《Java 8编程官方参考教程(第9版).pdf》:第十章到十二章学习笔记

    回到顶部 注:本文声明事项. 本博文整理者:刘军 本博文出自于: <Java8 编程官方参考教程>一书 声明:1:转载请标注出处.本文不得作为商业活动.若有违本之,则本人不负法律责任.违法 ...

  2. 时隔两年最近再次折腾opensuse 的一些笔记 - opensuse linux java service shell

    时隔两年最近再次折腾opensuse 的一些笔记 - opensuse linux java service shell opensuse 一些常用命令:    service xxx start/s ...

  3. Kotlin 或将取代 Java——《Java 编程思想》作者 Bruce Eckel [转]

    Bruce Eckel 是<Java 编程思想>.<C++编程思想>的作者,同时也是 MindView 公司的总裁,该公司向客户提供软件咨询和培训.他是 C++ 标准委员会拥有 ...

  4. Groovy小结:java调用Groovy方法并传递参数

    Groovy小结:java调用Groovy方法并传递参数 @(JAVA总结) 1. 场景描述 在网上查了资料发现,java有三种方式调用groovy脚本.但是真正在实际的服务器环境中,嵌入groovy ...

  5. What skills you need to become a full stack java developer?

    For a full stack Java developer you should start with learning backend and front-end technologies Fr ...

  6. Java Developer's Guide to SSL Certificates

    https://www.codebyamir.com/blog/java-developers-guide-to-ssl-certificates Overview When developing w ...

  7. openresty 学习笔记小结:综合应用实例

    openresty 学习笔记小结:综合应用实例 这个综合实验实现的功能其实很简单,用户访问一个页面,显示一个默认页面.输入参数(post或者get都可以),如果参数在数据库查询得到并满足一定条件,根据 ...

  8. Kotlin笔记

    官网: http://kotlinlang.org/ http://kotlinlang.org/docs/reference/ 中文教程: http://kotlindoc.com/ Gradle: ...

  9. Java学习笔记之:Java 流

    一.介绍 Java.io包几乎包含了所有操作输入.输出需要的类.所有这些流类代表了输入源和输出目标. Java.io包中的流支持很多种格式,比如:基本类型.对象.本地化字符集等等. 一个流可以理解为一 ...

随机推荐

  1. tabbar选中按钮的标题颜色和字体

    @implementation XMGTabBarController /* 问题: 1.选中按钮的图片被渲染 -> iOS7之后默认tabBar上按钮图片都会被渲染 1.修改图片 2.通过代码 ...

  2. shell编程之免交互 (不要再让你的双手过度劳累了)

    shell编程之免交互 1.Here Document免交互 2.Expect免交互 3.免交互磁盘创建 1.Here Document免交互 概述: Here Document使用I/O重定向的方式 ...

  3. VUE3 之 ref、provide、inject 的使用 - 这个系列的教程通俗易懂,适合新手

    1. 概述 首因效应告诉我们: 在日常交往中,第一印象是非常重要的,好的第一印象能让我们在与人相处时事半功倍. 但也从另一面告诉我们,不能仅凭第一印象去判断一个人,有时虚假的第一印象,也有可能蒙蔽我们 ...

  4. Postman_JavaScript

    使用语法:JavaScript 结构: 测试工具主要包括三部分 在发起请求之前运行的Pre-request,预处理数据,作用:在发送请求前编辑请求数据,比如用户名或时间戳 对响应后的数据运行的Test ...

  5. nodejs并行无关联

    var async = require('async'); //串行无关联series//串行有关联waterfall//并行:parallel //会把各个函数的执行结果一起放到最后的回调中asyn ...

  6. SpringBoot树获取方法总结

    最近项目中有需要获取全国行政区划省-市-区县-乡镇.街道办的树状结构数据,现将自己获取树的方法总结如下,有不到之处,敬请批评指正! 一.全国行政区划数据的整理以及获取 获取地址:https://pan ...

  7. 基于反熔丝FPGA、QSPI FLASH的高可靠程序存储、启动控制系统

    1      涉及术语解释 1.1     三模冗余 三模冗余系统简称TMR(Triple Modular Redundancy),是最常用的一种容错设计技术.三个模块同时执行相同的操作,以多数相同的 ...

  8. 01 前端基础之HTML

    目录 前端基础之HTML HTML简介 如何创建及展示 head内常见标签 body内基本标签 特殊符号 常见标签 标签的两大重要属性 列表标签 表格标签 form表单(很重要) 初次体验前后端交互 ...

  9. 3、前端--伪元素选择器、选择器优先级、字体、背景、边框、display、盒子模型

    伪元素选择器 # 首字调整>>>:也是一种文档布局的方式 p:first-letter { font-size: 48px; /*字体大小*/ color: red; } # 在文本 ...

  10. 32、python并发编程之背景知识

    目录: 一 引子 二 为什么要有操作系统 三 什么是操作系统 四 操作系统与普通软件的区别 五 操作系统发展史 六 总结视频链接: 一 引子 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的 ...