一.Kotlin之基础语法

一.kotlin相比于java:

java:

1.语法表现力差,例如:java1.8之前不支持lambda表达式,匿名内部的写法繁琐,在函数方面,不支持高洁函数,不支持参数默认值,也不支持函数命名参数。

2.可读性差,难维护 例如:java中的Callback嵌套多层的话,代码可读性就特别差,对维护更加困难

3.并发编程:在java 中,线程的并发以及它复杂的同步机制导致学习成本高。

总结:前期开发效率低,中期线上问题多,后期代码难维护

kotlin:

1.kotlin具有更加简洁的语法跟现代化语法特性,大大提高开发效率,线上奔溃率降低,java中的空指针问题也几乎可以避免

2.兼容性强:kotlin可以跟java混编,大部分旧的项目都是java开发,kotlin强大的兼容性可以让我们渐进的从java迁移到kotlin,不用一次性重写很多代码,从而产生新的问题

3.谷歌宣布kotlin成为官方语言后,现在各大招聘android,都会写着熟悉kotlin的优先,所以koltin我觉得是有非常好的前景的,赶紧入坑。

变量

在java中,如果我们要声明变量,我们必须声明它的类型,后面跟着变量的名称和对应的值,然后以分号结尾。就像这样:

int price = 100;  

String msg = "我是msg";

而kotlin则不一样,我们要使用 val 或者是 var这样的关键字作为开头,后面跟“变量名称 -> price ”,接着是变量类型 ->Int 和赋值语句 ,

如下:

var price : Int  = 100 ;

在kotlin 中,一般会把末尾的分号省略掉

var price : Int  = 100 

还有一点我们要注意,在kotlin中,我们应该尽可能的避免使用var ,尽可能多的去使用val。

var 跟 val 的区别

var  price = 100  price = 101   //编译通过

val  price  = 0   price =101 //编译器报错

原因很简单,val声明的变量,我们叫不可变变量,它的值在初始化后就不能再次被修改,它相当于java中的 final 变量。

var声明的变量,我们叫可变变量,它对应java中的普通变量

基础类型

基础类型:包括我们常见的数字类型,布尔类型,字符类型。以及这些类型组成的数组

一切皆对象

在java中,基础类型会分为原始类型和包装类型。比如整型会有对应的int 和 Integer,前者是原始类型,后者是包装类型

int i = 0 ;//原始类型

Integer  i = 1 ;//包装类型

java之所以要这么做,是因为原始类型的开销小,性能高,但它不是对象,无法很好的融入到面向对象的系统中。而包装类型的开销大,性能相对较差,但它是对象,可以很好的发挥面向对象的特性。

然而在kotlin语言体系中,是没有原始类型这个概念的,这就意味着,在kotlin里,一切都是对象

实际上,从某种程度上讲,Java 的类型系统并不是完全面向对象的,因为它存在原始类型,而原始类型并不属于对象。而 Kotlin 则不一样,它从语言设计的层面上就规避了这个问题,类型系统则是完全面向对象的。

Val i :Double = 1.toDouble()

可以发现,由于在kotlin中,整型数字“1”被看作对象了,所以我们可以调用它的成员方法toDoubel(),而这样的代码在java是无法实现的。

空安全

既然kotlin 中的一切都是对象,那么对象就有可能为空。也许你会想到写出这样的代码:

 val i :Double = null //编译器报错

可事实上,以上的代码是不能通过编译。这是因为kotlin强制开发者在定义变量的时候,指定这个变量是否可能为null 。对于可能为null的变量,我们需要在声明的时候在变量类型后面加一个问号“?”:

   val i :Double = null //编译器报错 

   val j :Double? = null //编译通过

并且kotlin 对可能为空的变量类型做了强制区分,这就意味着,“可能为空的变量”无法赋值给“不可能为空的变量”,当然,反向赋值是没有问题的

 var i :Double  = 1.0

 var j :Double = null

 i = j  //编译器报错

 j = i //编译通过

不过如果你有这种需求的话,也是可以做的:

var i :Double = 1.0 

var j : Double = null 

If( j !=  null ) i = j // 编译通过

数字类型

首先,在数字类型上,kotlin 跟 java 几乎是一样的,包括它们对数字“字面量” 的定义方式。

   val int = 1 // 整型默认会被推导成“Int” 类型

   val long = 12345L   // Long类型,我们则需要使用 “L” 后缀

  val double = 13.14  // 小数默认会被推导为 “Double ” ,我们不需要使用“D”后缀

  val float = 13.14F  // Float 类型, 我们需要使用 “F” 后缀

  val hexadecimal = OxAF。//使用“Ox” 来代表十六进制字面量

  val binary = Ob01010101  //使用“Ob”,来代表二进制字面量

