转生成为程序员靠攻略Kotlin入赘Google豪门 (part1:初窥门径)

写在前面

本文中可能函数和方法这两个词会经常换着用,这两个是指的同一个东西

函数:function,c,c++里面叫函数

方法:method, java里面叫方法

1、前言

简单介绍下今天的主角-kotlin,由JetBrains公司开发设计的一门编程语言,于2016年发布了1.0正式版,而2017年Google立即宣布kotlin为安卓开发的首选语言,而这其中是否有PY交易留给读者自己去想象了。

另外提一嘴,编程语言大致分为编译型和解释型,编译型就是把源码一次性编译成二进制文件,然后交给计算机再执行,比如C和C++都属于编译型,而解释型语言简单来说就是带一个解释器,在程序运行时一边读取我们的源码,一边把源码翻译成二进制文件给计算机执行,比如Java。

举个不恰当的比喻就是编译型语言是个饱汉子,会等饭做好后再吃,解释型语言就是饿了几天的流浪汉,饭还在做的时候就开吃。所以从原理上来说,编译型语言在运行时的效率会高一些,毕竟不用实时翻译。

2、Kotlin的优点与缺点

在说优缺点之前,先说下安卓开发们的老朋友java语言,学过安卓开发的打工仔都知道,安卓系统里面的ART(Android Runtime)虚拟机就是一种改进后的移动版虚拟机,而虚拟机的作用之一就是把JAVA源码编译后生成的class文件翻译成计算机能读懂的二进制文件,所以Kotlin如果能作为安卓开发的语言的话,那么必然编译后生成的也是和java一样的class文件,因为必须符合安卓系统的运行机制嘛。所以了解以上一点后,我们就知道kotlin和java其实殊途同归。

kotlin的优

  1. 语法更加简洁,更符合高级语言的定义,同样的功能使用kotlin后代码量可减少50%甚至更多,拒绝罗里吧嗦
  2. 语言安全性更高,比如kotlin是“天生拒绝空指针”圣体,自带杜绝空指针的特性,极大减少了打工仔们写的崩溃率最高的空指针bug的数量
  3. 支持函数式编程,比如高阶函数,可将一个函数作为另一个函数的参数
  4. 100%兼容java
  5. 自带类型推断,无需显示定义数据类型,可以自动推理出当前变量的数据类型,真相只有一个,kotlin就是福尔摩斯

kotlin的缺点:

一旦沾染上后就回不去了,对不起,java,我已经是kotlin的形状了~

3、初次邂逅Kotlin

3.1 变量与函数的定义
3.1.1变量

变量的定义与java有很大不同,前面说过kotlin自带类型推断,会在赋值的时候推理出变量的数据类型,所以我们定义变量的时候可以不用显示地写出数据类型。

val与var

val:表示该变量定义后只能赋值一次,类似java中的final

var: 表示该变量可多次赋值

PS:一个小技巧,优先使用val定义变量,当不满足需求时再用var,这样我们写出的程序更健壮稳定。

当然,自动推断机制不是总能推理成功的,比如我们延迟给这个变量赋值,所以这时候我们需要显式写出数据类型,和java将数据类型写在前面不一样,数据类型写在变量后面

3.1.2 函数

函数定义的模版如下:fun是函数定义的关键字

语法糖1:

这里说下函数相关的第一个语法糖:当函数里只有一行代码时,可以不用写大括号,直接将这行代码用=连接写在函数定义的尾部即可。

所以上面两数相加的栗子可以简写为

函数参数的默认值设置与函数传参

