Kotlin 基础语法

Kotlin 徽标

1. 🌟 Kotlin:Java 的“超级进化体”?

Kotlin 是一门由 JetBrains 开发的 现代静态类型编程语言,支持 JVM、Android、JavaScript、Native 等多平台:

适用于 JVM 的 Kotlin 编程语言Android 浏览器原生

Kotlin 与 Java 深度兼容,Kotlin 会编译为 JVM 字节码,与 Java 共享运行环境(JVM);并且 Kotlin 与 Java 之间拥有 100% 互操作性,这意味着 Kotlin 可以和所有现有的 Java 源代码和库配合使用,即在同一项目中可混合调用 Java 和 Kotlin 代码。这样的特性允许公司逐步从 Java 迁移到 Kotlin,而无需重写整个项目。

2. 安装 Java 和 Kotlin 开发环境

你可以通过以下几种方式来开始 Kotlin 开发:

  • 使用 IntelliJ IDEA 或 Android Studio: 这两款工具都原生支持 Kotlin,可以直接创建 Kotlin 项目。
  • 使用在线 Kotlin 编译器: 如果你不想安装任何东西,可以访问 Kotlin 官方在线编译器,直接在浏览器中编写、运行 Kotlin 代码。

3. Kotlin 基础语法

输出 Hello World 示例:

fun main() {println("Hello, World!")
}
  • fun 是定义函数的关键字,main 是程序的入口函数。
  • println 用来输出信息到控制台。

4. 变量和常量