数字类型的转换在 java 是可以隐式转换数字类型,而kotlin更推荐显示转换

例如 int 类型赋值给long类型,编译器会自动为我们做类型转换

int j =100;

long j  = i ;

按照java的思维来看,好像是没有问题的,但是你要注意,虽然java编译器不会报错,可它可能会带来问题,因为它们本质不是同一个类型,int long float double 这些类型之间的互相转换是会存在精度问题的,尤其这样的代码掺杂在复杂的逻辑中,在碰到一些边界条件下,即使出现了bug 也很难排查出来 

所以在kotlin中 在像这样的隐式转换是被抛弃了。 正确的做法是使用显式调用Int类型的toLong()函数

val i = 100

 val j :Long = i.toLong( )

还有比如 toByte()、toShort()、toInt()、toLong()、toFloat()、toDouble()、toChar() 等等。Kotlin 这样设计的优势也是显而易见的,我们代码的可读性更强了,将来也更容易维护了

布尔类型 

kotlin 布尔类型的变量 只有两种值 true 和false 布尔类型还支持一些逻辑操作,比如:

“&”代表“与运算”;“|”代表“或运算”;“!”代表“非运算”;“&&”和“||”分别代表它们对应的“短路逻辑运算”。

val i = 1

val j = 2

val k = 3

val isTrue: Boolean = i < j && j < k

字符:Cher

Char 用于表达单个字符 比如'A'. 'B'字符应该用单引号括起来

字符串 :String

字符串用于表达一连串的字符,和java一样,kotlin的字符串也是不可变的,一般用双引号

kotlin还提供非常简洁的字符串模板:

val name = "kotlin"

print("Hello $name!")

在java中我们需要使用两个“+”进行拼接

print("Hello" + name + "!" )

这样看是不是简洁了许些,在字符串格式更复杂的情况下,更能体现出这个特性的简洁

如果我们需要在字符串当中引用更复杂的变量,则需要使用花括号将变量括起来:

val array = array("java","kotlin")

print("Hello ${ array.get( 1 ) } ! " )

