kotlin语言的优势

[TOC]

什么是kotlin 语言?

Kotlin 是一种在 Java 虚拟机JVM上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBrains 设计开发并开源。

Kotlin 可以编译成Java字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。

在Google I/O 2017中,Google 宣布 Kotlin 成为 Android 官方开发语言。

kotlin 能做什么?

image

  • 开发Android App
  • 服务端开发

    既然Kotlin是基于JVM的编程语言,那么自然而然就可以使用所有基于JVM的服务端框架。下面是几个Kotlin官方文档推荐的框架。

    • Spring:一种开源框架,是为了解决企业应用程序开发复杂性问题而创建的。从Spring 5开始,Spring就已经支持Kotlin的新特性了,并可以使用Spring在线生成器(https://start.spring.io)生成基于Kotlin的工程,在Spring boot 2.0中Kotlin也将成为第一类开发语言。。

    • Vert.x:用于建立基于JVM的响应式Web应用的框架。

    • Ktor:由JetBrains发布的一款基于Kotlin的本地Web框架

    • kotlinx.html:是一种DSL(领域专用语言),用于在Web应用中生成HTML。Kotlin服务端框架和kotlinx.html的关系就像JSP和FreeMarker的关系一样,FreeMarker是基于Java的模板引擎。 使用FreeMarker,可以不依赖于HTML或其他技术,可以根据需要生成HTML或其他东西,也就是一种与具体渲染技术无关的技术。

  • 以JavaScript方式运行 kotlin.js
    Kotlin提供了生成JavaScript源代码的能力,也就是将Kotlin代码直接转换为JavaScript代码。目前,支持ECMAScript 5.1标准,未来会支持ECMAScript 6。

    注意,如果将Kotlin代码转换为JavaScript代码,在Kotlin代码中只能包含Kotlin标准库,不能包含任何JDK API以及任何第三方的Java Library API,任何不属于Kotlin本身(Kotlin语句和标准库)的部分在转换的过程中将被忽略。

  • Kotlin Script 脚本运行 可以像python 和 scala 一样写脚本运行,想想都兴奋呢!

  • Kotlin Native
    不是 Jni 的概念,它不仅仅是要与底层代码比如 C、C++ 交互,而且还要绕过 Jvm 直接编译成机器码供系统运行。也就是说,Kotlin 准备丢掉 Java 这根拐杖了!当然详细的内容我就不懂了,不敢吹牛了!

为什么要用kotlin

image

简洁

image image image

比如模型对象类:

data class User(var id : Long, var name: String, var email: String, var age Int)

或者

data class User(){
    var id : Long = 0
    var name: String?= null
    var email: String?= null
    var age = 0
}

这些内容省去了 getters、 setters、 equals()、 hashCode()、 toString() 以及 copy() 的内容。

看下同样的内容java怎么写的。

public class User {

    private long id;
    private String name;
    private String email;
    private String age;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}


函数式编程 和 lambda表达式
例 1

    //高阶函数变量
    var OnOptionListener : (()->Unit) ?= null
    
    //高阶函数接口定义
    fun setOnConfirmClickListener(listener : (()->Unit)){
        this.OnOptionListener = listener
    }
    //接口的使用
    exitDialog.setOnConfirmClickListener {
        //dosomething
    }
    
    

看看java 的写法

    //变量定义
    private OnOptionListener listener;
    //设置接口监听
    public void setOnConfirmClickListener(OnOptionListener listener) {
        this.listener = listener;
    }
    //定义接口
    public interface OnOptionListener{
        void onOption();
    }
    commonDialog.setOnConfirmClickListener(new AbsCommonDialog.OnOptionListener() {
        @Override
        public void onOption() {
            //dosomethin
        }
    });
    
    

例 2

    Handler().postDelayed({ 
            //dusomething
        }, 1000)
    //或一行表示
    Handler().postDelayed({ /*dusomething*/ }, 1000)

看看java 的写法

    new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //dosomething
            }
        }, 1000);

安全

彻底告别那些烦人的 NullPointerException——著名的十亿美金的错误。

补充插播一个改自 StackOverflow 帖子的段子:

杯具啊!我们公司有个职工姓 Null,当用他的姓氏做查询词时,把所有员工查询应用给弄崩溃了! 我该肿么办?

