第一行代码读书笔记(Chapter2 探究新语言,快速入门Kotlin编程)

准确来说,Java是解释性语言,Kotlin能被编译为class文件,再在虚拟机中运行

Kotlin几乎杜绝了空指针异常

运行Kotlin代码:IDEA创建Kotlin项目;在线运行kotlin代码;Android Studio创建一个main()函数

fun main() {
    println("Hello, world!!!")
}

2.3.1变量

Kotlin中定义一个变量,只允许valvar进行声明。

valvalue的简写)声明不可变的变量,对应Java中的final变量,不可二次赋值(地址)

varvariable的简写)用来声明一个可变的变量,对应Java中的非final变量。

Kotlin拥有出色的类型推导机制

var a=10       //整型
var b="hello"  //字符串

代码结尾不加分号

val a: Int = 10  //显示声明变量a为Int类

Kotlin中完全摒弃基本数据类型,全部使用对象数据类型

全部使用对象数据类型

全部使用对象数据类型

全部使用对象数据类型

Number是Kotlin内置抽象类,是Int、Long、Float、Double的父类

 

Java与Kotlin数据类型对照表

永远优先使用val来声明一个变量,而当val没有办法满足你的需求时再使用var。这样设计出来的程序会更加健壮,也更加符合高质量的编码规范

2.3.2 函数

函数==方法

main()函数是程序的入口函数

//入口函数
fun main() {
    println("Hello, world!!!")
}

//自定义函数
fun methodName(param1: Int,param2: Int):Int{
    return 0
}

fun:定义函数的关键字

参数格式: 参数名称:类型 paramName:Int

返回值类型:在参数括号后,不写则默认为void

import kotlin.math.max
fun main() {
    val a = 30
    val b = 43
    val value = largerNumber(a,b)
    println("larger number is "+value)
}
​
fun largerNumber(num1: Int,num2: Int):Int{
    return max(num1,num2)
}

语法糖:若函数中只有一行代码,Kotlin允许直接将该行代码写在函数定义尾部,并用等号连接。

= 表达了 return

//                                      = 表达 return
fun largerNumber(num1:Int,num2:Int):Int = max(num1,num2)

继续简化,让Kotlin自动推导返回类型

fun largerNumber(num1:Int,num2:Int) = max(num1,num2)

2.4 程序逻辑控制

顺序语句

条件语句:if 和 when

循环语句:

2.4.1 if条件语句

与Java相同的用法;略

if有返回值:

//每个条件的最后一行代码作为返回值
fun largerNumber(num1:Int,num2:Int):Int{
    val value = if(num1>num2){
        num1
    }else{
        num2
    }
    return value
}
//简化,直接返回
fun largerNumber(num1:Int,num2:Int):Int{
    return if(num1>num2){
        num1
    }else{
        num2
    }
}
//仅一行代码,继续简化
fun largerNumber(num1:Int,num2:Int) = if(num1>num2){
    num1
}else{
    num2
}

继续简化

fun largerNumber(num1:Int,num2:Int)=if(num1>num2) num1 else num2

2.4.2 when条件语句

when是为解决switch的痛点,并增加许多强大的新特性

when也有返回值

//精准匹配
when(param){
​
    匹配值 -> { 执行逻辑 }
    "Tom" -> 10  //当参数值为Tom时返回10
}
​
//类型匹配    is相当于Java中instanceOf关键字
when(param){
    is Int -> {}
    is Double -> {}
    else -> {}
}


//简化 前
fun getScore(name:String)=if(name == "Tom"){
    86
} else if(name =="Jim"){
    77
}else if(name == "Jack"){
    95
}else if(name == "Lily"){
    100
}else{
    0
}
//使用when简化
fun getScore(name:String) = when(name){
    "Tom" -> 86
    "Jim" -> 77
    "Jack" -> 95
    "Lily" -> 100
    else -> 0
}
fun checkNumber(num:Number){
    //类型匹配
    when(num){
        is Int -> println("number is Int")
        is Double -> println("number is Double")
        else -> println("number not support")
    }
}
//无参数的when语句
fun getScore(name:String) = when{
    //将条件表达式写在匹配值的位置,可对参数做一定的操作
    name.startsWith("Tom") -> 86
    name == "Jim" -> 77
    name == "Jack" -> 95
    name == "Lily" -> 100
    else -> 0
}

2.4.3 循环语句

while循环与Java一样

for循环不同

