0%

在Kotlin中可以使用三个"开始,三个"结束来定义一个Raw String,如果要定义的字符串中包含需要进行转义的字符时,使用Raw StringString要方便一些。

比如需要定义一个字符串,来保存{"gender":"男","name":"zhaiyz"},如果使用基本的字符串定义需要:

1
val stringJson = "{\"gender\":\"男\",\"name\":\"zhaiyz\"}"

字符串中的"需要使用\"进行转义,如果使用Raw String的方式进行定义需要:

1
val rawStringJson = """{"gender":"男","name":"zhaiyz"}"""

字符串中的"不需要再进行处理,以上两种方式的结果是等价的,但是明显使用Raw String的更加方便且可读性高。

阅读全文 »

开发中经常需要定义一些POJO,里面只有基本字段及对应的setter/getter方法。比如以下代码是使用Java定义一个包含姓名、生日两个字段的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class User {

private String name;

private Date birthday;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Date getBirthday() {
return birthday;
}

public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}

如果使用Kotlin定义相同功能的类只需要以下代码:

1
2
3
4
5
6
class User {

var name: String? = null

var birthday: Date? = null
}

可以看出Kotlin定义简洁了很多。
在Java中namebirthday叫作field,而在Kotlin中叫作property。使用var定义的property直接可以通过变量名进行赋值和取值。以下代码可以初始化一个User对象:

1
2
3
4
5
6
fun main(args: Array<String>) {
val user = User()
user.name = "zhaiyz"

println("User: name = ${user.name}")
}

输出:

1
User: name = zhaiyz

可以看出来,使用起来很方便。

阅读全文 »

在Kotlin中进行一些字符串拼接的时候,使用字符串模板会很简单。以$开始,直接根上变量名或是用{}包含表达示即可。代码示例:

1
2
3
4
5
fun main(args: Array<String>) {
val name = "world"
println("Hello $name!")
println("Hello ${name.capitalize()}!")
}

输出:

1
2
Hello world!
Hello World!

如果想直接输出$,那么需要对$进行转义,使用\$
代码:

1
println("Hello \$name!")

输出:

1
Hello $name!

字符串模板只是Kotlin的语法糖,println("Hello $name!")对应的字节码反编译为Java代码,相当于String var2 = "Hello " + name + "!";,只是方便了使用。

在开发中,经常用到把一个List按一定规则转换为Map来使用。本文就介绍下几种常用的转换方式。
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
data class User(val id: Long, val name: String, val age: Int)

fun main(args: Array<String>) {

val users = listOf(User(1, "张三", 20), User(2, "李四", 20), User(3, "王五", 25), User(4, "赵六", 25))

// 变为以id为key, user为value的map,类型为Map<Long, User>
println(users.associateBy { it.id })

// 变为以id为key,name为value的map,类型为Map<Long, String>
println(users.associate { it.id to it.name })

// 可以自定义key和value的map,类型为Map<String, String>
println(users.associateBy({ "id:${it.id}" }, { "name:${it.name}" }))

// 生成按age聚合,对象List为value的map,类型为Map<Int, List<User>>
println(users.groupBy { it.age })
}

输出:

1
2
3
4
{1=User(id=1, name=张三, age=20), 2=User(id=2, name=李四, age=20), 3=User(id=3, name=王五, age=25), 4=User(id=4, name=赵六, age=25)}
{1=张三, 2=李四, 3=王五, 4=赵六}
{id:1=name:张三, id:2=name:李四, id:3=name:王五, id:4=name:赵六}
{20=[User(id=1, name=张三, age=20), User(id=2, name=李四, age=20)], 25=[User(id=3, name=王五, age=25), User(id=4, name=赵六, age=25)]}

转成的Map其实都是LinkedHashMap,看输出的结果也可以看出来,生成的Map中的对象顺序和List中的一致。
当key的重复的时候,后面的值覆盖前面的值。比如添加一行代码:

1
println(users.associateBy { it.age })

来使用age字段当作key,其中id为1和2的age重复,id为3和4的age重复,生成map的时候,会保留下id为2和4的,id为1和3的值被覆盖了。此行代码的输出为

1
{20=User(id=2, name=李四, age=20), 25=User(id=4, name=赵六, age=25)}

Kotlin与Java相比有一个很高级的特性,就可以扩展方法。可以直接为一个类的所有对象添加方法。
比如以下代码可以为所有String类型对象添加一个printIt()方法,调用时打印其本身。

1
2
3
fun String.printIt() {
println(this)
}

以上代码可以简写为