在 1965 年有人提出了这个计算机科学中最糟糕的错误,该错误比 Windows 的反斜线更加丑陋、比 === 更加怪异、比 PHP 更加常见、比 CORS 更加不幸、比 Java 泛型更加令人失望、比 XMLHttpRequest 更加反复无常、比 C 预处理器更加难以理解、比 MongoDB 更加容易出现碎片问题、比 UTF-16 更加令人遗憾。

“我把 Null 引用称为自己的十亿美元错误。它的发明是在1965 年,那时我用一个面向对象语言( ALGOL W )设计了第一个全面的引用类型系统。我的目的是确保所有引用的使用都是绝对安全的,编译器会自动进行检查。但是我未能抵御住诱惑,加入了Null引用,仅仅是因为实现起来非常容易。它导致了数不清的错误、漏洞和系统崩溃,可能在之后 40 年中造成了十亿美元的损失。近年来,大家开始使用各种程序分析程序,比如微软的 PREfix 和 PREfast 来检查引用,如果存在为非 Null 的风险时就提出警告。更新的程序设计语言比如 Spec# 已经引入了非 Null 引用的声明。这正是我在1965年拒绝的解决方案。” —— 《Null References: The Billion Dollar Mistake》托尼·霍尔(Tony Hoare),图灵奖得主

进入正题
image

Kotlin 可以保护你避免对可空类型的误操作 空的类型在编译时就编译不通过,使用IDEA的话会自动报红。 并且如果你检查类型是正确的,编译器会为你做自动类型转换,如下:

fun calculateTotal(obj: Any) {
    if (obj is Invoice)
        obj.calculateTotal()
}

一般可空的变量只需要在后面增加?即可放在空指针。

btn?.text = "按钮文字"
user?.let{
    tvName.text = it.name
    tvAge.text = it.age.toString()
    ...
}

互操作性

使用 JVM 上的任何现有库,因为有 100% 的兼容性,包括 SAM 支持,任何有java的地方就可以有kotlin。

import io.reactivex.Flowable
import io.reactivex.schedulers.Schedulers

Flowable
    .fromCallable {
        Thread.sleep(1000) //  模仿高开销的计算
        "Done"
    }
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.single())
    .subscribe(::println, Throwable::printStackTrace)

无论是 JVM 还是 JavaScript 目标平台,都可用 Kotlin 写代码然后部署到你想要的地方

import kotlin.browser.window

fun onLoad() {
    window.document.body!!.innerHTML += "<br/>Hello, Kotlin!"
}

工具友好性

IntelliJ 平台下的IDEA (包含AndroidStudio、PHPStrom、PyCharm等) 提供了很多智能提示不全等功能,java 一键转成kotlin,包括你复制java代码粘贴到kotlin文件里,也可以自动转换。
image image image

语法糖

遍历

for (l in list) {
    println("$l")
}
 
for ((k, v) in map) {
    println("$k -> $v")
}

for (i in 1..100) { ... }  // 闭区间:包含100
for (i in 1 until 100) { ... } // 不包含100
for (x in 2..10 step 2) { ... } // 按照步长为2增长
for (x in 10 downTo 1) { ... } //
if (x in 1..10) { ... } //判断x是否在1到10这个区间内

val list = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    list.filter { it%2==0 }             // 取偶数
            .map{ it*it }               // 平方
            .sortedDescending()         // 降序排序
            .take(3)                    // 取前 3 个
            .forEach { println(it) }    // 遍历, 打印

类扩展方法

//例 1
fun String.myToLowerCase(): String {
    return this.toLowerCase()
}
 
fun main(args: Array<String>) {
    println("this is test".myToLowerCase())
}

//例 2 
//冒泡排序的切换元素方法
fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] 
    this[index1] = this[index2]
    this[index2] = tmp
}

val list = arrayListOf(1, 3, 4, 6, 2, 7, 9, 8, 5, 0)
//原来的冒泡排序
for(i in 0 until list.size){
    for(j in i until list.size){
        if(list[i] > list[j]){
            val tmp = list[i]
            list[i] = list[j]
            list[j] = tmp
        }
    }
}

//改进后
for(i in 0 until list.size){
    for(j in i until list.size){
        if(list[i] > list[j]){
            list.swap(i, j)
        }
    }
}
//单独切换
list.swap(0, 1)

with 语法