for-in循环

声明一个闭区间

val range = 0..10  //创建[0,10]的区间  闭区间
fun main() {
    //使用 for-in 循环遍历区间
    for(i in 0..10){
        println(i)
    }
}

开区间

val range = 0 until 10  //创建[0,10)的区间

step:设置步长,每次加几

fun main(){
    for(i in 0 until 10 step 2){
        println(i)
    }
}

..until 创建升序区间

降序区间downTo

fun main(){
    for(i in 10 downTo 1){
        println(i)
    }
}

2.5.1 类与对象

创建类Person:

class Person{
    var name = ""
    var age = ""
    
    fun eat(){
        println(name + " is eating. He is " + age +"years old.")
    }
}

实例化类:与Java的区别,去掉了new

val p = Person()  //表示调用了该类的构造函数
fun main(){
    val p = Person()
    p.name = "Jack"    // 为Person的实例化对象赋值
    p.age = 19
    p.eat()            // 调用方法
}

2.5.2 继承与构造函数

Effective Java这本书中明确提到,如果一个类不是专门为继承而设计的,那么就应该主动将它加上final声明,禁止它可以被继承。

继承

新建Student类

class Student{
    var sno = ""
    var grade = 0
}

要让Student类继承Person类,需要做两件事:

1.使Person类可以被继承

在kotlin中任何一个非抽象类默认不可被继承,相当于Java中给类加final

open关键字:在class之前加

open class Person{
    
}

2.继承:使用:

class Student : Person() {
    var sno = ""
    var grade = 0
}

()表示调用了构造函数

Kotlin中构造函数

主构造函数 和 次构造函数

主构造函数

默认都有一个不带参数的主构造函数,可显示指明参数,它没有函数体,直接定义在类名后

//         sno与grade字段在被初始化后不可变,故直接设置为val
//         主构造函数   将字段都放入其中   
class Student(val sno: String, val grade:Int) : Person(){
    
}

在实例化以上类时,必须传入构造函数中所有的参数

val student = Student("wu",59)   

构造函数中的参数创建实例时传入的,不需要重新赋值,因此我们可以将参数全部声明为val

主构造函数无函数体,若想在主构造函数中编写一些逻辑,可写在init结构体中

class Student(val sno: String, val grade: Int) : Person(){
    init{
        println("sno is "+sno)
        println("grade is "+grade)
    }
}

继承规定:子类 中的构造函数必须调用 父类 中的构造函数

如何体现调用了呢?括号()

改造Person为有参构造函数

open class Person(val name: String, val age: Int){
    ...
}

改造Student类

// 将父类的name,age属性作为参数,但不需要指定var或val
class Student(val sno: String, val grade: Int,name: String,age: Int) : Person(name,age){
    init{
        println("sno is "+sno)
        println("grade is "+grade)
    }
}

不能再将父类中的字段声明为val,因为在父类已经指定了。

次构造函数

一个类只能有一个主构造函数,但可以有多个次构造函数

次构造函数与主构造函数的区别:有函数体

Kotlin规定:一个类有主又有次,所有次必须调用主(包括间接调用:调用调用主的次构造函数)

次构造函数通过constructor关键词定义

这里定义两个次构造函数:

第一个接收name和age参数,通过this关键字调用主构造函数,并为主构造函数赋值

第二个不接收任何参数,通过this调用另一个次构造函数

class Student(  val sno: String,
                val grade: Int, 
                name: String,
                age: Int) :Person(name,age){
    constructor(name:String, age:Int):this("",0,name,age){}
    constructor(): this("",0){}
}

无主构造函数,仅有次构造函数,委派隐式发生,并执行块

class Person(val pets: MutableList<Pet>=mutableListOf())
​
class Pet{
    constructor(owner: Person){
        owner.pets.add(this)
    }
}
若类具有主构造函数,则次构造函数,则次构造函数中必须调用主构造,间接或直接

使用this()来调用主构造

即使类没有主构造函数,委派仍然隐式发生,并且仍然执行初始值设定项块:

class Constructors {
    init {
        println("Init block")
    }
​
    constructor(i: Int) {
        println("Constructor $i")
    }
}

且这个生成的 主构造函数的可见性 是公开的

若不希望它是公共的,就需要声明可见性

class DontCreateMe private constructor(){ }

2.5.3 接口

单继承,多实现

继承与实现都使用 : 来实现

接口后无()

实现接口就必须实现接口中所有抽象方法