1
fun String.printIt() = println(this)

使用方式如下

1
2
3
fun main(args: Array<String>) {
"Hello world!".printIt()
}

输出:Hello world!
在扩展方法里面this为调用者本身。

阅读全文 »

Kotlin中参数是可以设置默认值的,设置默认值的参数,如果没有传就使用默认值。
示例代码,保存在Funs.kt中:

1
2
3
fun sayHello(name: String = "world") {
println("Hello $name!")
}

调用以上代码时,可以有两种方式,如下:

1
2
3
4
fun main(args: Array<String>) {
sayHello()
sayHello("zhaiyz")
}

输出:

1
2
Hello world!
Hello zhaiyz!

sayHello()没有传参,name就使用world做为值,如果传入了参数,就使用参数值。

但是以上方法在Java中调用的时候,只有sayHello(String name)方法,如果想在Java中使用不传默认参数的方法,需要在方法上加上@JvmOverloads,这样Kotlin编译的时候,会生成一个不需要当前默认值的重载方法,之后就可以在Java中使用没有默认参数的方法了。

阅读全文 »

Kotlin与Java最大的不同之一就是函数可以不需要定义在类中。本文就介绍下Kotlin的包级函数。

Kotlin中定义一个包级函数很简单:

1
2
3
4
5
package com.zhaiyz.demo

fun sayHello(name: String) {
println("Hello $name!")
}

把以上内容保存在Funs.kt中。
在Kotlin中使用包级函数:

1
2
3
4
5
import com.zhaiyz.demo.sayHello

fun main(args: Array<String>) {
sayHello("world")
}

可以import对应包下面的函数,直接使用。
在Java中使用Kotlin的包级函数:

1
2
3
4
5
6
7
8
import com.zhaiyz.demo.FunsKt;

public class Demo {

public static void main(String[] args) {
FunsKt.sayHello("world");
}
}

因为Java中函数必须通过类或对象调用,Kotlin的包级函数在Java中使用要通过Kotlin包级方法所在的文件名+Kt作为类引入,再进行调用,相当于使用静态函数。

Kotlin中的main函数,也是一个特殊的包级函数,可以做为程序的入口。

开发过程中经常要写一些工具类,里面定义一些静态方法。本文介绍下在Kotlin中定义静态方法的方式。
可以使用以下两种方式:

  1. 使用object,比如:
    1
    2
    3
    4
    5
    object Utils {
    fun sayHello(name: String) {
    println("Hello $name!")
    }
    }
  2. 使用companion object
    1
    2
    3
    4
    5
    6
    7
    class Utils {
    companion object {
    fun sayHello(name: String) {
    println("Hello $name!")
    }
    }
    }
    在Kotlin中使用调用方式是一样的:
    1
    2
    3
    fun main(args: Array<String>) {
    Utils.sayHello("world")
    }
    在Java中调用时,如果使用object
    1
    2
    3
    public static void main(String[] args) {
    Utils.INSTANCE.sayHello("world");
    }
    如果使用companion object
    1
    2
    3
    public static void main(String[] args) {
    Utils.Companion.sayHello("world");
    }

开发中会遇到一些需要对小数进行格式化的地方,这时可以使用DecimalFormat。此文记录一个使用DecimalFormat格式化小数时的一个注意事项。

比如现在有两个小数1.251.15,需要四舍五入保留一位小数。可以使用以下kotlin代码:

1
2
3
4
5
6
7
fun main(args: Array<String>) {
val number1 = 1.25
val number2 = 1.15
val decimalFormat = DecimalFormat("0.0")
println(decimalFormat.format(number1))
println(decimalFormat.format(number2))
}

但是以上代码的输入为:

1
2
1.2
1.2

和预期的不一样。这是因为DecimalFormat默认的RoundingModeRoundingMode.HALF_EVEN。API中的解释为:

1
Rounding mode to round towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor. Behaves as for RoundingMode.HALF_UP if the digit to the left of the discarded fraction is odd; behaves as for RoundingMode.HALF_DOWN if it's even.

如果要四舍五入,需要显示的设置RoundingModeRoundingMode.HALF_UP,最终代码为:

1
2
3
4
5
6
7
8
fun main(args: Array<String>) {
val number1 = 1.25
val number2 = 1.15
val decimalFormat = DecimalFormat("0.0")
decimalFormat.roundingMode = RoundingMode.HALF_UP
println(decimalFormat.format(number1))
println(decimalFormat.format(number2))
}

以上代码的输入为:

1
2
1.3
1.2

符合预期。