public void onClick(View v){
System.out.println(“sad”);
}
});
在 kotlin 中,这也得到简化:
view.onClick {
println(“nice !!”)
}
类型安全
在 Android 开发中,出现 NullPointerException
已经可以说是家常便饭了。但如果在运行的时候出现这个异常导致程序崩溃,对用户体验造成的损失是巨大的。
Kotlin 能很好的避免这个问题:
- 指定 null
// Java
String text1 = null // NE
// Kotlin
var text1: String = “Kotlin”// 正常
var text2: String = null // NE
var text3: String ?= null // 正常
Kotlin 中只有加了 ? 才允许为 null。
- 检查 null Kotlin 可以通过
?
确保安全调用:
// Java
if(a != null){
int x = a.length();
}
// Kotlin
val x = a?.length // 仅当 a 不为 null 时才能通过编译
- 为 null 时默认值
val x = b?.length ?: 0 // 如果 b 为 null,那他的 length 就为0
val x = b?.length ?: throw NullPointerException()
val x = b!!.length
Lambda 优化
Lambda 表达式增加了 Kotlin 的简洁功能,从而也让代码更容易理解。(Java 6 不支持 lambda )
val sum = {x: Int, y: Int -> x + y} // 类型:(Int, Int) -> Int
val result = sum(2, 7)// result == 9
条件判断更优雅
kotlin 中 when
同样能带给你惊喜,你可以用它简化 if..else
或 switch
:
// Java
if(x == 1) println(“x is 1”);
else if(x == 2) println(“x is 2”);
else if(x == 3 || x == 4) println(“x is 3 or 4”);
else if(x >= 5 || x <= 10) println(“x is 5, 6, 7, 8, 9, or 10”);
else println(“x is out of range”);
// Kotlin
when (x) {
1 -> print(“x is 1”)
2 -> print(“x is 2”)
3, 4 -> print(“x is 3 or 4”)
in 5…10 -> print(“x is 5, 6, 7, 8, 9, or 10”)
else -> print(“x is out of range”)
}
当然除了以上这些,Kotlin 还有许多令人惊喜的特性,
第二章 Kotlin初阶易错知识点
1、不需要分号,不需要分号,不需要分号
2、字段定义://var 可变变量;val 常量
例如:
var a: Int = 1
val b = 2
val c: Int = 0
var d: Int = 0
复制代码
3、字符串的定义,去掉空格
var age: String? = “abc” //加 ? 可为空
val age2 = age!!.toInt() //抛出空指针异常
val age3 = age?.toInt() //不做处理,返回null
val age4 = age?.toInt() ?: -1 //age为空时,返回-1
text.trimMargin()
复制代码
4、list,数组是不型变的(invariant)
val items = listOf(“item1”, “item2”, “item3”)
for (item in items) {
println(item)
}
for (index in items.indices) {
println(“item at $index is ${items[index]}”)
}
//输出
// item at 0 is apple
// item at 1 is banana
// item at 2 is kiwi
复制代码
5、数组
//[1,2,3]
val a = arrayOf(1, 2, 3)
//[0,2,4]
val b = Array(3, { i -> (i * 2) })
for (i in a.indices) {
println("eche element : " + a[i])
}
复制代码
6、运算符(>/</=/>=/<=/!=)
if-else
复制代码
7、运算逻辑when(X)可以传int,enum等
val sss = 5
val validNumbers = 11…19
when (sss) {
0, 1 -> print(“x == 0 or x == 1”)
in 1…10 -> print(“x is in the range”)
in validNumbers -> print(“x is valid”)
!in 10…20 -> print(“x is outside the range”)
else -> print(“none of the above”)//如果包含了所有的情况,就不需要写else了
}
fun hasPrefix(x: Any): Boolean = when (x) {
is String -> x.startsWith(“prefix”)//当是string类型,则运算startsWith(),返回是否以特定前缀结尾
else -> false//不是string类型,直接返回false
}
//判断某个值是否在一个set集合里面
val items = setOf(“apple”, “banana”, “kiwi”)
when {
“orange” in items -> {
println(“juicy”)
println(“{do something}”)
}
“apple” in items -> {
println(“apple is fine too”)
println(“do another thing!”)
}
}
复制代码
8、类型转换
val e: Byte = 1
val f: Int = e.toInt()//转换
复制代码
中缀操作符 as
eg: val x: String = y as String
val x: String? = y as String?
val x: String? = y as? String
9、数字定义(可以用"_"来区别很长的数字)
//使用下划线使数字常量更易读
val oneMillion = 1_000_000
val creditCardNumber = 1234_5678_9012_3456L
val socialSecurityNumber = 999_99_9999L
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010
复制代码
10、for循环(极其方便)
fun forCircle() {
for (i in 1…5 step 1) {
print(i)
//输出12345
}
for (i in 5 downTo 1 step 1) {
print(i)
//输出54321
}
for (i in 1…5 step 2) {
print(i)
//输出13
}
for (i in 1 until 5 step 1) {
print(i)
//输出1234,没有5 等同于[1,5)
}
}
复制代码
11、类型替代(typealias)
typealias f = Foo//类型替代(f代表新的名词,Foo代表需要另起名字的对象名,比如,Foo全名为:尼古拉斯.凯奇.赵四,那么f可以叫做赵四,哪里需要这么高大上的名称)
复制代码
12、is和!is
fun getStringLength(obj: Any): Int? {
if (obj !is String) {
return null
}
//此时obj已经自动转化为string类型
return obj.length
}
复制代码
13、lambda表达式使用之一
//limbda表达式
val sumLambda: (Int, Int) -> Int = { x, y -> x + y }//xy是入参,x+y是返回值
复制代码
14、长度可变的入参(关键字:vararg)
//可变长度入参
fun sum5(vararg v: Int): Int {
var sum = 0
for (vt in v) {
sum += vt
}
return sum
}
复制代码
15、类相关(主构造函数,次构造函数,init方法,默认参数,变量的get和set方法,super父类方法,重写父类方法,共有函数,私有函数)
class Runoob constructor(name1: String = “jack”, psd1: String = “123456”) {//默认参数
//主构造器中不能包含任何代码,初始化代码可以放在初始化代码段中,初始化代码段使用 init 关键字作为前缀
init {
println(“name : $name1, psd : $psd1”)
// name = “”//这里连name常量都没有定义,所以不能够进行赋值
}
constructor(name: String, psd: String, addr: String) : this(name, psd) {
this.name = name
this.psd = psd
}
//次构造函数
constructor(name: String, psd: String, age: Int) : this(name, psd) {
}
var nickName = name1
get() {
return nickName
}
var name: String
get() {
return name.toUpperCase()
}
set(value) {
name = value
}
var psd: String = “”
private set
get() {
return psd + “@”
}
}
复制代码
16、interface的方法体是否实现是可选的。属性也是抽象的,需要实现类重新赋值。
interface BaseView {
var mNickName: String//抽象的属性
fun walk() {//方法体是否实现是可选的
println(“BaseView,walk!!!”)
}
fun yeal() {}//
}
复制代码
17、密封类
//密封类
sealed class Expr//相当于枚举的扩展
data class Const(val number: Double) : Expr()//这里只有另外一个double的状态入参
data class Sum(val e1: Expr, val e2: Expr) : Expr()//这个密封类里面就有两个Expr的状态入参
object NotANumber : Expr()
fun eval(expr: Expr): Double = when (expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
//因为已经覆盖了所以的情况,就不需要else子句了
}
复制代码
18、枚举
Color.BLACK.name
enumValues().size
enumValues().get(0)
enumValues().plus(Color.WHITE)
enumValues().iterator()
enumValueOf(Color.WHITE.toString())
复制代码
19、list和Comparable
fun <T : Comparable> sort(list: List) {
}
sort(listOf(1, 2, 3)) // OK。Int 是 Comparable 的子类型
// 错误:HashMap<Int, String> 不是 Comparable<HashMap<Int, String>> 的子类型
// sort(listOf(HashMap<Int, String>()))
复制代码
20、object对象
val site = object {
var name = “jack”
var url = “www.tansu.com”
}
复制代码
21、委托类,委托对象(通过关键字 by 建立)
interface MyBase {
fun bark()
// fun bak()
}
class BaseImpl(val x: Int) : MyBase {
fun bak() {}
override fun bark() {
println(“x:$x”)
}
}
// 通过关键字 by 建立 委托类
class Deried(b: MyBase) : MyBase by b
fun test3() {
var baseImpl = BaseImpl(10)
Deried(baseImpl).bark()
baseImpl.bak()
// Deried(baseImpl).bak()//无法访问到非interface定义的方法
}
// 定义包含属性委托的类
class Example {
var p: String by Delegate()
//说明:如果p是var的话,那么委托类需要有getValue和setValue两个方法(因为此时是可变的变量,需要由set方法)
//说明:如果p是val的话,那么委托类只需要有getValue方法即可,另外一个可以不要求(此时为不可变常量,不需要set值进去)
}
// 委托的类
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return “$thisRef, 这里委托了 ${property.name} 属性”//这里name为p
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println(“$thisRef 的 ${property.name} 属性赋值为 $value”)//value为设置进来的值
}
}
fun test4() {
val e = Example()
println(e.p) // 访问该属性,调用 getValue() 函数
e.p = “Runoob” // 调用 setValue() 函数
println(e.p)
// Example@433c675d, 这里委托了 p 属性
// Example@433c675d 的 p 属性赋值为 Runoob
// Example@433c675d, 这里委托了 p 属性
}
复制代码
21、监听类值的变化
class User {
var name: String by Delegates.observable(“初始值”) { prop, old, new ->
println(“旧值:
o
l
d
−
>
新值:
old -> 新值:
old−>新值:new. prop:$prop”)
}
}
val user = User()
user.name = “第一次赋值”
user.name = “第二次赋值”
// 旧值:初始值 -> 新值:第一次赋值
// 旧值:第一次赋值 -> 新值:第二次赋值
复制代码
22、map
//把属性储存在映射中
class MyWebSite(val map: Map<String, Any?>) {
val name: String by map
val url: String by map
}
使用
var myWebSite = MyWebSite(mapOf(“name” to “jack”, “url” to “www.baidu.com”))
myWebSite.name
myWebSite.url
//结果读取出来
复制代码
23、其它
class Foo {
var notNullBar: String by Delegates.notNull()
}
使用
var foo = Foo()
foo.notNullBar = “bar”
println(foo.notNullBar)
kotlin最佳实践
类型的声明与使用
val与var
val->不可变引用,var->可变引用。
我们应该尽可能地使用val关键字来声明所有的kotlin变量 为什么呢?
- 首先一个变量在声明时是不可变的,那就代表你在使用的时候不需要考虑其他地方会对它重新复制和改变(对于对象注意只是引用不可变),直接使用。
- val声明的类型由于必须初始化,它是线程安全的。
- kotlin为了保证类型安全,所有变量声明的地方必须要做初始化,即显示赋一个初值。
空与非空
kotlin
对于可空类型
和非空类型
认为是两个完全不同的类型,比如Int
与Int?
,他们俩就不是相同的类型。利用这个特点和编译时检查,kotlin
基本可以避免空指针异常
。
上面已经说了kotlin的类型声明时必须要有初值
,所以空与非空类型
和val与var
一组合就会变成4种情况,下面我们对一个Person
对象进行声明:
val p:Person = Person()
val p:Person? = null // 这个情况是没有意义的
var p:Person = Person() // 如果这个对象是非空类型,那么初始化的时候必须赋一个非null初值
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
重要知识点
下面是有几位Android行业大佬对应上方技术点整理的一些进阶资料。
高级进阶篇——高级UI,自定义View(部分展示)
UI这块知识是现今使用者最多的。当年火爆一时的Android入门培训,学会这小块知识就能随便找到不错的工作了。不过很显然现在远远不够了,拒绝无休止的CV,亲自去项目实战,读源码,研究原理吧!
- 面试题部分合集
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
有帮助,可以添加V获取:vip204888 (备注Android)**
[外链图片转存中…(img-ijOfxyNq-1712754565964)]
重要知识点
下面是有几位Android行业大佬对应上方技术点整理的一些进阶资料。
[外链图片转存中…(img-VcqfTtP1-1712754565965)]
高级进阶篇——高级UI,自定义View(部分展示)
UI这块知识是现今使用者最多的。当年火爆一时的Android入门培训,学会这小块知识就能随便找到不错的工作了。不过很显然现在远远不够了,拒绝无休止的CV,亲自去项目实战,读源码,研究原理吧!
[外链图片转存中…(img-TsdmEiXB-1712754565965)]
- 面试题部分合集
[外链图片转存中…(img-cUW4YLe8-1712754565965)]
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-JM2wnINb-1712754565966)]