在开始使用变量之前,我们必须先声明它。为了声明变量,Kotlin 提供了两个关键字 声明变量:

  • var(for variable
  • val(for value

4.1. 变量

变量是程序中最常用的元素之一。变量是值的存储,可以是字符串、数字或其他内容。每个变量都有一个名称(或标识符)以区别于其他变量。可以通过变量的名称访问值。

Kotlin 中使用 var 关键字声明一个变量:

fun main() {var age: Int = 25println("初始年龄:$age")age = 26 // 修改变量值println("修改后的年龄:$age")
}

控制台输出结果:

image-20250318102450036

4.2. 常量

变量是程序中最常用的元素之一。常量是不可变的变量,一旦初始化后不能再改变它的值。Kotlin 提供了 valconst 两种方式来声明常量。

4.2.1. 使用 val 声明常量

val 声明只读变量,即在运行时一旦赋值后不能再改变它的值。虽然 val 声明的变量不能重新赋值,但它在运行时是可以参与计算的。

fun main() {val pi: Double = 3.14159  // 声明一个常量 piprintln("圆周率的值是:$pi")
}

运行结果:

圆周率的值是:3.14159

如果我们试图修改只读变量的值时,IDEA 会提示 Val cannot be reassigned 错误:

image-20250318104321740

🐖 val 只保证了变量引用的不可变性(对于引用类型),虽然禁止重新分配变量,但对引用类型的对象内部状态是允许修改的。

4.2.2. 使用 const 声明编译时常量

const 关键字声明编译时常量(带有 val),必须是在编译时就确定变量的值。通常用于声明那些在程序运行期间不会改变的值,并且在整个程序中是常量。它只能用于 Top-level(顶层)变量或 object 中的属性,且必须是基本数据类型(例如 Int, Double, String 等)。

const val PI : Double = 3.14159  // 声明一个常量 pifun main() {println("圆周率的值是:$PI")
}

运行结果:

圆周率的值是:3.14159

当我们在局部函数或类的成员变量中使用 const 声明常量时,IDEA 会提示 Modifier 'const' is not applicable to 'local variable' 错误:

image-20250318105701362

4.3. 命名规则

在声明变量时,我们需要遵循一些基本的命名规则和惯例:

4.3.1 基本命名规则
  • 变量名必须由字母、数字和下划线组成,但必须以字母或下划线开头
  • Kotlin 是区分大小写的语言,变量 nameName 是不同的。
  • 避免使用 Kotlin 关键字(例如 if, while, return, val, var 等),它们不能作为变量名。如果确实需要使用关键字,可以通过反引号(`)包裹来实现。
4.3.2 命名惯例
  • 变量:使用 小写字母驼峰命名法(camelCase) 来命名变量
  • 常量:使用 全大写字母下划线 分隔单词(UPPER_SNAKE_CASE
  • 类名和接口:使用 大驼峰命名法(PascalCase),即每个单词的首字母大写
  • 函数:使用 小写字母驼峰命名法(camelCase)
  • 属性:使用 小写字母驼峰命名法(camelCase)

5. 数据类型

5.1. 基本数据类型

Kotlin 是强类型语言,提供了多种基本数据类型,涵盖了数值、布尔、字符以及字符串:

  • 数值类型Int, Long, Short, ByteDoubleFloat
  • 布尔类型Boolean
  • 字符类型Char
  • 字符串类型String
5.1.1. 数值类型
  • Int: 整型,表示 32 位带符号整数,范围从 -2,147,483,6482,147,483,647

    val age: Int = 25
    
  • Long: 长整型,表示 64 位带符号整数,范围从 -9,223,372,036,854,775,8089,223,372,036,854,775,807

    val distance: Long = 1000000000L
    
  • Short: 短整型,表示 16 位带符号整数,范围从 -32,76832,767

    val height: Short = 180
    
  • Byte: 字节型,表示 8 位带符号整数,范围从 -128127

    val byteValue: Byte = 100
    
  • Float: 单精度浮点数,表示 32 位浮点数,适合存储小范围的小数。

    val temperature: Float = 36.6f
    
  • Double: 双精度浮点数,表示 64 位浮点数,适合进行高精度计算。

    val pi: Double = 3.14159
    

🐖 对于大数字数值,Kotlin 支持使用下划线(_)来提高可读性:

fun main() {val oneMillion = 1_000_000  // 表示 1000000val largeNumber = 1_234_567_890  // 表示 1234567890val binaryNumber = 0b1010_1011_1100_1111  // 二进制表示val hexNumber = 0xAB_CD_EF  // 十六进制表示
}
  • 下划线 只能用作分隔符,不能出现在数字的开始或结束。
  • 可以根据需要添加任意数量的下划线。
  • 下划线不影响数字的实际值,它仅用于视觉上的分隔。
5.1.2. 布尔类型
  • Boolean: 布尔类型,表示 truefalse,通常用于条件判断。

    val isAdult: Boolean = true
    
5.1.3. 字符类型
  • Char: 字符类型,表示一个 Unicode 字符。用单引号 ' 包围。

    val grade: Char = 'A'
    
5.1.4 字符串类型
  • String: 字符串类型,表示一系列字符。可以用双引号 " 包围字符串。

    val name: String = "Kotlin"
    

5.2. 类型推断

类型推断(Type Inference)是 Kotlin 编译器的一个强大特性,允许编译器在没有显式指定类型的情况下推断出变量或表达式的类型。

这使得我们在声明时不需要显式声明类型 ,Kotlin 编译器会根据变量的初始值自动推断出变量的类型。

fun main() {val x:Int = 42val name:String = "Alice"val pi:Double = 3.14
}

在这个例子中,Kotlin 编译器会自动推断出 xInt 类型;变量 name 类型被推断为 String

image-20250318144808884

在 IDEA 中变量名后的类型显示为暗灰色,提示我们存在冗余:

image-20250318144632776

5.3. 类型检测

类型检测(Type Checks)用于判断对象是否属于某个特定类型。

Kotlin 主要通过 is 操作符检查对象是否是指定类型的实例。它相当于 Java 中的 instanceof

基本语法

if (obj is Type) {// obj 是 Type 类型的实例,可以安全使用
} else {// obj 不是 Type 类型的实例
}

5.4. 类型转换

5.4.1. 强制类型转换 (as)

as 用于进行强制类型转换。如果对象不能转换为指定类型,Kotlin 会抛出 ClassCastException 转换异常。因此,使用 as 时需要确保对象的实际类型与目标类型一致。

fun forceConvert(obj: Any) {val str = obj as String  // 如果 obj 不是 String 类型,这里会抛出 ClassCastExceptionprintln(str.length)
}
5.4.2. 安全类型转换 (as?)

as? 是一个安全的转换操作符。如果转换成功,它会返回转换后的类型;如果转换失败,它会返回 null,而不会抛出异常。

fun safeConvert(obj: Any) {val str = obj as? String  // 如果 obj 不是 String 类型,str 会是 nullprintln(str?.length ?: "不是字符串")  // 如果 str 为 null 输出 "不是字符串"
}
5.4.3. 智能类型转换

当使用 is 操作符进行类型检测时,Kotlin 会自动将该对象转换为检测的类型,我们可以直接访问该类型的属性和方法。

例如,当 obj is String 时,我们可以直接使用 objString 类型方法(如 .length),而不需要显式地进行转换。

fun printStringLength(obj: Any) {if (obj is String) {// 在这里 obj 被智能转换为 String 类型,可以直接使用 String 类型的方法println("字符串的长度是: ${obj.length}")} else {println("不是一个字符串")}
}

6. 控制流程

Kotlin 的控制流程包括条件判断、循环控制、跳出和返回等基本结构。

6.1. 条件判断

6.1.1. if 表达式

if 表达式是一种控制流语句,用于根据条件执行不同的代码块,与 Java 类似,但 Kotlin 的 if 可以作为表达式使用,这意味着它能像函数调用或赋值操作那样返回一个值。

  1. 基本语法

    if (condition) {// 如果条件为真,执行这里的代码
    } else {// 如果条件为假,执行这里的代码
    }
    
  2. 多个条件的 if-else

    val x = 10
    if (x < 5) {// x < 5
    } else if (x == 5) {// x == 5
    } else {// x > 5
    }
    
  3. 作为表达式使用,将 if 的结果赋值给变量

    val max = if (x > y) x else y
    println(max)  // 输出最大值
    
6.1.2. when 表达式

when 语法类似于 Java 中的 switch 语句,但更为灵活。它可以用来匹配各种条件,如常量、范围、类型等。

  1. 基本语法

    when (variable) {value1 -> {// 执行代码块}value2 -> {// 执行代码块}else -> {// 默认代码块}
    }
    
  2. 表达式作为条件

    when 不仅仅能匹配常量,还能匹配表达式:

    val x = 10
    when {x % 2 == 0 -> println("x is even")else -> println("x is odd")
    }
    
  3. 范围匹配

    when 可以检查一个值是否在某个范围内:

    val x = 5
    when (x) {in 1..10 -> println("x is between 1 and 10")!in 11..20 -> println("x is not between 11 and 20")else -> println("x is out of range")
    }
    
  4. 类型匹配

    when 也可以根据对象的类型来进行判断:

    fun printType(obj: Any) {when (obj) {is String -> println("It's a String")is Int -> println("It's an Integer")else -> println("Unknown type")}
    }
    
  5. 多个条件匹配

    可以在 when 中使用逗号分隔多个条件:

    val x = 3
    when (x) {1, 3, 5 -> println("x is odd")2, 4, 6 -> println("x is even")else -> println("Unknown")
    }
    

6.2. 循环控制

6.2.1. for 循环

for 用于循环遍历任何提供了迭代器的对象(如 ListSet 等) 。基本语法如下:

for (item: Int in ints) {// ......
}
遍历数组或集合

Kotlin 的 for 循环也可以用于遍历数组或集合。

val arr = arrayOf(1, 2, 3, 4, 5)
for (i in arr) {println(i)
}
数字区间遍历
  1. 遍历范围(闭区间)

    在数字区间上范围遍历可以通过 .. 运算符来创建一个闭区间(包含开始值和结束值):

    // 1 <= i <= 5
    for (i in 1..5) {print(i) // 12345
    }
    
  2. 遍历范围(半开区间)

    使用 until 关键字可以创建一个半开区间,遍历时不包括结束值:

    // 1 <= i < 5
    for (i in 1 until 5) {print(i) // 1234
    }
    
  3. 步长遍历

    通过 step 关键字指定步长来控制每次遍历的增量,实现跳步:

    // 10<= i <=1
    for (i in 1..10 step 2) {print(i) // 13579
    }
    
  4. 倒序遍历

    使用 downTo 可以创建一个递减的范围:

    // 1 <= i <= 5
    for (i in 5 downTo 1) {println(i) // 54321
    }
    
6.2.2. while 循环

Kotlin 中的 whiledo-while 循环与 Java 类似,用于在条件为 true 时重复执行某个代码块:

  • while 循环在每次执行之前检查条件,如果条件为 false,则不会执行循环体。
  • do-while 循环先执行一次循环体,然后再检查条件,因此保证至少执行一次。
while (condition) {// 循环体
}do {// 循环体
} while (condition)

6.3. 跳出和返回

与 Java 一样,Kotlin 中也使用 returnbreakcontinue 作为控制流程的关键字,它们用于在循环和函数中实现不同的跳转行为。

6.3.1. return

return 关键字用于从函数中返回,并可以指定返回值。如果在函数中调用 return,函数会立即结束,控制流会返回到调用该函数的地方。如果是 Unit 类型(即没有返回值的函数),则 return 后不需要指定值。

fun add(a: Int, b: Int): Int {return a + b
}

return 不仅用于函数中,也可以用于跳出嵌套的循环(通常与标签一起使用)。

6.3.2. break

break 关键字用于立即跳出循环,不再执行后续的循环体代码。在嵌套循环中,break 会终止最内层的循环,程序将继续执行 break 后的代码。

fun main() {for (i in 1..5) {if (i == 3) {break  // 当 i 等于 3 时,跳出循环}println(i)}println("循环结束")
}

在这个例子中,循环在 i == 3 时通过 break 跳出,因此数字 3 和 4 都不会被打印出来。控制台输出如下:

image-20250319094646094

6.3.3. continue

continue 关键字用于跳过当前循环的剩余部分,直接进行下一次循环的条件判断。它不会终止循环,只会跳过当前迭代的剩余部分。

fun main() {for (i in 1..5) {if (i == 3) {continue  // 跳过 i 为 3 的这次循环}println(i)}
}

在这个例子中,continue 跳过了 i == 3 时的打印操作,导致 3 没有被打印出来,其他数字依然按顺序输出:

image-20250319094757063

6.3.4. 标签(label)

标签label)是一种用于标识代码块(如循环或函数)的方式,允许指定跳出特定的代码块或循环。标签通常与 breakreturn 关键字一起使用,避免了在嵌套的循环或代码块中只依赖于内层结构的 breakreturn,可以显式地指定跳出某个特定的循环或函数。

标签语法

标签的定义通常是通过在代码块前加上一个名称并使用 @ 符号:

labelName@ 代码块
使用标签与 break 跳出嵌套循环
fun main() {outerLoop@ for (i in 1..5) {for (j in 1..5) {if (i == 3 && j == 3) {println("Found at i=$i, j=$j, jumping out of both loops")break@outerLoop  // 跳出外层循环}println("i=$i, j=$j")}}println("Loop exited.")
}

在这个例子中,我们给外层循环加了一个标签 outerLoop@。当我们在内层循环中遇到 i == 3j == 3 的时候,通过 break@outerLoop 跳出的是外层循环,而不是内层循环。通常,break 只会跳出当前循环,但是通过使用标签,我们能控制跳出嵌套结构中的特定循环:

image-20250319101519543

标签与 return 的结合使用

Kotlin 中函数可以使用函数字面量、局部函数与对象表达式实现嵌套。

return 默认的行为是从外层函数返回。标签限定之后的 return@标签可以实现从 lambda表达式中返回,不影响外层函数的返回。

fun foo() {listOf(1, 2, 3, 4, 5).forEach {if (it == 3) return // 非局部直接返回到 foo() 的调用者println(it)}println("this point is unreachable")
}

上述代码执行时,由于 return 的默认行为,在 (it == 3) 时会跳出循环直接从外层函数 foo() 返回,输出结果:

image-20250319110928426

如果我们只想跳出循环,不想直接从外层函数 foo() 返回,就需要配合标签使用:

fun foo() {val list = listOf(1, 2, 3)list.forEach forEach@{if (it == 2) return@forEachprintln(it)}println("This will be printed")
}

使用标签的 return@forEach 会指定跳出循环,不会影响 foo() 函数的执行。"This will be printed" 会被打印出来。

image-20250319111534143

🐖 return@标签 在非内联函数中使用是不允许的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/36733.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于RAGFlow本地部署DeepSeek-R1大模型与知识库:从配置到应用的全流程解析

作者&#xff1a;后端小肥肠 &#x1f34a; 有疑问可私信或评论区联系我。 &#x1f951; 创作不易未经允许严禁转载。 姊妹篇&#xff1a; DeepSpeek服务器繁忙&#xff1f;这几种替代方案帮你流畅使用&#xff01;&#xff08;附本地部署教程&#xff09;-CSDN博客 10分钟上手…

uniapp APP权限弹框

效果图 第一步 新建一个页面&#xff0c;设置透明 {"path": "pages/permissionDisc/permissionDisc","style": {"navigationBarTitleText": "","navigationStyle": "custom","app-plus": {&…

【深度学习与大模型基础】第7章-特征分解与奇异值分解

一、特征分解 特征分解&#xff08;Eigen Decomposition&#xff09;是线性代数中的一种重要方法&#xff0c;广泛应用于计算机行业的多个领域&#xff0c;如机器学习、图像处理和数据分析等。特征分解将一个方阵分解为特征值和特征向量的形式&#xff0c;帮助我们理解矩阵的结…

麒麟V10 arm cpu aarch64 下编译 RocketMQ-Client-CPP 2.2.0

国产自主可控服务器需要访问RocketMQ消息队列&#xff0c;最新的CSDK是2020年发布的 rocketmq-client-cpp-2.2.0 这个版本支持TLS模式。 用默认的版本安装遇到一些问题&#xff0c;记录一下。 下载Releases apache/rocketmq-client-cpp GitHubhttps://github.com/apache/roc…

Moonlight-16B-A3B: 变革性的高效大语言模型,凭借Muon优化器打破训练效率极限

近日&#xff0c;由Moonshot AI团队推出的Moonlight-16B-A3B模型&#xff0c;再次在AI领域引发了广泛关注。这款全新的Mixture-of-Experts (MoE)架构的大型语言模型&#xff0c;凭借其创新的训练优化技术&#xff0c;特别是Muon优化器的使用&#xff0c;成功突破了训练效率的极…

在windows下安装windows+Ubuntu16.04双系统(下)

这篇文章的内容主要来源于这篇文章&#xff0c;为正式安装windowsUbuntu16.04双系统部分。在正式安装前&#xff0c;若还没有进行前期准备工作&#xff08;1.分区2.制作启动u盘&#xff09;&#xff0c;见《在windows下安装windowsUbuntu16.04双系统(上)》 二、正式安装Ubuntu …

一次Linux下 .net 调试经历

背景&#xff1a; Xt160Api, 之前在windows下用.net调用&#xff0c;没有任何问题。 但是移植到Linux去后&#xff0c;.net程序 调用 init(config_path) 总是报错 /root/test 找不到 traderApi.ini (/root/test 是程序目录) 然后退出程序 解决过程: 于是考虑是不是参数传错了&…

AI爬虫 :Firecrawl的安装和详细使用案例(将整个网站转化为LLM适用的markdown或结构化数据)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 1. Firecrawl概述1.1 Firecrawl介绍1.2 Firecrawl 的特征1.3 Firecrawl 的功能1.4 Firecrawl的 API 密钥获取2. 安装和基本使用3. 使用 LLM 提取4. 无模式提取(curl语句)5. 使用操作与页面交互6. Firecrawl Cloud7. 移…

【Java集合夜话】第1篇:拨开迷雾,探寻集合框架的精妙设计

欢迎来到Java集合框架系列的第一篇文章&#xff01;&#x1f339; 本系列文章将以通俗易懂的语言&#xff0c;结合实际开发经验&#xff0c;带您深入理解Java集合框架的设计智慧。&#x1f339; 若文章中有任何不准确或需要改进的地方&#xff0c;欢迎大家指出&#xff0c;让我…

网络安全知识:网络安全网格架构

在数字化转型的主导下&#xff0c;大多数组织利用多云或混合环境&#xff0c;包括本地基础设施、云服务和应用程序以及第三方实体&#xff0c;以及在网络中运行的用户和设备身份。在这种情况下&#xff0c;保护组织资产免受威胁涉及实现一个统一的框架&#xff0c;该框架根据组…

企业级云MES全套源码,支持app、小程序、H5、台后管理端

企业级云MES全套源码&#xff0c;支持app、小程序、H5、台后管理端&#xff0c;全套源码 开发环境 技术架构&#xff1a;springboot vue-element-plus-admin 开发语言&#xff1a;Java 开发工具&#xff1a;idea 前端框架&#xff1a;vue.js 后端框架&#xff…

Web爬虫利器FireCrawl:全方位助力AI训练与高效数据抓取

Web爬虫利器FireCrawl&#xff1a;全方位助力AI训练与高效数据抓取 一、FireCrawl 项目简介二、主要功能三、FireCrawl应用场景1. 大语言模型训练2. 检索增强生成&#xff08;RAG&#xff09;&#xff1a;3. 数据驱动的开发项目4. SEO 与内容优化5. 在线服务与工具集成 四、安装…

[HelloCTF]PHPinclude-labs超详细WP-Level 6Level 7Level 8Level 9-php://协议

由于Level 6-9 关的原理都是通用的, 这里就拿第6关举例, 其他的关卡同理 源码分析 定位到代码 isset($_GET[wrappers]) ? include("php://".$_GET[wrappers]) : ; 与前几关发生变化的就是 php:// 解题分析 这一关要求我们使用 php协议 php:// 协议 php://filte…

《Linux 网络架构:基于 TCP 协议的多人聊天系统搭建详解》

一、系统概述 本系统是一个基于 TCP 协议的多人聊天系统&#xff0c;由一个服务器和多个客户端组成。客户端可以连接到服务器&#xff0c;向服务器发送消息&#xff0c;服务器接收到消息后将其转发给其他客户端&#xff0c;实现多人之间的实时聊天。系统使用 C 语言编写&#x…

Maven生命周期

三套生命周期&#xff0c;项目清理&#xff0c;项目构建&#xff0c;项目生成 我们主要关注五个阶段 clean&#xff1a;移除上一次构建生成的文件compile&#xff1a;编译项目源代码test&#xff1a;使用合适的单元测试框架运行测试package&#xff1a;将编译后的文件打包&am…

【JVM】内存区域划分,类加载机制和垃圾回收机制

本篇内容为了解 JVM 的内存区域划分&#xff0c;类加载机制&#xff0c;垃圾回收机制。实际开发中几乎用不到&#xff0c;但为了某些情况我们又不得不了解。 目录 一、JVM中的内存区域划分 1.1 内存区域划分考点 二、JVM的类加载机制 2.1 类加载流程 2.2 类加载什么时候会…

v-自定义权限指令与v-if互相影响导致报错Cannot read properties of null (reading ‘insertBefore‘)

项目场景&#xff1a; vue3vite项目中报错Cannot read properties of null (reading ‘insertBefore‘) 原因分析&#xff1a; :v-自定义权限指令与v-if互相影响 <el-button text bg type"primary" click"handleWrite(detailData,项目填报)" v-hasPe…

qt下载和安装教程国内源下载地址

qt不断在更新中&#xff0c;目前qt6日渐成熟&#xff0c;先前我们到官方下载或者国内镜像直接可以下载到exe文件安装&#xff0c;但是最近几年qt官方似乎在逐渐关闭旧版本下载通道&#xff0c;列为不推荐下载。但是qt5以其广泛使用和稳定性&#xff0c;以及积累大量代码使得qt5…

k8s1.30 部署calio网络

一、介绍 网路组件有很多种&#xff0c;只需要部署其中一个&#xff0c;推荐calio。 calio是一个纯三成的数据中心网络方案&#xff0c;calico支持广泛的平台。如k8s&#xff0c;openstack等。 calio在每一个计算节点利用linux内核&#xff0c;实现了一个高效的虚拟路由器来…

navicat导出文件密码解密

文章目录 一、概念二、导出文件1、创建的数据库连接信息2、导出带密码的连接信息3、查看导出后的文件 三、Python代码解析四、参考地址 一、概念 Navicat中导出的带密码的文件后缀是.ncx结尾的&#xff0c;里面是xml格式的文件&#xff0c;存储了数据库的连接&#xff0c;方便…