1、创建 DTOs(POJOs/POCOs)
data class Customer(val name: String, val email: String)
会为 Customer
类提供以下功能:
- 所有属性的 getters (对于 var 定义的还有 setters)
equals()
hashCode()
toString()
copy()
- 所有属性的
component1()
、component2()
……等等(参见数据类)
2、 函数的默认参数
//调用方可以不传任何参数,采用默认值
foo()
//方法
fun foo(a: Int = 0, b: String = "") { …… }
3、过滤 list
//数组
val list = arrayListOf<Int>(1,2,3,4,5,6,7,8)
//方法 1:
//val positives = list.filter { x -> x > 5 }
//方法 2:
val positives = list.filter { it > 5 }
//结果:
positives.forEach {
Log.d("LUO", "it=====$it")
}
4、检测元素是否存在于集合中(也支持字符串)
//集合
val list = arrayListOf<String>("a","b","c","d")
//1、在集合中判断
if ("a" in list) {
Log.d("LUO", "1=====")
}
//2、不在集合中判断
if ("m" !in list) {
Log.d("LUO", "2=====")
}
5、字符串内插
println("Name $name")
6、类型判断
when (x) {
is Foo //-> ……
is Bar //-> ……
else //-> ……
}
7、遍历 map/pair型list
//map 集合
var map = HashMap<String,Int>()
map.put("小明",22);
map.put("小刚",25);
map.put("小红",28);
//遍历,
for ((k, v) in map) {
Log.d("LUO", "$k -> $v")
}
注意:k、v 可以改成任意名字。
8、使用区间
for (i in 1..100) { …… } // 闭区间:包含 100
for (i in 1 until 100) { …… } // 半开区间:不包含 100
for (x in 2..10 step 2) { …… }
for (x in 10 downTo 1) { …… }
if (x in 1..10) { …… }
9、只读 list
val list = listOf("a", "b", "c")
10、只读 map
val map = mapOf("a" to 1, "b" to 2, "c" to 3)
11、访问 map
println(map["key"])
map["key"] = value
//map 集合
var map = HashMap<String,Int>()
map.put("小明",22);
map.put("小刚",25);
map.put("小红",28);
//打印
val aa = map["小红"]
Log.d("LUO", "==== $aa")
12、延迟属性
val p: String by lazy {
// 计算该字符串
}
13、扩展函数
fun String.spaceToCamelCase() {
Log.d("LUO", "==执行了扩展函数==")
}
"Convert this to camelcase".spaceToCamelCase()
14、创建单例
object Resource {
val name = "Name"
}
15、If not null 缩写
val files = File("Test").listFiles()
println(files?.size)
16、If not null and else 缩写
val files = File("Test").listFiles()
println(files?.size ?: "empty")
17、if null 执行一个语句
val values = ……
val email = values["email"] ?: throw IllegalStateException("Email is missing!")
18、在可能会空的集合中取第一元素
val emails = …… // 可能会是空集合
val mainEmail = emails.firstOrNull() ?: ""
19、if not null 执行代码
val value = ……
value?.let {
…… // 代码会执行到此处, 假如data不为null
}
20、映射可空值(如果非空的话)
val value = ……
val mapped = value?.let { transformValue(it) } ?: defaultValue
// 如果该值或其转换结果为空,那么返回 defaultValue。
21、返回 when 表达式
fun transform(color: String): Int {
return when (color) {
"Red" -> 0
"Green" -> 1
"Blue" -> 2
else -> throw IllegalArgumentException("Invalid color param value")
}
}
22、“try/catch”表达式
fun test() {
val result = try {
count()
} catch (e: ArithmeticException) {
throw IllegalStateException(e)
}
// 使用 result
}
23、“if”表达式
fun foo(param: Int) {
val result = if (param == 1) {
"one"
} else if (param == 2) {
"two"
} else {
"three"
}
}
24、返回类型为 Unit 的方法的 Builder 风格用法
fun arrayOfMinusOnes(size: Int): IntArray {
return IntArray(size).apply { fill(-1) }
}
25、单表达式函数
fun theAnswer() = 42
//等价于
fun theAnswer(): Int {
return 42
}
//单表达式函数与其它惯用法一起使用能简化代码,例如和 when 表达式一起使用:
fun transform(color: String): Int = when (color) {
"Red" -> 0
"Green" -> 1
"Blue" -> 2
else -> throw IllegalArgumentException("Invalid color param value")
}
26、对一个对象实例调用多个方法 (with)
class Turtle {
fun penDown()
fun penUp()
fun turn(degrees: Double)
fun forward(pixels: Double)
}
val myTurtle = Turtle()
with(myTurtle) { // 画一个 100 像素的正方形
penDown()
for (i in 1..4) {
forward(100.0)
turn(90.0)
}
penUp()
}
27、配置对象的属性(apply)
val myRectangle = Rectangle().apply {
length = 4
breadth = 5
color = 0xFAFAFA
}
这对于配置未出现在对象构造函数中的属性非常有用。
28、对于需要泛型信息的泛型函数的适宜形式
// public final class Gson {
// ……
// public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
// ……
inline fun <reified T: Any> Gson.fromJson(json: JsonElement): T = this.fromJson(json, T::class.java)
29、 使用可空布尔
val b: Boolean? = ……
if (b == true) {
……
} else {
// `b` 是 false 或者 null
}
30、交换两个变量
var a = 1
var b = 2
a = b.also { b = a }
31、TODO():将代码标记为不完整
Kotlin 的标准库有一个 TODO() 函数,该函数总是抛出一个 NotImplementedError。 其返回类型为 Nothing,因此无论预期类型是什么都可以使用它。 还有一个接受原因参数的重载:
fun calcTaxes(): BigDecimal = TODO("Waiting for feedback from accounting")
IntelliJ IDEA 的 kotlin 插件理解 TODO() 的语言,并且会自动在 TODO 工具窗口中添加代码指示。
32、每个数字类型支持如下的转换:
- toByte(): Byte
- toShort(): Short
- toInt(): Int
- toLong(): Long
- toFloat(): Float
- toDouble(): Double
- toChar(): Char
33、整数除法
请注意,整数间的除法总是返回整数。会丢弃任何小数部分。例如:
val x = 5 / 2
//println(x == 2.5) // ERROR: Operator '==' cannot be applied to 'Int' and 'Double'
println(x == 2)
如需返回浮点类型,请将其中的一个参数显式转换为浮点类型。
fun main() {
val x = 5 / 2.toDouble()
println(x == 2.5)
}
34、字符串
字符串用 String 类型表示。字符串是不可变的。 字符串的元素——字符可以使用索引运算符访问: s[i]。 可以用 for 循环迭代字符串:
for (c in str) {
println(c)
}
可以用 + 操作符连接字符串。这也适用于连接字符串与其他类型的值, 只要表达式中的第一个元素是字符串:
val s = "abc" + 1
println(s + "def")
请注意,在大多数情况下,优先使用字符串模板或原始字符串而不是字符串连接
35、 字符串模板
字符串字面值可以包含模板表达式 ,即一些小段代码,会求值并把结果合并到字符串中。 模板表达式以美元符($)开头,由一个简单的名字构成:
val i = 10
println("i = $i") // 输出“i = 10”
或者用花括号括起来的任意表达式:
val s = "abc"
println("$s.length is ${s.length}") // 输出“abc.length is 3”
36、返回和跳转
Kotlin 有三种结构化跳转表达式:
- return。默认从最直接包围它的函数或者匿名函数返回。
- break。终止最直接包围它的循环。
- continue。继续下一次最直接包围它的循环。
所有这些表达式都可以用作更大表达式的一部分:
val s = person.name ?: return
37、继承
在 Kotlin 中所有类都有一个共同的超类 Any,这对于没有超类型声明的类是默认超类:
class Example // 从 Any 隐式继承
Any 有三个方法:equals()、 hashCode() 与 toString()。因此,为所有 Kotlin 类都定义了这些方法。
默认情况下,Kotlin 类是最终(final)的:它们不能被继承。 要使一个类可继承,请用 open 关键字标记它。
open class Base // 该类开放继承
//如需声明一个显式的超类型,请在类头中把超类型放到冒号之后:
open class Base(p: Int)
class Derived(p: Int) : Base(p)
38、接口
Kotlin 的接口可以既包含抽象方法的声明也包含实现。与抽象类不同的是,接口无法保存状态。它可以有属性但必须声明为抽象或提供访问器实现。
使用关键字 interface 来定义接口
interface MyInterface {
fun bar()
fun foo() {
// 可选的方法体
}
}
//一个类或者对象可以实现一个或多个接口。
class Child : MyInterface {
override fun bar() {
// 方法体
}
}
39、接口继承
一个接口可以从其他接口派生,从而既提供基类型成员的实现也声明新的函数与属性。很自然地,实现这样接口的类只需定义所缺少的实现:
interface Named {
val name: String
}
interface Person : Named {
val firstName: String
val lastName: String
override val name: String get() = "$firstName $lastName"
}
data class Employee(
// 不必实现“name”
override val firstName: String,
override val lastName: String,
val position: Position
) : Person
注意:
1、我在 android Moudle 中定义的 Kotlin 接口,在 APP 工程中可以看到,单使用不到?
2、让APP 工程支持 kotlin 编程,在 kt 接口中继承Moudle中的接口,用 kt 接口,就可以实现接口回调;
40、函数式(SAM)接口
只有一个抽象方法的接口称为函数式接口或 SAM(单一抽象方法)接口。函数式接口可以有多个非抽象成员,但只能有一个抽象成员。
可以用 fun 修饰符在 Kotlin 中声明一个函数式接口。
fun interface KRunnable {
fun invoke()
}
SAM 转换
1、对于函数式接口,可以通过 lambda 表达式实现 SAM 转换,从而使代码更简洁、更有可读性。
2、使用 lambda 表达式可以替代手动创建实现函数式接口的类。 通过 SAM 转换, Kotlin 可以将其签名与接口的单个抽象方法的签名匹配的任何 lambda 表达式转换为实现该接口的类的实例。
//例如,有这样一个 Kotlin 函数式接口:
fun interface IntPredicate {
fun accept(i: Int): Boolean
}
//如果不使用 SAM 转换,那么你需要像这样编写代码:
// 创建一个类的实例
val isEven = object : IntPredicate {
override fun accept(i: Int): Boolean {
return i % 2 == 0
}
}
通过利用 Kotlin 的 SAM 转换,可以改为以下等效代码:
// 通过 lambda 表达式创建一个实例
val isEven = IntPredicate { it % 2 == 0 }
41、类和接口
对于类内部声明的成员:
- private 意味着只在这个类内部(包含其所有成员)可见;
- protected—— 和 private一样 + 在子类中可见。
- internal —— 能见到类声明的 本模块内 的任何客户端都可见其 internal 成员;
- public —— 能见到类声明的任何客户端都可见其 public 成员。
请注意在 Kotlin 中,外部类不能访问内部类的 private 成员。
如果你覆盖一个 protected 成员并且没有显式指定其可见性,该成员还会是 protected 可见性。
42、泛型
与 Java 类似,Kotlin 中的类也可以有类型参数:
class Box<T>(t: T) {
var value = t
}
//一般来说,要创建这样类的实例,我们需要提供类型参数:
val box: Box<Int> = Box<Int>(1)
//但是如果类型参数可以推断出来,例如从构造函数的参数或者从其他途径,允许省略类型参数:
val box = Box(1) // 1 具有类型 Int,所以编译器知道我们说的是 Box<Int>。