Kotlin 还新增了一个原始字符串 ,用三个引号表示:"""  

它可以用来存放复杂的多行文本,并且它定义的时候是什么格式,打印也是对应的格式,不需要跟java写一堆的加号和换行符。 

                val s = """
       当我们的字符串有复杂的格式时
       原始字符串非常的方便
       因为它可以做到所见即所得。 """

        print(s)  

数组

在kotlin中,我们一般会使用 arrayOf()来创建数组

val arrayInt = arrayOf(1,2,3)

val arrayString = arrayOf("apple","pear")

同时kotlin编译器也会根据传入的参数进行类型推导,比如针对这里的arrayInt,由于我们赋值的时候传入的是整数,所以它的类型会被推导为整形数组。

在java中,获取数组的长度,java中应该使用"array.length", 如果是获取List的大小则是使用"list.size".这主要是因为数组不属于java集合。

不过在kotlin中,虽然数组仍然不属于集合,但它的一些操作是跟集合统一的。

val arrayString = arrayOf("apple","pear")

println("Size is ${array.size}")

println("First element is ${array[0]}")

//输出

Size is 2

First element is apple

如上面的代码,我们直接使用array.size就能拿到数组的长度

函数声明

我们看一下以下的代码:

/*
关键字    函数名          参数类型   返回值类型
 ↓        ↓                ↓       ↓      */
fun helloFunction(name: String): String {
    return "Hello $name !"
}/*   ↑
   花括号内为:函数体
*/

在这段代码中:

  • 使用了fun关键字来定义函数
  • 函数名称。使用的是驼峰命名法
  • 函数参数是以参数名在前,参数类型在后的写法
  • 返回值类型,紧跟参数后面

在上面的代码,你会发现它的函数体只有一行代码,针对这种其实我们可以省略函数体的花括号,直接使用  ‘ = ’ 来连接,如下

fun helloFunction(name:String):String = "Hello $name !"

这种写法,我们称为单一表达式函数。

另外,由于kotlin支持类型推导,我们可以把返回值的类型也省略掉:

fun helloFunction(name:String) = "Hello $name !"

函数调用

如果我们想调用它:

heeloFunction("kotlin")

不过,kotlin还提供一些新的特性,那就是命名参数,简单来说,就是它允许我们在调用函数时传入“形参的名字”。

helloFunction(name = "kotlin")

让我们看一下更具体的使用场景:

fun createUser( name: String,

 age: Int,

 gender: Int, 

friendCount: Int, 

feedCount: Int, 

likeCount: Long, 

commentCount: Int) { 

//.....省略

}

这是一个包含很多参数的函数,在kotlin中,我们一般提倡以纵向的方式排列,这样更符合我们的阅读习惯

但是,如果我们像java那样调用createUser ,代码会非常难以阅读:

createUser("Tom ",30,1,78,2093,10937,1211)

这里的第一个参数,我们知道肯定是name ,但是到了后面的一堆数字,就容易迷惑。

createUser(
    name = "Tom",
    age = 30,
    gender = 1,
    friendCount = 78,
    feedCount = 2093,
    likeCount = 10937,
    commentCount = 3285
)

如果我们这样写的话,可读性是不是变得更加强了呢。这里体现出kotlin命名参数的可读性跟易维护性两个优势

除了命名参数这个特性,kotlin还支持参数默认值。

fun createUser(
    name: String,
    age: Int,
    gender: Int = 1,
    friendCount: Int = 0,
    feedCount: Int = 0,
    likeCount: Long = 0L,
    commentCount: Int = 0
) {
    //..
}

我们可以看到,里面的 参数大部分都被赋予了默认值,这样的好处在于,我们在调用时候就可以省很多事情,比如,下面这段代码只需要传3个参数,剩下的4个参数不传,编译器就会自动帮我们填上默认值。

createUser(
    name = "Tom",
    age = 30,
    commentCount = 3285
)

流程控制

在kotlin中,流程控制主要有 if ,when,for ,while 

if

if主要用于逻辑判断。跟java基本一致

val i = 1
if (i > 0) {
    print("Big")
} else {
    print("Small")
}

输出结果:
Big

我们也可以这样写:

val message = if (i > 0) "Big" else "Small"

print(message)

另外,由于kotlin明确规定类型分为 “可空类型” 跟“不可空类型”,因此,我们会经常遇到可空的变量,并且要判断它们是否为空:

fun getLength(text: String?): Int {
  return if (text != null) text.length else 0
}

在这个例子中,我们把if当成表达式,如果text不为空,就返回它的长度,如果为空,则返回0

在kotlin中,类型这样的逻辑判断出现的很频繁,因此,kotlin针对这种情况提供一种简写,叫做Elvis表达式

fun getLength(text: String?): Int {
  return text?.length ?: 0
}

when 

when语句,一般我们的逻辑只有两个分支时候,我们直接用if/else,而大于两个逻辑分支,我们使用when

 val i :Int  =1 

when( i ){

1 -> print("1")

2 -> print ("2")

else -> print("i 不是1也不是2")

}

when语句有点像java里面的 switch case语句,不过kotlin的when更加强大,它也可以作为表达式,为变量赋值:

val i :Int  =1 

val  message  = when( i ){

1 -> "一"

2 -> "二"

else -> print("i 不是1也不是2")

}

println(message)

循环迭代:while 与 for

首先while循环,它在使用上跟java没有什么区别,都是用于重复执行某些代码

var i = 0
while (i <= 2) {
    println(i)
    i++
}

var j = 0
do {
    println(j)
    j++
} while (j <= 2)

输出结果:
0
1
2
0
1
2

for

但是对于for语句,kotlin跟java的用法就不一样了。

kotlin的for语句更多用于“迭代” 如下代码就代表迭代array这个数组里的所有元素,程序会依次打印出 “1,2,3”。

val array = arrayOf(1, 2, 3)
for (i in array) {
    println(i)
}

除了迭代数组跟集合外,kotlin还支持迭代一个区间。

首先,我们要定义一个区间,可以使用“..”来连接数组的区间的两端,比如“1..3”就代表从1到3的封闭间,左闭右闭

val oneToThree = 1..3 //代表[1,3]

接着,我们可以使用for语句,对这个闭区间范围进行迭代:

for (i in oneToThree) {
    println(i)
}

输出结果:
1
2
3

甚至,我们可以逆序迭代一个区间,比如:

for (i in 6 downTo 0 step 2) {
    println(i)
}

输出结果:
6
4
2
0

以上代码的含义就是逆序迭代一个区间,从6到0,每次的迭代的步长是2。需要注意的是,逆序区间我们不能使用“6..0”来定义。而是使用downTo

你可能感兴趣的:(Android,安卓,kotlin,Android,安卓,kotlin)