支持多态

支持多个默认方法

函数的可见性修饰符

Kotlin中有4种,定义在fun前

public

所有类可见,在Kotlin中属于默认项

private

与Java一致,只在本类中可以访问

protected

在Kotlin中表示对当前类和子类可见

internal

只对同一模块内的类可见

 

2.5.4 数据类(实体类POJO)与单例类

数据类

在Java中一个实体类中,需要有构造方法,get/set方法,hashCode(),toString等

在Kotlin中只需一行代码 data

data class Cellphone(val brand: String, val price: Double)

只需在类之前加data,Kotlin会根据主构造函数中参数自动生成equals(),hashCode(),toString()等方法,减少开发工作量

在使用==比较两个对象时,会自动调用equals(),data根据参数来比较,若参数相同则true

单例类

在Kotlin中,只需将class关键字改为object关键字即可

object Singleton{
    
}
object Singleton{
    fun singletonTest(){
        println("singletonTest is called.")
    }
}
//调用方式
Singleton.singletonTest()

2.6 Lambda编程

2.6.1 集合的创建与遍历

List,Set

ArrayList,LinkedList

HashSet

HashMap

val list = ArrayList<String>()
list.add("Apple")
list.add("Banana")
list.add("Orange")
list.add("Pear")
//简化写,相当于Java中Arrays.asList();
val list = listOf("Apple","Banana","Orange","Pear")

List集合

//遍历集合
fun main(){
    val list = listOf("Apple","Banana","Orange","Pear")
    for(fruit in list){
        println(fruit)
    }
}

listOf()与Java中一样,也是不可变的集合,不能添加、修改或删除

可变集合

使用mutableListOf()

fun main(){
    val list = mutableListOf("Apple","Banana","Orange","Pear")
    
    list.add("Watermelon")
    
    for(fruit in list){
        println(fruit)
    }
}

Set集合

自动去重

val set = setOf("Apple","Banana","Orange","Pear")
​
for(fruit in set){
    println(fruit)
}

Map集合

HashMap

//类似Java写法
val map = HashMap<String,Int>()
map.put("Apple" ,1)
map.put("Banana", 2)

Kotlin中不建议使用put()和get()方法对Map进行加和读

推荐使用数组下标语法结构

map["Apple"] = 1

读取

val number = map["Apple"]

简便写法:mapOf(),mutableMapOf()

val map = mapOf("Apple" to 1,"Banana" to 2,"Orange" to 3,"Pear" to 4)

to不是关键字,而是infix函数

遍历Map集合

fun main(){
    val map = mapOf("Apple" to 1,"Banana" to 2,"Orange" to 3,"Pear" to 4)
    for((fruit, number) in map){
        println("fruit is " + fruit +", number is "+ number)
    }
}

2.6.2 集合的函数式API

maxBy

1.找出水果集合中单词最长的水果

val list = listOf("Apple","Banana","Orange","Pear")
val maxLengthFruit = list.maxBy {  it.length  }
println("max length fruit is " + maxLengthFruit)

不建议在Lambda表达式中编写太长的代码

Lambda表达式的语法结构:

{ 参数名1: 参数类型, 参数名2: 参数类型 ->函数体 }

参数列表结尾的->,表示函数体的开始

函数体中可以写任意行代码,最后一行代码会自动作为 返回值

由繁入简

maxBy:普通函数,接收一个Lambda类型的参数,

在遍历时将遍历的值作为参数传递给Lambda表达式。

工作原理:以传入的内容为条件并最大化的要求来遍历集合,

传入length则条件自然就是单词长度

//原始写法:
val list = listOf("Apple","Banana","Orange","Pear")
//规则 { 参数名1: 参数类型 ->函数体 }
val lambda = { fruit: String -> fruit.length }
val maxLengthFruit = list.maxBy(lambda)

不用lambda参数

val maxLengthFruit = list.maxBy({fruit: String -> fruit.length})

Kotlin规定:当Lambda参数是函数最后一个参数时,可将Lambda表达式移到函数括号外

val maxLengthFruit = list.maxBy() { fruit: String -> fruit.length }

根据类型推导,进一步简化

val maxLengthFruit = list.maxBy{ fruit -> fruit.length }

当Lambda表达式的参数列表只有一个参数,不必声明参数名,用it关键字代替

val maxLengthFruit = list.maxBy { it.length }

map

//将所有水果名变大写
val newList = list.map{ it.toUpperCase() }

