第二章(Kotlin基础)
基本要素:函数和变量
函数
函数定义规则
- 函数通过关键字
fun
用来声明一个函数 - 参数的类型与函数返回类型写在它的名称后面,这和变量声明一样
- 函数可以定义在文件的最外层,不一定要把它放在类中
示例:
fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}
>>> println(max(1,2)) //打印结果:2
函数的声明以关键字 fun
开始,函数名称紧随其后:上面示例中函数名称是max,接下来是括号括起来的参数列表。参数列表后面跟着返回类型,它们之间用一个冒号隔开。如果不需要返回类型,则可以直接省略冒号及其后面的返回类型。
在Kotlin中,if
是有结果值的表达式。如上示例代码中函数的返回值 if (a > b) a else b ,它和Java中的三元运算符相似:(a>b) ? a : b。Kotlin中,if
是表达式,而不是语句。表达式和语句的区别在于,表达式有值,并且能作为另一个表达式的一部分使用;而语句总是包围着它的代码块中的顶层元素,并且没有自己的值。
表达式函数体
上面示例代码可以变得更简单。因为它的函数体是由单个表达式构成的,可以用这个表达式作为完整的函数体,并去掉花括号和return语句。如果函数体写在花括号中,我们说这个函数有代码块体。如果它直接返回了一个表达式,那么这个函数就有表达式体。
fun max(a: Int, b: Int): Int = if (a > b) a else b
上面代码可以进一步简化,省掉返回类型:
fun max(a: Int, b: Int) = if (a > b) a else b
为什么有些函数可以不声明返回类型?作为一门静态类型语言,Kotlin不是要求每个表达式都应该在编译器具有类型吗?事实上,每个变量和表达式都有类型,每个函数都有返回类型。但是对表达式函数体来说,编译器会分析作为函数体的表达式,并把它的类型作为函数的返回类型。这也是Kotlin的类型推导。(注意:只有表达式体函数的返回类型可以省略。对于有返回值的代码块函数体,必须显示地写出返回类型和return语句。)
变量
Kotlin中声明变量的关键字有两个:
- val(来自value)— 不可变引用。使用val声明的变量不能在初始化之后再次赋值。它对应的是Java的final变量。
- var(来自variable)— 可变引用。使用var声明的变量的值可以被改变。这种声明对应的是普通(非final)的Java变量。
默认情况下,应该尽可能地使用val关键字来声明所有的Kotlin变量,仅在必要的时候换成var。
注意:尽管val引用自身是不可变的,但是它指向的对象可能是可变的。例如:下面这段代码是完全有效的:
val languages = arrayListOf("Java") //声明不可变引用
languages.add("Kotlin") //改变引用指向的对象
字符串模板($)
Kotlin中的字符串模板相当于Java中的“+”号,示例:
val name = "World"
//下面两行代码是等效的
println("Hello "+name)
println("Hello $name")
>>> 打印结果:Hello World
类和属性
类
Kotlin中类声明比Java中更简洁。我们以一个简单的JavaBean类来对比,以下两个例子完全等效,只是分别用Java与Kotlin来声明。
/* Java */
public class Person {
private final String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
/* Kotlin */
class Person(val name: String)
属性
在Java中,字段和其访问器(getter,setter)的组合常常被叫做属性。而在Kotlin中,属性是头等的语言特性,完全代替了字段和访问器方法(getter和setter方法),在类中声明一个属性和声明一个变量一样:使用val和var关键字。声明成val的属性是只读的(只有getter方法),声明成var属性是可变的(包含getter和setter方法)。
示例:
class Person(val name: String, var age: Int) //Person类声明了一个只读的name属性与可变的age属性
fun main(args: Array<String>) {
val person = Person("xiaochao",24)
// person.name = "xiaochao" //编译不通过,val修饰,是只读的(只有getter,没有setter),不可修改
person.age = 25//编译通过,var修饰,是可变的,这里赋值是调用setter方法
println("name=${person.name},age=${person.age}")//这里取值是调用getter方法
}
>>> 打印结果:name=xiaochao,age=25
上面代码演示了在构造函数中声明属性及调用,如果想直接在Person类文件中声明属性也是一样的。
class Person {
val name: String = "xiaochao"
var age: Int = 0
}
fun main(args: Array<String>) {
val person = Person()
// person.name = "hello world" //编译不通过,name是val修饰的,是只读的,不可修改
person.age = 18
println("name=${person.name},age=${person.age}")
}
>>> 打印结果:name=xiaochao,age=18
自定义访问器(getter、setter)
假设你声明这样一个矩形,它能判断自己是否是正方形。不需要一个单独的字段来存储这个信息(是否是正方形),因为可以随时通过检查矩形的长宽是否相等来判断:
class Rectangle(val height:Int,val width:Int){
// val isSquare:Boolean
// //自定义getter方法,同理也可以自定义setter方法,不过要自定义setter方法则属性必须声明为var类型
// get() {
// return height==width
// }
//可以使用表达式函数体来简化
val isSquare:Boolean
get() = height==width
}
fun main(args: Array<String>) {
val rectangle = Rectangle(20,20)
println(rectangle.isSquare)
}
>>> 打印结果:true
枚举和“when”
声明枚举类
和Java一样,枚举并不是值的列表:可以给枚举声明属性和方法。
enum class Color(val r: Int, val g: Int, val b: Int) {
//下面每一个颜色都表示一个Color枚举类常量
RED(255, 0, 0), YELLOW(255, 255, 0),
ORANGE(255,165,0),INDIGO(75,0,130),
GREEN(0, 255, 0), BLUE(0, 0, 255);//这里必须要有分号
fun rgb() = (r * 256 + g) * 256 + b//给枚举类定义一个方法
}
fun main(args: Array<String>) {
println(Color.BLUE.rgb())
}
>>> 打印结果:255
when的基本使用
fun getMnemonic(color:Color){
when(color){
Color.RED -> println("red")
Color.BLUE -> {
println("blue")
}
Color.GREEN,Color.YELLOW -> println("green or yellow")
}
}
when当作表达式函数体
使用when当作表达式函数体时,when中的分支都必须在最后加else判断(在这里判断条件Color是枚举类型,所以这里将枚举类型的所有常量声明完整也可以省略else,其他情况下则必须加else):
fun getMnemonic2(color:Color) =
when(color){
Color.RED -> "RED"
Color.BLUE -> {
"BLUE"
}
Color.GREEN,Color.YELLOW -> "GREEN or YELLOW"
//如果不加else则编译无法通过,因为Color下还有ORANGE与INDIGO没判断
else -> "other"
}
不带参数的when
如果没有给when表达式提供参数,那么分支条件就是任意的布尔表达式。
fun mixOptimized(color1:Color,color2:Color) =
when{
(color1==Color.RED && color2==Color.YELLOW) ||
(color1==Color.YELLOW && color2==Color.RED) -> Color.ORANGE
(color1==Color.YELLOW && color2==Color.BLUE) ||
(color1==Color.BLUE && color2==Color.YELLOW) -> Color.GREEN
else -> throw Exception("Dirty color")
}
智能转换:合并类型检查和转换
如果你检查过一个变量是某种类型,后面就不再需要转换它,可以就把它当作你检查过的类型使用。事实上编译器为你执行了类型转换,我们把这种行为称为智能转换,智能转换只在变量经过 is
检查之后且不再发生变化的情况下有效。例子:
private val view:View? = null
fun test(){
if(view is TextView){
view.setText("这里view已经可以当成TextView使用")
}
}
智能转换通过 is
关键字来表示,这里的 is
相当于Java中的 instanceof
强制转换则通过 as
关键字来表示,例子:
private val view:View? = null
fun test(){
val textview = view as TextView
textview.setText("强制转换")
}
for循环
for循环基本使用
for (i in 0..10) { //从0开始遍历到10
println(i)//0,1,2,3,4,5,6,7,8,9,10
}
上面我们看到了最简单的for循环的使用方式,Kotlin中的for循环是用区间来表示,使用.. 运算符来表示区间,上面的for循环就表示0到10这个区间。除了区间这个概念,Kotlin中的for循环还涉及到步长这个概念。步长简单理解就是每次循环区间的大小,默认是1,如上面的代码,没有显示指定步长,默认就是从0到10这个区间以1的步长递增循环,接下来我们指定步长为2,那么输出的结果就会是0,2,4,6,8,10。以2的步长去递增。看下面代码:
for (i in 0..10 step 2) {
println(i)//0,2,4,6,8,10
}
如果我们想从10递减到0那么该怎么写呢?看下面代码:
for (i in 10 downTo 0) { //这里我们同样可以设置步长
println(i)
}
上面我们通过0..10知道了for循环的区间,这样会打印出0到10,接下来我们再看一种Kotlin中for循环写法:
for (i in 0 until 10){
println(i)//0,1,2,3,4,5,6,7,8,9
}
注意上面until
这种写法与0..10的区别在与until
这种写法只会打印0到9,而0..10则会打印0到10。
迭代数字:区间和数列
区间本质上就是两个值之间的间隔,这两个值通常是数字:一个起始值,一个结束值。使用 ..
运算符来表示区间:
val oneToTen = 1..10
注意Kotlin的区间是包含的或者闭合的,意味着第二个值始终是区间的一部分。
你能用整数区间做的最基本的事情就是循环迭代其中所有的值。如果你能迭代区间中所有的值,这样的区间被称作数列。
for循环迭代map
val maps = TreeMap<Char, String>()
for (c in 'A'..'F') {
val value = Integer.toBinaryString(c.toInt() )//A-F的二进制值
maps[c] = value //c为键,value为值
}
for ((key, value) in maps) {
println("$key = $value")
}
//打印结果
A = 1000001
B = 1000010
C = 1000011
D = 1000100
E = 1000101
F = 1000110
使用in关键字来检查集合和区间的成员
例如,我想检查5这个数字是否在0,10之间,代码如下:
fun main(args: Array<String>) {
println(testIn(5))//true
}
fun testIn(i:Int):Boolean{
//这里in可以取反,!in
return i in 0..10
}
再举个例子,比如我想检查某个List列表中是否包含某个值,也可以通过in来检查,代码如下:
fun main(args: Array<String>) {
println(testIn("xiaochao"))//true
}
fun testIn(name: String): Boolean {
val listdata = ArrayList<String>()
listdata.add("xiaochao")
listdata.add("xiaowang")
listdata.add("laowang")
return name in listdata
}
Kotlin中的异常
Kotlin中异常与Java中并没有太大区别。但是当Kotlin在使用 try catch
时,却可以将其作为表达式。
fun testException(str:String):Int{
val number = try{
Integer.parseInt(str)
}catch (e:NumberFormatException){
0
}
return number
}
fun main(args: Array<String>) {
println(testException("55")) //打印结果:55
println(testException("hello world")) //打印结果:0
}
总结
fun
关键字用来声明函数。val
关键字和var
关键字分别用来声明只读变量和可变变量。- 字符串模板帮组你避免繁琐的字符串链接。在变量名称前加上
$
前缀或者用${ }
包围一个表达式,来把值注入到字符串中。 - 熟悉的
if
是带返回值的表达式。 when
表达式类似于Java中的switch
但功能更强大。- 在检查过变量具有某种类型之后不必显示地转换它的类型:编译器使用智能转换自动帮你完成。
- for、while、do-while循环与Java类似,但是for循环现在更加方便,特别是当你需要迭代map的时候,又或是迭代集合需要下标的时候。
- 简洁的语法1..5会创建一个区间。区间和数列允许Kotlin在for循环中使用统一的语法和同一套抽象机制,并且还可以使用
in
云算法和!in
运算符来检查值是否属于某个区间。 - Kotlin中的异常处理和Java非常相似,除了Kotlin不要求你声明函数可以抛出的异常(即不需要在函数后显示的 throws Exception)。
第二章(Kotlin基础)的更多相关文章
- java面向对象编程——第二章 java基础语法
第二章 java基础语法 1. java关键字 abstract boolean break byte case catch char class const continue default do ...
- RxJava2实战--第二章 RxJava基础知识
第二章 RxJava基础知识 1. Observable 1.1 RxJava的使用三步骤 创建Observable 创建Observer 使用subscribe()进行订阅 Observable.j ...
- 第二章 impala基础使用
第二章 impala基本使用 1.impala的使用 1.1.impala-shell语法 1.1.1.impala-shell的外部命令参数语法 不需要进入到impala-shell交互命令行当中即 ...
- (转)JAVA AJAX教程第二章-JAVASCRIPT基础知识
开篇:JAVASCRIPT是AJAX技术中不可或缺的一部分,所以想学好AJAX以及现在流行的AJAX框架,学好JAVASCRIPT是最重要的.这章我给大家整理了一些JAVASCRIPT的基础知识.常用 ...
- 《SQL 基础教程》第二章:查询基础
这一章的结构如下: SELECT 语句基础 算术运算符和比较运算符 逻辑运算符 SELECT 语句可用于查询数据,并且可以设定条件来查询具有特定值的记录.条件的设定就需要算数运算符.比较运算符和逻辑运 ...
- 第二章----python基础
概要:python是一种计算机编程语言,有自己的一套语法,编译器或者解释器负责把符合语法的程序代码翻译成CPU能识别的机器码,然后执行.python使用缩进来组织代码块,Python程序中大小写是敏感 ...
- 第二章 python基础(一)
第一节 Python文件类型 源代码 Python源代码的文件以“py”为扩展名,由Python程序解释,不需要编译 字节代码 Python源文件经编译后生成的扩展名为“pyc”的文件 编译方法 im ...
- 第二章 Python基础语法
2.1 环境的安装 解释器:py2 / py3 (环境变量) 开发工具:pycharm 2.2 编码 编码基础 ascii ,英文.符号,8位为一个东西,2**8 unicode ,万国码,可以表示所 ...
- 第二章 XHTML基础
1.一个网页,也就是一个XHTML文档,是由元素组成.元素定义了文本和图形在XHTML文档中的结构.XHTML文档的扩展名通常是.html或者htm. 2.XHTML元素使用XHTML标记定义,每个标 ...
- 第二章 Servlet基础
这章我们主要的目标 理解Servlet Servlet的编码和部署 Servlet生命周期 Servlet的配置 Servlet与容器交互 什么是Servlet -是运行在Web服务器或应用服务 ...
随机推荐
- python_0基础学习_day01
Python是一门动态解释型的强类型定义语言 一.变量 变量命名规则 由数字.字母.下划线组成 不能以数字开头 要具有描述性 要区分大小写 禁止使用python的关键字(在pycharm中关键字明明变 ...
- fiddler设置断点
1.有两种方法设置断点 before response:也就是发送请求之后,但是Fiddler代理中转之前,这时可以修改请求的数据 after response:也就是服务器响应之后,但是在Fiddl ...
- Java虚拟机学习笔记(三)--- 生存还是死亡
即便是可达性分析中不可达的对象,也不代表该对象一定被回收,一个对象被“宣判死刑”需要经过两次标记,第一次是被可达性算法标记为不可用,然后进入第二次筛选,筛选条件是对象是否有必要执行finalize() ...
- 使用CefSharp在.NET中嵌入Chromium
使用CefSharp可以在.NET轻松的嵌入Html,不用担心WPF与Winform 控件与它的兼容性问题,CefSharp大部分的代码是C#,它可以在VB或者其他.NET平台语言中来进行使用. 近几 ...
- Linux 使用命令 1
fold : Usage: fold [OPTION]... [FILE]...Wrap input lines in each FILE (standard input by default), w ...
- Python RPC 之 gRPC
gRPC 简介: gRPC 是一款高性能.开源的 RPC 框架,产自 Google,基于 ProtoBuf 序列化协议进行开发,支持多种语言(Golang.Python.Java等),本篇只介绍 Py ...
- hdu6703_array
题意 给定一个1到\(n\)的全排列,两种操作,将\(a_{pos}\)修改为\(a_{pos}+1000000\),询问第一个大于等于\(k\)的且不在\(a_1...a_r\)的数. 分析 由于\ ...
- PrintWriter out = response.getWriter();乱码解决
resopnse request的乱码问题 今天在改项目时,发现这个简单又容易忽视在问题.说起这个问题,比较简单,但也比较容易忽视.下面就具体讲讲这个问什么会出现乱码问题. request乱码指的 ...
- node.js的Promise对象的使用
Promise对象是干嘛用的? 将异步操作以同步操作的流程表达出来 一.Promise对象的定义 let flag = true; const hello = new Promise(function ...
- 90001PS相关操作
第一章 PS基础操作 1.1 PS界面介绍 (1)界面包含:菜单栏.状态样式栏.工具栏.绘图区域.工作区. (2)布局可以在左上角进行切换,区分主要为工作区的侧重点不同. (3)布局想恢复可在窗口 ...