基础语法
1.包定义
package my.demo
包定义在顶部,与Java语法一样,但需要注意的是,目录和包的结构无须匹配,但是最好匹配,不然一堆坑
2.函数定义
fun sum(a:Int,b:Int){
return a+b
}
函数使用_fun_定义,变量名在前,变量类型在后,也可以将表达式作为函数体,返回值会自动推断
fun sum(a:Int,b:Int) = a+b
函数可以返回一个无意义的值(类似于返回一个空值或无返回值或返回一个Null,而Kotlin这里返回一个Unit类型的无意义的值),若返回一个有意义的值的话,将返回值类型写到函数后面,类似于fun sum():Int {}
。kotlin中支持以占位符的形式输出语句(字符串模板),不需要类似于logback使用{},使用**$变量**方式,但是这种方式适合于测试,因为底层仍然使用的String.valueOf,调用toString方法去输出,使用logback等日志框架的时候,可以延迟构建日志信息的开销(String),提高程序性能
fun printSum(a:Int,b:Int):Unit{
println("sum of $a and $b is ${a+b}")
}
Unit这个返回类型可以省略掉,如下所示
fun printSum(a:Int,b:Int){
println("sum of $a and $b is ${a+b}")
}
3.变量定义
分为不变和可变变量,分别使用val和var来定义(val更加类似于静态变量,但能否通过类名.变量名来调用,未测试)
//不变变量
val a: Int = 1 //立即赋值
val b = 2 //自动推断出Int类型
val c: Int //如果没有初始值,类型不能省略
c = 3 //明确赋值
//可变变量
var x = 5
5 += 1
//顶层变量,类似于全局变量
val PI = 3.14
var x = 0
fun incrementX(){
x += 1
}
4.注释
与java注释一样,但kotlin的块注释可以嵌套,类似于这样
/**
* hhhh
* /**
* fff
* /**
* ggggg
* */
* */
*
* abc
*
*/
5.字符串模板
上面说过一些,这里补充下,字符串模板中支持模板表达式,类似于这样
var s1 = "try again or walk way"
val s2 = "${s1.replace("or","and")} , ${s1.length}"
6.条件表达式
类似于这样
fun maxOf(a:Int,b:Int):Int{
if(a>b){
return a
}else {
return b
}
}
也可以这样,因此在kotlin中并没有三目运算符,if就能做到
fun maxOf(a:Int,b:Int) = if (a>b) a else b
还可以作为代码块使用
val max = if(a>b){
println("Choose a ")
a
}else{
println("Choose b ")
b
}
7.null检测
kotlin中,变量的声明,默认都是不能为空的,如果该变量可以为空,则必须在类型后加**?**表示该引用可以为空。如果该变量标注了可以为空,则在使用该变量的一些方法时,会编译不通过。必须进行null判断,而在null判断之后,该变量会自动转换为非空值。如下所示
fun printProduct(x:Int?,y:Int?){
//因为x和y有可能为null,因此必须进行null判断
if(x != null && y != null){
// 在空检测后,x 和 y 会自动转换为非空值(non-nullable)
println(x*y)
}else{
println("either '$arg1' or '$arg2' is not a number")
}
}
kotlin中没有三目运算符,但是有些地方类似三目运算,使用起来比三目运算符更方便
例如:
val l = b?.length ?: -1
如果**??*左侧表达式非空,就返回左侧表达式,否则返回右侧表达式
8.类型检测以及自动类型转换
使用is检测一个表达式是否是某类型的一个示例, 如果一个不可变的局部变量或属性已经判断出为某类型,那么检测后的分支中可以直接当作该类型使用,无需显式转换,例如
fun getStringLength(obj:Any):Int?{
if(obj is String){
//在当前条件分支内obj自动转换为String
return obj.length
}
return null
}
或
fun getStringLength(obj:Any):Int?{
if(obj !is String) return null
//当前分支自动转换为String
return null
}
或
fun getStringLength(obj: Any): Int? {
// `obj` 在 `&&` 右边自动转换成 `String` 类型
if (obj is String && obj.length > 0) {
return obj.length
}
return null
}
注:Any表示任何类型(Anything),类似于Java中的Object
9.for循环
类似于python
val items = listOf("apple","banana","kiwi")
for(item in items){
println(item)
}
或
fun main(args: Array<String>) {
val items = listOf("apple", "banana", "kiwi")
//indices表示该list的下标数组
for (index in items.indices) {
println("item at $index is ${items[index]}")
}
}
甚至这样
//可以直接遍历对象中的属性,编译时候会优化,不会产生额外对象
for((index,value) in array.withIndex()){
println("the element at $index is $value")
}
10.while循环
while 和 do-while与Java一样
11.when表达式
类似于Java中的switch-case语句,但是比其更强大,更好用
when(x){
1 -> print("x == 1 ")
2 -> print("x == 2 ")
else ->{
print("x is neither 1 nor 2")
}
}
一般情况下when必须有else分支,但是如
果编译器能够检测出所有的情况都已经覆盖,则可以不加else分支
when可以使用任意表达式作为分支条件,而不只是常量,甚至还可以使用in,is,fun等表达式,这是相对Java来说很好的一个方面,例如
when(x){
in 1..10 -> println("x is in the range")
in validNumbers -> println("x is valid")
!in 10..20 -> println("x is outside the range")
is String -> println("x is String")
else -> print("none of the above")
}
when可以用来取代if-else,若不提供条件,则为真的时候执行该分支
12.区间
类似于python,基础语法如下
//基础
for(x in 1..5){
println(x)
}
//在某个区间
if(x in 1..5){
println(x)
}
//不在某个区间
if(x !in 1..5){
println("x not exist 1..5")
}
//区间迭代
for(x in 1..100 step 2){
//step 表示步距为2
println(x)
}
in只适合于正序,若倒序的话需要使用
for(x in 5 downTo 1){
//downTo中也可使用step
println(x)
}
1…10指1-10这十个数字,如果需要包头不含尾的话,需要使用until,例如
for(i in 1 until 10){
println(i) //1-9
}
12.集合
集合初始化
val list = listOf("apple","banana","kiwi")
val set = setOf("apple","banana","kiwi")
//使用泛型规定map类型
val map = mapOf<String,Int>(Pair("1",21),Pair("2",53))
println(map.get("1"))
//map中有两个函数很好用,分别是getOrDefualt和getOrElse,如果map中没有找到key对应的value的话,就可以这么使用
map.getOrDefault("3", 99)
map.getOrElse("4", defaultValue = { 1 })
对集合进行迭代
for(item in items){
println(item)
}
用in判断集合是否包含某个示例
when{
"orange" in items -> println("juicy")
"apple" in items -> println("apple is fine too")
}
在kotlin中也可以使用类似于Java8的lambda表达式,因此可以这么做
list.filter{it.}
13.类和对象的基本使用
abstract class Shape(private val sides: List<Double>) {
val perimeter: Double get() = sides.sum()
abstract fun calculateArea(): Double
}
interface RectangleProperties {
val isSquare: Boolean
}
//这里省略了一个关键字constructor,相当于自动构建了Rectangle的主构造函数,如果构造函数中的所有参数都有默认值,则kotlin会多创建一个无参数的构造函数
class Rectangle(
//在idea中,变量会占据两个tab
private var height: Double,
private var length: Double,
) : Shape(listOf(height, length, height, length)), RectangleProperties {
//使用:来继承或实现接口,在kotlin中没有@Override注解,但是需要在方法前加一个override来标记为重写方法
override fun calculateArea(): Double = height * length
override val isSquare: Boolean get() = length == height
}
class Triangle(
private var sideA: Double,
private var sideB: Double,
private var sideC: Double
) : Shape(listOf(sideA, sideB, sideC)) {
override fun calculateArea(): Double {
var s = perimeter / 2
return Math.sqrt(s * (s - sideA) * (s - sideB) * (s - sideC))
}
}
fun main(args: Array<String>) {
val rectangle = Rectangle(5.0, 2.0)
val triangle = Triangle(3.0, 4.0, 5.0)
println("Area of rectangle is ${rectangle.calculateArea()}, its perimeter is ${rectangle.perimeter}")
println("Area of triangle is ${triangle.calculateArea()}, its perimeter is ${triangle.perimeter}")
}