参数的默认值直接使用等号赋值即可(PS:在主构造函数里面设置参数默认值可以有效减少次级构造函数的使用

函数传参,kotlin里面函数传参可以使用键值对来传参,比如上面的add函数传参,如下

3.2 逻辑控制
3.2.1 条件语句之if语句

if语句与Java的几乎一样,按之前一样使用即可。

语法糖2:if语句自带返回值,可以返回每个条件下最后一行代码的值

还是以比较两数大小为例,下图1是java习惯的写法,图2是kotlin的写法,我们再把图2简化下,不要bigger这个变量,直接返回If语句的值,这样就变成了图3;还记得上面说的函数定义的语法糖吗,当函数只有一行代码时,直接用=写在函数定义的尾部,所以就简化成了图4

Ps:你可能疑惑图4明明是四行代码,虽然是四行,但是其实if的每个条件下都只有一行代码,所以可以理解为等效一行。

   

                      图1                                                                          图2

   

                     图3                                                                          图4

3.2.2 条件语句之when语句

when语句可以理解为java中switch语句的proMax版本,switch语句有点鸡肋,只能接受整型和String,并且每个case条件都要加break,太繁琐了,而when语句大大解决上面的痛点,还加了强大的新特性。when语句的固定模版如下

以下面的查询年龄为例,我们不难看出when语句也是自带返回值的

当然,除了值匹配外,when语句也支持类型匹配,is 关键字就是类型匹配,与java中的 instanceof类似,举栗如下:

再说一个when的进阶用法,不带变量名的写法,这种用法适用于比较灵活的场景,以上面的年龄查询为例,假设所有姓张的都是18岁的话,只能用这种不带变量名的写法才能实现,如下

PS:泪目了,kotlin里面比较字符串值可以直接用==,Kotlin==等价于Javaequals比较的是对象里的内容, === 等价于Java==,比较的是对象的引用

3.2.3 循环语句

Java中常用的循环就两种,for和while,而kotlin中也是这两种,其中while语句是和java一样没有变,但for语句舍弃了java中常用的for-i这种循环,将for-each循环做了改进,变成了for-in循环,并引入了区间,没错,就是数学课里的那个区间,比如一个0到9的,左闭右闭区间可以如下表示

左闭右开区间用until关键字创建

上面的都是升序区间,我们也可以创建一个降序区间,使用downTo关键字

以累加0到9的所有数字和为例

如果是累加0到9中所有偶数的和,我们则可以使用step关键字跳过某些下标,达到for循环中i = i + n的效果,如下

3.3 面向对象编程

对象?什么对象!心中无女人,编码自然神!

3.3.1类与对象

kotlin与Java一样都是使用class类声明一个类,例如

这里提一下可见性修饰符(所有修饰符在当前类都可见,所以表格里面就不提了

Java

Private

当前类可见

Default(默认)

同一个包路径下可见

Protected

同一个包路径下可见及其子类可见

Public

所有类可见

Kotlin

Private

当前类可见

Internal

同一个模块下可见

Protected

子类可见

public(默认)

所有类可见

3.3.2 构造函数与继承

与java不同的是,kotlin默认你创建的类是无法继承的,相当于给你的类加了java中final,(估计和val一样,为了程序的健壮性)所以如果想让类可以继承,需要在前面添加open关键字

下面难点来了,korlin中构造函数分为主构造函数和次构造函数,并且在继承父类时,子类需要指明调用的父类哪个构造函数

以上面的Human类为例,由于他没有显式的构造函数,所以我们定义一个子类Worker去继承时,指明的构造函数是默认的无参构造函数,就是下面例子中冒号后面的Human(),而括号里面的三个参数是Worker的主构造函数的入参,父类没有的参数得使用val或var重新定义,比如height这个变量。

当然我们可以调整下human类的主构造函数,改成如下

相应的,子类worker也需要改下,因为此时父类已经没有默认的无参构造函数了

ps:上面的age和name两个变量是父类就有的,我们不能再用val和var定义了,这样会冲突,因为构造函数里面使用val和var定义的变量都会变成这个类的成员变量

任何一个类都只有一个主构造函数,但是可以有多个次构造函数,下面我们说下次构造函数,次构造函数使用constructor关键字定义,还有一件事,次级构造函数必须调用主构造函数,这个应该好理解,主构造函数是本,次构造函数是在这上面锦上添花,对了,次构造函数里面不能再用val和var新定义变量了,构造函数里面使用val和var定义的变量都会变成这个类的成员变量。

此外介绍一种特殊情况,就是这个类只有次构造函数,没有主构造函数,此时次构造函数调用的是父类的主构造函数,因为自己没嘛,如下(与Java一样,this代指当前类,super代指父类)

3.3.2接口

接口和java中的基本一样,只是不管是继承父类还是实现接口,都是统一用冒号,这块就不展开了。

3.3.3 常用类

单例类

Kotlin中会把一些我们开发中常用的类封装,让我们使用起来更加方便,比如单例类,在定义单例类的时候,我们只需要把class关键字改成object,就能自动帮我们创建一个单例类,我们只需要往里面加方法和变量即可

数据类

此外,常用的数据类也帮我们进行了封装,我们使用时只需要在类定义时加上data关键字即可,然后会帮我们自动生成equals, hashCode, toString等方法,一行代码搞定

4、常用集合的创建与遍历

List集合

在kotlin里,你可以继续按照java里面的写法创建集合

不过嘛,既然用了kotlin,那就贯彻到底,用下kotlin的内置函数listOf和mutableListOf

listOf会创建一个不可变的集合,mutableListOf创建可变集合

集合的遍历也很简单,继续用for-in循环(比java少了临时变量的定义,更加简洁)

Map集合

与List类似,map的创建也是mapOf和muatableMapOf两个函数

mapOf创建不可变的map,后者则是可变,键与值之间使用 to 连接,遍历依旧使用for-in,键和值直接放括号里,举个板栗,我们创建一个人物名称和对应年龄的map

map的查找对应键值,依旧可以使用get()与put(),但是推荐kotlin提供的类似数组的访问方式,如下

5、Lambda表达式

这块算是比较难理解的点了,lambda表达式简单说就是一段代码或者说一个简化版的函数,先说下lambda表达式的标准格式

再解释一个名词,函数式API,我自己的理解是 指能接受lambda表达式作为参数的函数,

kotlin提供了很多内置的函数式API,然后每个函数又有很多扩展方法,下面只介绍一部分,其他的留给读者自己去查找了,这里就不展开了

5.1 数据过滤筛选(slice, filter, drop, take)
5.1.1 slice

slice函数,中文意思切片,简单说就是将集合切一部分出来成为一个新集合,怎么切呢,当然是按下标啦,slice函数有两个重载方法,一个接受IntRange作为参数,一个接受下标集合作为参数

IntRange就是一个闭区间,指定起始下标和终点下标,比如把下标2到下标5的这段数据切下

第二份重载方法接受下标集合作为参数,比如把单数下标的数据切下组成一个新集合

5.1.2 Filter 

Filter (数据过滤),主要是用于过滤集合中的数据,筛选出符合条件的数据,举个板栗,从下面的人名中筛选出两个字以下的,直接使用了上面提到的简化写法

还可以与map函数搭配,先过滤出名字小于2个字的数据,再把数据以字符串长度映射出一个新的集合{2,2},如下

​​​​​​​5.1.3 Drop

drop:作用是丢掉集合的前n个元素,然后返回一个新集合

还有个dropLast,丢掉倒数n个元素,返回一个新集合

​​​​​​​​​​​​​​5.1.4 Take

take:挑出集合的前n个元素并返回

与dropLast类似,take也有takeLast,挑出集合倒数几个元素并返回

5.2 集合映射(map, flatMap, groupBy
5.2.1 map

map函数可以将一个集合按照你设定的映射规则映射为一个新集合,元素顺序与原集合一致,举个板栗:把集合allStars按照字符串长度重新映射成一个新集合{3,4,2,2,4,3},如下,简单来说就是把一种数据类型的集合转化成另一种数据类型

稍微解释下上面的代码,map函数执行时,会遍历allStars这个集合,每次遍历时会把遍历的元素传入lambda表达式中,得到该元素的长度length,然后把这个值加入新集合中。

上面的栗子我是按照函数的定义结构写的,把lambda作为参数传入函数map中,这其实可以继续简化:

1.首先,我们不需要专门定义一个lambda变量,可以直接写到括号里,如下

2.其次,当lambda表达式是函数的最后一个参数时,可以直接将lambda表达式写到括号外面,就变成下面这样了,这里其实和java里面的lambda的写法一样了

3.然后是 如果lambda表达式是函数唯一的参数,可以不用写括号,如下

4.别忘了,前面说过,kotlin是小福尔摩斯,有类型推断机制,所以我们可以不用指明carName的数据类型,如下

5.最后,如果lambda表达式只有一个参数时,可以直接用it关键字代替,那么最后就简化成

5.2.2 flatMap

和上面说的map函数的元素一对一映射不同,flatMap函数是元素的一对多映射,还是举个板栗,如下,我们把每个字符串与字符串自己的长度,首字符,尾字符进行映射,形成一对三的对应关系,然后就得到新集合newList。

这里比较难理解的是这个一对三的映射关系是用的一个List集合来表示的,其实也好理解,这里flatMap就是在遍历每一个元素,然后把元素传入你写的lambda表达式里面,然后得到一个新集合,最后把新集合加入到返回结果里面

5.2.3 groupBy

顾名思义,是用于分组的函数,有两个重载方法

先讲一个参数的重载方法,举个板栗,将下面所有姓一样的人分成一组

两个参数的,第一个参数是分类标准,第二个参数是分类后元素的映射关系,还是举例,把所有姓一样的人分一组,再把名字映射成名字长度返回,如下

5.3 any,all,find,count函数(条件查找
5.3.1 any

判断集合中是否至少存在一个元素满足条件,返回bool值,比如判断有没有姓刘的人

5.3.2 all

判断集合中是否所有元素都满足条件,返回bool值,比如判断是否所有人都姓刘

5.3.3 find

找到集合中第一个满足条件的元素并返回,举例:找到第一个姓马的人并返回

5.3.4 count

统计集合中有多少元素满足条件,返回Int值,举例:统计所有姓马的人并返回人数

6、Kotlin调用Java方法

前面说到了很多函数式API,当kotlin调用java方法时,且这个java方法是抽象方法的接口时,我们就可以使用java函数式API。

先说下什么是单抽象方法的接口,例如我们常用的点击事件接口,他里面只有一个抽象方法onClick()

以点击事件为例,我们看看java中一般怎么写点击事件的,一般是通过匿名类实现

而kotlin中没有new关键字了,匿名类是通过object关键字实现,所以我们把上面的代码改成kotlin实现,如下

上面这段代码和java比并没有简化,但是别忘了kotlin要智能很多,因为onClickListener只有一个抽象方法,所以我们不用显式的重写这个方法,kotlin也能推断知道大括号里面是重写的那个唯一方法,所以简化成如下:

继续简化,如果一个java方法的参数中,只有一个参数是java单抽象方法的接口,那么我们可以直接省略接口名称,如下

别忘了,之前说过,如果lambda表达式是最后一个参数时,可以把表达式写在括号后面,并且如果是唯一的参数时,还可以省略括号,所最后简写为

怎么样,是不是干净利落!

7、空指针检查

空指针可以说是安卓系统里面崩溃率最高的异常了,java我们对空指针处理主要有两种方法,一种是主动判空,在调用时判断一下是否为空,显然这种很麻烦,而且容易忘,我们不可能每次调用都去判空,第二种,在定义函数时,使用注解表明参数不能传空,但是这个只能用作基本类型和String类,其他类得自定义注解来实现。

而kotlin默认所有参数和变量都不可为空,如果给一个函数传空值会在编译时就不能通过。如果非要有空值,可在数据类型后接一个?,表示该参数可为空,举个板栗,如下图表示参数b可以传空值。

?.

Kotlin中如何判空,kotlin通过一种简写来简化用if语句判空的繁琐,使用?.则表示不为空则执行后面的语句,例如字符串b如果不为空则转换为大写

?:

此外Kotlin还提供了?: 用来表示?:的左边不为空就返回左边,否则返回右边。比如下面的代码,如果b不为空则把b赋值给temp,否则把a的字符串赋值给temp

下面我们把?. 和?:结合使用,来写个Int型和String型相加的函数,如下

非空断言 !!

kotlin并不总是那么智能,一旦你定义了一个可为空的变量,即使你在调用时判空了,能确保不出现空指针,但是ktolin还是可能编译不通过,这个时候我们可以使用非空断言,就是告诉kotlin,这个值不可能为空,不用在编译的时候检查了,如下:

let函数

不知道有没有读者发现?.的缺陷,就是很容易造成累赘一样的重复写法,如下:下面这段代码进行了三次非空判断,其实完全没有必要这样,这时我们引入let函数

Let函数的基本格式

这里的变量1和变量是同一个对象,let函数的作用就是把变量的值传入lambda表达式里的变量1,然后再执行后面的逻辑,所以上面的三次非空判断使用Let函数后可以这样写

然后还记得之前说的lambda表达式只有一个参数时,可以省略变量名,用it指代吗,所以简化为,所以其实let可以用来处理全局判空的问题

8、字符串内嵌表达式

Java中我们拼接字符串与变量值时都是使用+ 使用起来比较繁琐,但是kotlin可以使用内嵌表达式,格式如下

举个板栗:

输出:a+b=30

未完待续。。。

  • 28
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值