这篇文章为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. npm 查看一个包的版本信息

    有了npm 我们能够简单的一段代码就下载我们需要的包,但是包是不断更新的, 所以我们要关注包的版本信息: 现在,假设我们需要 jquery ,但是jquery现在有很多版本,我们如何通过npm查看呢? ...

  2. Idea快捷键---根据自己使用情况持续更新

    查看接口的实现类 -->ctrl+alt+b 查看继承关系 -->ctrl+h 快速查看上次查看代码的位置: -->ctrl+alt+方向键(注意与intel显卡快捷键的冲突,如有冲 ...

  3. 认识Visual C++ 6.0工程结构

  4. 需求: 使用LinkedList存储一副扑克牌,然后实现洗牌功能。

    import java.util.LinkedList; import java.util.Random; /* 需求: 使用LinkedList存储一副扑克牌,然后实现洗牌功能. */ //扑克类 ...

  5. ◆JAVA加密解密-3DES

    从数据安全谈起       当你使用网银时,是否担心你的银行卡会被盗用?     当你和朋友用QQ进行聊天时,是否担心你的隐私会被泄露?     作为开发者,编写安全的代码比编写优雅的代码更重要,因为 ...

  6. [USACO4.2]工序安排Job Processing

    两种想法: (样例是真的良心,卡掉了两种错误做法)洗完一件马上塞一件到最快的空闲烘干机去?X,因为最后一件洗完的衣服决定了第二问的答案,但它并不一定得到最优待遇--最快的烘干机.   给最后一件洗完的 ...

  7. 排查log4j不输出日志到文件的问题

    问题描述 项目使用Spring Boot框架,在pom文件中添加了如下配置: <dependency> <groupId>org.slf4j</groupId> & ...

  8. 微服务从代码到k8s部署应有尽有系列(五、民宿服务)

    我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...

  9. io流复习+代码演示

    前置知识: 序列化和反序列化 1.序列化就是在保存数据时, 保存数据的值和数据类型 2.反序列化就是在恢复数据时, 恢复数据的值和数据类型 3.需要让某个对象支持序列化机制,则必须让其类是可序列化的, ...

  10. 【剑指 Offer II 001. 整数除法】同leedcode 29.两数相除

    剑指 Offer II 001. 整数除法 解题思路 在计算的时候将负数转化为正数,对于32位整数而言,最小的正数是-2^31, 将其转化为正数是2^31,导致溢出.因此将正数转化为负数不会导致溢出. ...