一. kotlin是什么?
kotlin是一种运行在java虚拟机上的静态编程语言,2011年,JetBrains推出了kotlin项目,2016年2月15日正式发布了第一个官方稳定版本V1.0,2017年在google I/O大会上,google正式宣布kotlin成为Android官方开发语言。
二、基本数据类型:
1、java基本数据类型
byte、short、int、long、float、double、char、boolean。
定义:int i = 0;
2、kotlin基本数据类型
Double、Float、Long、Int、Short、Byte、Char、Boolean。
定义:var i : Int = 0;//成员变量必须初始化
3、方法
fun method(arg:Int):Int{
return 0
}
void->unit
类
所有类的基类是Any,类定义:
public class A{}//类
open class A{}//类A 可继承,否则不可继承
class C:A(){}//c继承A,A必须是open
接口
interface TestInterface{
}
class C:TestInterface{}//实现接口,多个使用,分割
三、 优势
1、空指针问题
java示例:
public class Person {
private List<Address> mAddressList;
public static void main(String[] args) {
Person person = new Person();
if (person.mAddressList != null) {//1层判空
for (Address address : person.mAddressList) {
if (address != null){//二层判空
if (address.address1 != null){//三层判空
System.out.println(address.address1.length());
}
}
}
}
}
}
class Address {
String address1;
}
kotlin代码实现:
class Person1 {
var mAddressList: List<Address?>? = null//不再需要分号
}
class Address {
var address1: String? = null
}
//方法 fun关键字,如果有返回值,加在方法名后面
fun main(args: Array<String>) :Unit {
val person = Person1()
person.mAddressList?.forEach {
println(it?.address1?.length)
}
}
说明:
(1)kotlin提供具体类型+?的类型,可以允许对应变量为null
(2)通过?.操作符可以解决空指针问题。
这种情况可以动态避免空指针问题,即在执行过程中避免。
(3)kotlin同时提供强制非空类型定义,如果违背,编译期间就会报错,如下所示:
class Address {
var address1: String? = null
fun setAddress(address: String) {//不允许为空
//这里使用address就不需要判空,一定不为空
print(address.length)//正确
}
fun setAddress2(address2:String?){//运行为空
//这里使用address就需要判空,可能为空
print(address2.length)//编译器报错,无法这么调用
print(address2?.length)//正确,为null时打印null
print(address2!!.length)//正确,为null时强制crash
}
}
fun main(args: Array<String>) {
val address = Address()
var value:String? = null
address.setAddress(value)//编译错误
address.setAddress2(value)//编译通过
}
kotlin对于为null的对象,同时提供强制抛出异常的机制,如下:
val person:Person1? = null
person?.address//person为null时不执行后续代码
person!!.address//person为null时,抛出空指针异常
kotlin空指针潜在的问题
假如Person是java代码,kotlin调用上述java代码,示例:
fun main(args: Array<String>) {
val person = Person()//Person是java代码
person.mAddressList.forEach {//此时编译器并不会提示mAddressList可能为null !!
println(it.address1.length)//任何一个环节空指针都会打印空
}
}
纯kotlin代码本身存在的可能潜在的空指针问题
//kotlin中,所有的类默认都是不可继承的,除非使用open关键字修饰,这里因为使用了
//abstract,默认为open,所以没有加上
abstract class Person1 {
abstract val address: Address
init {
address.toString()//空指针 crash
}
}
class Student() : Person1() {
override val address: Address = Address()
}
class Address//可以没有{}
fun main(args: Array<String>) {
val person = Student()
}
2、数据类
在java中通常会定义一些纯粹保存数据的类,比如android中常见的对应于json的java对象,如下所示:
//java数据类代码
public class Person {
public String name;
public String address;
public int age;
//......
}
kotlin为我们提供了对应的data类,
data class Person1(var name: String, var age: Int, val address: String)
数据类的优势:
1、数据类重写了toString方法
2、数据类重写了equals和hasCode方法
3、数据类提供了copy方法
4、数据类提供了componetN方法
3.单例
object SingleInstance {//使用object来声明一个单例对象
}
对应于java中的单例代码:
//kotlin单例对应的java单例的写法
public class SingleInstance {
private SingleInstance() {
}
public final static SingleInstance INSTANCE = new SingleInstance();
}
伴随对象
class MyClass {//类比于java的static
companion object {//这就是伴随对象的定义
fun test() {}
}
}
//测试类
class Main {
companion object {
@JvmStatic//会被编译成真正的static方法
fun main(args: Array<String>) {
MyClass.test()//伴随对象的调用
MyClass.Companion.test()//你也可以通过这种方式调用
}
}
}
4.扩展
kotlin扩展如下所示:
fun String.lastChar(): Char {//这里为String定义了一个扩展方法,该方法的功能就是获取字符串的最后一个字符
return this[this.length - 1]//注意这里使用了this
}
//测试类,提供main方法
class Main {
companion object {
@JvmStatic fun main(args: Array<String>) {
println("hello".lastChar())//注意这里,打印'o'
}
}
}
扩展解决的问题是java中大量的util类的问题,如:
import java.util.Collections;
Collections.swap(list, Collections.binarySearch(list
, Collections.max(anthoerList)), Collections.max(list));
代码很啰嗦,通过扩展可以简化如下:
list.swap(list, binarySearch(list)
, max(athoerList), max(list));
实际上是将util工具类完成的功能,回归类型本身。
5.强大的表达式、操作符、库方法
(1)if-else表达式
相较于java,除了完成正常的条件判断外,if-else可以做为表达式:
min = if (a < b) a else b//作为表达式使用
(2)when表达式
val a = -1
when (a) {
1 -> println("a == 1")//注意,这即表示一个匹配条件,类似于switch中的case
-1 -> println("a == -1")
0 -> println("a == 0")
else -> {//类似于switch中的default
print("a not match...")
}
}
(3)强大的函数:let、with、run、apply、also
let:
fun main(args: Array<String>) {
var person: Person1? = null
//不使用let
person?.address
person?.age
person?.name
//使用let: 针对一个可null的对象统一做判空处理
person?.let {//最后一条语句作为返回值
it.age
it.address
it.name
}
}
with:
fun main(args: Array<String>) {
var person: Person1 = Person1("", 0, "")
with(person) {//可以省略具体的对象,最后一条语句作为返回值
name
age
address
}
}
run:
var person: Person1 = Person1("", 0, "")
person.run {//run方法实际上结合了with和let,最后一条语句作为返回值
name
age
address//address作为返回值
}
apply
var person: Person1 = Person1("", 0, "hha")
var result = person.apply {//返回值为对象本身,故可以链式调用
name//省略it
}.apply {
address
}.apply {
age
}
also
var result = person.also {//和let很像,不过返回值为对象本身,可以链式调用
it.name//必须使用it指代,
}.also {
it.address
}
println(result)
map
var map = mapOf(//只读
"key1" to "value1",
"key2" to "value2"
)
//map的遍历,很简单
map.forEach { key, value -> println("key: $key, value: $value") }
var mutableMap = mutableMapOf(
"key1" to "value1"
)
mutableMap.put("ke2", "value2")
mutableMap.put("ke3", "value2")
//可以过滤
val size = mutableMap.filterValues { it.equals("value2") }.size
print(size)
}
arr
var arr = arrayOf("1",2,3)
arr[1] = 4
arr.forEach {
print(it)
}
list
val list = listOf("1","2",3)
list.forEach {
print(it)
}
val list2 = mutableListOf("1", 2)
list2.add(3)
list2.plus(list)
list2.forEach {
print(it)
}
6.高阶方法和lambda表达式
在kotlin中,方法是一等公民。什么是一等公民?翻译成编程语言对应的意思就是:kotlin中的方法同一般的变量一样,可以作为方法参数、可以赋值给其他变量等等。
(1)高阶方法
高阶方法是指,那些入参类型包含方法类型或者返回值是个方法类型的方法。
fun sayHello(str: String, checkStr: (str: String) -> Boolean) {
if (checkStr(str)) {
println("pass...")
} else {
println("error...")
}
}
(2)lambda表达式
他们所表达的场景就是,在没有显示定义方法的时候,我们可以通过这种方式生成一个具有同等形式、功能的方法。
val testStr2 = "test"
//调用前面的sayHello
sayHello(testStr2, { str -> str.isNotEmpty() })//打印'pass...'
//相当于
fun checkStr(str: String): Boolean {
return str.isNotEmpty()
}
//lambda表达式作为方法最后一个参数时还可以放在外部
sayHello(testStr2) { str -> str.isNotEmpty() }//打印'pass...'
lambda语法:
//直接给sum赋值一个方法类型实例,等于后面就是标识的lambda表达式
val sum = { x: Int, y: Int -> x + y }
//也可以显示定义sum的类型为(Int,Int)->Int的方法类型
val sum: (Int, Int) -> Int = { x, y -> x + y }
7.inline方法
//此时方法m1就是内联方法,使用了inline关键字修饰
inline fun m1() {
println("hello world")
}
//测试方法
fun test() {
m1()
}
}
8.中缀方法
//我们为Int类定义了一个中缀方法sum
infix fun Int.sum(i: Int): Int = this + i
fun main(args: Array<String>) {
println(1 sum 2)//调用sum中缀方法
}
解构和ranges
解构
//必须是data类,data类提供了componentN方法
data class Person1(var name: String, var age: Int, val address: String) {
}
val person:Person1 = Person1("name", 1, "address")
val (name, age) = person//字段顺序不能变
ranges
fun main(args: Array<String>): Unit {
val i = 0
for (i in 1..10) {
print(i)
}
val j = 0
for(j in 10 downTo 2){
print(j)
}
val k = 0
for (k in 10 downTo 1 step 3){
print(k)
}
val h = 0
for (h in 10 until 3){
print(h)
}
}
协程
fun main(args: Array<String>) = runBlocking {
GlobalScope.launch {//top-level级别的
delay(1000L)
println("world!")
}
println("hello ")
delay(2000L)
}