filter

过滤集合中的数据,可结合其他函数一起使用

//先保留5个字母以内的水果,留下的单词 变大写
//先过滤再变大写效率高,反过来就低一点
val newList = list.filter{ it.length <= 5 }
                  .map{ it.toUpperCase() }

any,all

any:是否存在

all:是否所有都

2.6.3 Java函数式API的使用

如果在Kotlin中调用Java方法,该方法接收了一个Java单抽象方法接口参数,就能使用函数式API

单抽象方法接口:Runnable接口

new Thread(new Runnable(){
    @Override
    public void run(){
        System.out.println("Thread is running");
    }
}).start();

翻译为kotlin

//创建匿名类用object关键字
Thread(object : Runnable{
    override fun run(){
        println("Thread is running")
    }
}).start()

使用Lambda表达式规则化简

Thread(Runnable{
    println("Thread is running")
}).start()

若参数列表仅有一个Java单抽象方法接口参数

Thread({
    println("Thread is running")
}).start()

Lambda表达式是方法最后一个参数,移到方法括号外,

唯一一个参数,省略括号Thread()

Thread{
    println("Thread is running")
}.start()
button.setOnClickListener{
    
}

2.7 空指针检查

Kotlin默认参数和变量都不可以为空,若为空,编译出错

若业务逻辑需要个空,则需要可为空的类型系统

2.7.1 可为空的类型系统

在类名后加上问号

Int? 表示 可为空整型

String? 表示 可为空字符串

却依然编译不通过,

还需要处理掉空指针异常

判空

fun doStudy(study: Study?){
    //这样就是处理了
    if(study != null){
        study.xx()
        study.xx()
    }
}

2.7.2 判空辅助工具

?.操作符

当对象不为空时正常调用,为空什么都不做

if(a!=null){
    a.doSomething()
}
​
等价于
||
||
a?.doSomething()

fun doStudy(study: Study?){
    //这样就是处理了
        study?.xx()
        study?.xx()
​
}

?:操作符

左右都接收一个表达式,左不为空则返回左边,否则返回右边

val c = a ?: b
val c = if(a != null){
    a
} else {
    b
}

操作符混用

//                 text可能为空    不为空调用length。否则啥也不做  
fun getTextLength(text: String?) = text?.length ?: 0
                                              //不为空返回length。否则返回0

若已经进行了非空判断,仍编译失败,如在方法外判断非空,而方法内不知道,编译不通过

非空断言

在对象后面加!!

表示我确信这个对象不会为空,不需要你再来做空指针检查了。

var content: String? = "hello"
​
fun main(){
    if(content != null){
        printUpperCase()
    }
}
​
fun printUpperCase(){
    val upperCase = content!!.uppercase()   // !! 尽量少用
    println(upperCase)
}

let函数

函数式API编程接口,会将调用对象作为参数传递到表达式中

obj.let{
    obj2 ->
    //编写具体业务逻辑
}

obj与obj2实际上是同一个对象

实例:

var study: Study?=null
​
fun doStudy(study: Study?){
    //有点啰嗦,两次判断同一个对象是否为空
        study?.xx()
        study?.xx()
​
}
fun doStudy(study: Study?){
    study?.let{
        stu ->
            stu.XX()
            stu.XX()
    }
}
//继续简化
fun doStudy(study: Study?){
    study?.let{
        it.xx()
        it.xx()
    }
}

2.8 Kotlin中的小魔术

2.8.1 字符串内嵌表达式

将表达式写在字符串中

${}

仅有一个变量时,大括号省略

val brand = "Samsung"
val price = 1299.99
​
println("Cellphone(brand="+brand+", price="+price+")")
​
//化简
println("Cellphone(brand=$brand, price=$price)")

2.8.2 函数的参数默认值

通过给函数的参数设定默认值,一定程度上替代次构造函数的功能

//                             设置了默认值,实例化时可传可不传
fun printParams(num: Int, str: String = "hello"){
    println("num is $num, str is $str")
}
​
fun main(){
    printParams(123)
    
}
//            存在顺序问题
fun printParams(num: Int = 100, str: String){
    println("num is $num, str is $str")
}
​
//通过键值对传参
fun main(){
    printParams(str="hello")
    printParams(str="hello",num=123)
}

2.9 小结

变量、函数、逻辑控制语句、面向对象编程、Lambda编程、空指针检查机制...

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JonyJosda

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值