第一行代码读书笔记(Chapter2 探究新语言,快速入门Kotlin编程)
准确来说,Java是解释性语言,Kotlin能被编译为class文件,再在虚拟机中运行
Kotlin几乎杜绝了空指针异常
运行Kotlin代码:IDEA创建Kotlin项目;在线运行kotlin代码;Android Studio创建一个main()函数
fun main() {println("Hello, world!!!")
}
2.3.1变量
Kotlin中定义一个变量,只允许val或var进行声明。
val(value的简写)声明不可变的变量,对应Java中的final变量,不可二次赋值(地址)
var(variable的简写)用来声明一个可变的变量,对应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 = 30val b = 43val 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" -> 100else -> 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") -> 86name == "Jim" -> 77name == "Jack" -> 95name == "Lily" -> 100else -> 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 = 19p.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(){@Overridepublic 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 ?: bval 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编程、空指针检查机制...
第一行代码读书笔记(Chapter2 探究新语言,快速入门Kotlin编程)相关推荐
- 第一行代码读书笔记1+常见错误分析
1.eclipse里面的视图在 windows ---- show views ---- other ----- Android 2.需要掌握Logcat的使用 Logcat是你在茫茫人海中寻找到一片 ...
- 日报2015/11/11(第一行代码读书笔记)
SQLite数据存储 这里需要说明的是,要使用这种存储,在开发的时候最好是使用模拟器或者把真机root,不然没有权限访问数据库所在的位置.po主直接把三星的s4用刷机大师刷成了别的系统,顺便root掉 ...
- 第一行代码读书笔记3+错误分析
as中怎么删除项目 file---project structure 然后点击左边的 + 与 - 进行删除. 参考资料:http://jingyan.baidu.com/article/c74d600 ...
- 日报2015/11/17(第一行代码读书笔记)
ContentResolver 使用内容提供器是Android实现跨程序共享数据的标准方式. 基本用法 这里要访问的是通讯录,里面已经有一个系统自己的ContentProvider 数据查询无非是要最 ...
- 从零开始写安卓APP 《第一行代码》笔记 第一周
这是软件开发课的任务,本人其实不会java也不会安卓开发.以前只做过web端,因为某课程的爆炸实验单人撸了全栈.不过好在很早前就想学了,这里记录一下过程.放的主要是<第一行代码>的一些笔记 ...
- 第一行代码阅读笔记---基本知识
在res中,我们会看到很多目录,分别如下: drawable-hdpi drawable-ldpi drawable-mdpi drawable-xxhdpi layout menu values v ...
- 第一行代码学习笔记第六章——详解持久化技术
知识点目录 6.1 持久化技术简介 6.2 文件存储 * 6.2.1 将数据存储到文件中 * 6.2.2 从文件中读取数据 6.3 SharedPreferences存储 * 6.3.1 将数据存储到 ...
- 第一行代码学习笔记第七章——探究内容提供器
知识点目录 7.1 内容提供器简介 7.2 运行权限 * 7.2.1 Android权限机制详解 * 7.2.2 在程序运行时申请权限 7.3 访问其他程序中的数据 * 7.3.1 ContentRe ...
- 第一行代码学习笔记第二章——探究活动
知识点目录 2.1 活动是什么 2.2 活动的基本用法 2.2.1 手动创建活动 2.2.2 创建和加载布局 2.2.3 在AndroidManifest文件中注册 2.2.4 在活动中使用Toast ...
最新文章
- vue.js 发布后路径引用问题
- android 增删改查 源码_学生信息增删改查小程序案例(springboot服务端)
- Prim算法 求出 最小生成树
- php7 方法,PHP7中方法的弃用
- SharePoint2010内容类型剖析(四)
- 沼跃鱼早已看穿了一切 C/C++
- EasyUI的DataGrid 分页栏英文改中文解决方案
- 【论文写作】毕业论文怎么写?写作步骤是什么?
- Spring.Net配置多数据源
- Struts2学习日记(二)简单的Struts2登陆实现(Action继承ActionSupport类)
- cakephp2.X教程第一部分(基于cakephp1.3.4在线教程的改编)
- java电力巡检系统 项目讲解_苏河湾1号街坊项目电力监控系统的设计与应用
- 网易云音乐数仓模型设计实践
- c语言printf()输出格式大全(转载)
- 泰山OFFICE技术讲座:介绍几个看着相似的标点
- Unhandled Exception:System.DllNotFoundException: Unable to load DLLquot;**quot;:找不到指定的模块
- 数据仓库知识与实战——电信运营商数仓建模
- 99. 激光炸弹(前缀和)
- 基于16S的细菌群落功能预测工具Tax4Fun2
- 云计算工程师必备的10本书