val tvName = TextView(this)
with(tvName){
    setText("张三")
    setSingleLine()
    setTextColor(Color.WHITE)
}

对比java的写法

TextView tvName = new TextView(this);
tvName.setText("张三");  
tvName.setSingleLine();
tvName.setTextColor(Color.WHITE);

高阶函数

    //例 1
    //高阶函数接口定义
    fun setOnConfirmClickListener(listener : (()->Unit)){
        this.OnOptionListener = listener
    }
    fun setOnConfirmClickListener(listener : ((text : String)->Unit)){
        this.OnOptionListener = listener
    }
    //没有参数和只有一个参数时,调用的时候都可以把参数省略
    exitDialog.setOnConfirmClickListener {
        //dosomething
    }
    
    fun setOnConfirmClickListener(listener : ((id: Long, text : String)->Unit)){
        this.OnOptionListener = listener
    }
    //多个参数时
    exitDialog.setOnConfirmClickListener { id, text->
        println("id 是 $id,  文字是$text")
    }
    
    
    //例 2 
    val sum: (Int, Int) -> Int = { x, y -> x+y }
    val result = sum(1,2)
    
    // 例3 
    
    /**
     * 遍历获取路径下的文件
     * @param dir 上层路径
     * @param dirs 存储文件的列表
     * @param condition 条件
     */
    fun foreachFiles(dir: File, condition: ((file: File) -> Boolean)? = null) : ArrayList<String>{
        val dirs = arrayListOf<String>()
        dir.listFiles()?.forEach {
            if (it.isDirectory) {
                dirs.addAll(foreachFiles(it, condition))
            } else {
                if (condition != null) {
                    if (condition(it)) {
                        dirs.add(it.absolutePath)
                    }
                } else {
                    dirs.add(it.absolutePath)
                }
            }
        }
        return dirs
    }

    val kotlinSrcDir = File("D:\\java\\workspace\\javatest")

    val allFiles        = foreachFiles(kotlinSrcDir)
    val allKotlinFiles  = foreachFiles(kotlinSrcDir, { it.name.endsWith(".kt") })
    val allJavaFiles    = foreachFiles(kotlinSrcDir, { it.name.endsWith(".java") })
    val readmeFiles     = foreachFiles(kotlinSrcDir, { it.name == "README.md" })
    val allSmallFiles   = foreachFiles(kotlinSrcDir, { it.length() < 1024*1024 })

    println(allFiles)
    println(allKotlinFiles)
    println(allJavaFiles)
    println(readmeFiles)
    println(allSmallFiles)

例3的写法很特别,循环例遍历路径下的所有文件,而条件却写在了参数上,那么调用者可以随意的写入条件,不同的条件就得到不同的结果,这就得到了最大程度的私人定制。

默认参数 + 命名参数

结合默认参数,命名参数消除了构造者。

java 代码


  public static void main(String[] args){
        TestClass testClass = new TestClass();
        testClass.test();
        testClass.test("张三");
        testClass.test("张三", 18);
        testClass.test("张三", 18, 1.72f);
        testClass.test("张三", 18, 1.72f, "http://www.xx.com/aa.jpg");
        testClass.test("张三", "http://www.xx.com/aa.jpg");
    }

    public void test(){
        // dosomething
    }
    public void test(String name){
        // dosomething
    }
    public void test(String name, int age){
        // dosomething
    }
    public void test(String name, int age, float height){
        // dosomething
    }
    public void test(String name, int age, float height, String imagePath){
        // dosomething
    }
    public void test(String name, String imagePath){
        // dosomething
    }

kotlin 代码


    fun main(args: Array<String>){
        test()
        test("张三")
        test("张三", 18)
        test("张三", 18, 1.72f)
        test("张三", 18, 1.72f, "http://www.xx.com/aa.jpg")
        test("张三", imagePath =  "http://www.xx.com/aa.jpg")
    }

    fun test(name : String ?= null, age : Int = 0, height : Float = 0f, imagePath : String ?= null){
        // dosomething
    }

懒加载

val lazySum: Int by lazy {
    println("begin compute lazySum ...")
    var sum = 0
    for (i in 0..100)
        sum += i
    println("lazySum computed!n")
    sum // 返回计算结果
}
fun main(args: Array<String>) {
    println(lazySum)
    println(lazySum)
}
// 输出:
begin compute lazySum ...
lazySum computed!
5050
5050

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