上篇已提(tu)到(cao)Java中的各种坑。习惯了C#的各种特性和语法糖后,再转到Java感觉比较别扭。最后本着反正Java也不是很熟悉,干脆再折腾折腾其他语言的破罐子破摔的心态,逛了一圈JVM语言,最终决定转Kotlin。

为何选择Kotlin

项目遭遇人员变动,包括我在内就剩两个人开发,转型成本低,代码质量容易控制。

JVM语言。号称与Java 100%兼容。实际使用的确能够与Java几乎无缝地相互调用,基本上可以无缝迁移,完美兼容Java生态。

OOP。目前OOP仍是主流,方便后续交接或者其它新加入的开发成员上手。

静态类型。在选择语言的时候也考虑过像Groovy,JRuby等的动态类型语言。然而俗话说得好,动态一时爽,重构火葬场。当项目变大的时候,静态类型支持的较为完善的语义分析能够帮助项目快速整理、重构代码。并且引入很多函数式特性后,静态类型语言的开发效率与爽感,不比动态类型语言低多少。

吸收了一些函数式特性。除了常见的lambda,map,filter,reduce之外,还吸收了ruby的一些如对象上下文切换、代码块语法糖等便捷的特性(但是也可能导致代码可读性下降)。

对JetBrain的信任。JetBrain在静态分析的成果上有目共睹。相信JetBrain设计的语言应该会比较有品位(然而严格得不近人情的null safety是有点让人纠结)。

最后,就是刚好看到Kotlin,确认了眼神……

Kotlin好用的特性

Lambda

牺牲了CE使得Lambda不像Java中那么多的约束。引入类似Ruby代码块的写法(默认it参数),让代码看起来比较好看,虽然我个人不是很喜欢这种默认约定,但是用起来真香。

面向表达式

不同于其他语言,Kotlin里的if else,try catch等都是表达式,我们可以直接这样子写代码:

val y = if (x % 2 == 0) "even" else "odd"

val z = try { readFromFile() } catch (ex: IOException) { "" }

DSL

Lambda是最后一个参数时,可以写在括号外面(学自ruby)。主要是用来让回调比较好看,和实现DSL。

val ls = listOf(1, 2, 3)

ls.map { 2 * it } // returns [2, 4, 6]

Receiver。Kotlin不仅有纯函数类型,还可以通过Receiver声明类的方法类型。这个特性可以用来实现类的方法扩展、this切换的功能。

下面代码给Int扩展了个double方法:

val double = fun Int.() = 2 * this

val x = 3.double() // x = 6

下面例子通过切换this实现了一个类似C#初始化对象的方法:

class Obj(init: Obj.() -> Unit) {

var prop1: Int = 0

var prop2: String = ""

init {

init(this)

}

}

val obj = Obj {

prop1 = 1

prop2 = "abc"

}

其他

很多好用的方法,像listOf,mapOf。to操作符等

……

Kotlin的坑

Kotlin没有final,但是有open。

Kotlin中Class默认都是不能继承的。需要继承的Class要在声明的地方加上open修饰。另外提一下有个插件叫all-open,专门用来让所有Kotlin的类变为可继承的……

注解的继承

Kotlin不支持可继承的注解。

纯的容器类型

List,Map不能修改其内部存储的元素。需要修改应该用MutableList和MutableMap。

Lombok

号称和Java 100%兼容,但是不能访问Lombok生成的方法!

因为Lombok的方法是编译期通过注解处理器(annotation processing)生成的,Kotlin编译时只调用了Javac,所以无法处理Lombok定义的方法。强制先编译Java代码,后编译Kotlin代码,可以解决这个问题,但是又会有新的问题:你不能在Java代码中调用Kotlin代码。所以如果你要混合使用Java和Kotlin的话,推荐所有数据类型都用Kotlin写。

val和var

var就是普通变量。val相当于const。平时尽量使用val,有益身心健康。

重头戏,null safety

Null safety是Kotlin宣传得最多的特性,但是我并没有放在“好用的特性”节中介绍,因为它的坑非常多,以至于我十分怀疑null safety的好处是否能抵消它带来的副作用。

所有类型默认都不包括null值,除非加个问号定义为Nullable类型。Nullable类型取值时,强制check null。如果调用Java代码,默认Java代码都是Nullable。不过从Java来的变量不做check null倒是不会报error,只报warning。如果运行时值为null的话,仍然会抛NullPointerException。Kotlin的null safety的特性其实只是一个编译器的特性,通过将null与其他类型区分开来,在类型检查的时候顺便检查了可能出现的NullPointerException,但是在运行时非Nullable的变量实际上也是可以放进去null值的(比如通过反射)。

由于非Nullable类型不被赋值为null值(废话),导致这些类型的变量可能会没有默认值!这是个严重的问题。如果是像Int,String这种比较像值的类型(其实也是引用类型)还好,可以有0,空字符串等默认值。而像自定义的类,这种类型的变量其实是个引用,如果不能默认为null的话,那么它的默认值的取值只能有这么几种方案:

类似C语言,未初始化的随机值:会产生更大更不确定硬隐蔽的问题。

定义一个“未初始化”的值:那么这个值和null有什么区别?又绕回来了。

类似C++,默认创建一个空对象:但是并非所有类都有默认构造函数,而且在拥有GC的语言中,创建空对象需要分配内存,还会调用构造函数中的逻辑。声明变量时引入这么多过程是非常不合适的。

所以,Kotlin最终选了一种简单粗暴的方案:禁止变量未初始化。

禁止变量未初始化的问题在于,当你需要定义大量的数据类的时候,你就知道有多蛋疼了——所有属性都必须有个初始值。这不仅需要多敲不少键盘,影响手指健康,当碰到属性是非Nullable的聚合时,也常常无法确定其初始值。我已经隐隐看到某些开发人员将所有变量都标记为Nullable的画面了……Kotlin自身也发现了这个问题,因此引入了lateinit特性,然而用起来仍然有点令人胆战心惊。

反序列化。即使是业务逻辑上明确了不会为null值的属性,你也无法保证网络上/数据库里传输过来的数据中,对应的属性会不会是null值,或者干脆漏了,所以就算model设计正确的,实际运行时可能还是会出现NullPointerException。我又隐约看到某些开发人员将所有变量都标记为Nullable的画面了……另外反序列化时,需要先生成一个空对象,也就是属性都没初始化的对象。当然Kotlin不会允许这么做的,所以还需要引入NoArg插件来自动生成无参数的构造函数……

类型擦除式泛型

为了和Java 100%兼容,Kotlin不得不跟着Java用类型擦除式泛型,也拥有了前面说过的类型擦除式泛型的所有坑。不过Kotlin可以使用内联函数来稍微缓解类型擦除的负面影响。比如可以这样定义json反序列化的方法:

inline fun parse(json: String): T = objectMapper.readValue(json, T::class.java)

return

Kotlin有两种方法定义一个匿名函数:lambda和anonymous function。当在这两种方法的函数体中使用return时,执行的语义是不同的。根据官方文档return会跳出最近的显示声明的函数或anonymous function。例如下面的return会直接跳出foo函数。

fun foo() {

listOf(1, 2, 3, 4, 5).forEach {

if (it == 3) return // non-local return directly to the caller of foo()

print(it)

}

println("this point is unreachable")

}

// outputs: 12

而下面这个只是当value == 3时跳过一次循环,相当于其他语言的continue

fun foo() {

listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {

if (value == 3) return // local return to the caller of the anonymous fun, i.e. the forEach loop

print(value)

})

print(" done with anonymous function")

}

// outputs: 1245 done with implicit label

或者也可以使用Label来指定执行return后跳到的位置(感觉像goto似的)。

fun foo() {

listOf(1, 2, 3, 4, 5).forEach lit@{

if (it == 3) return@lit // local return to the caller of the lambda, i.e. the forEach loop

print(it)

}

print(" done with explicit label")

}

另外,break和continue也是有类似的问题。

写在最后

最近家庭工作都比较忙,这短短的一篇转型踩坑记竟然写了个跨年。有些踩坑的记忆随着时间流逝以及用习惯了给慢慢淡化掉了,于是也没写进来。目前Java系这边的开发我尽量使用Kotlin,并没有碰到什么根本上的大问题,与Java的兼容性也挺好的,有精力的同学可以放心品尝。

kotlin t class.java_尝试Java,从入门到Kotlin(下)相关推荐

  1. 渭南java_渭南java语言入门教程视频

    把符捕获f表名称达式异常员的可生合条或成量.渭南类型量C件的作为字符成变串常,渭南姓名,同时也可以这样通引的进行方式赋值过索,选器得到的结定是要支.异异常和{内插.字持n常筛符串果一过滤,0新到此的文 ...

  2. Java 稳步成长、Kotlin 崛起、Go 保持独特风格,2020 年各大编程语言发展趋势一览...

    [编者按]步入 21 世纪 20 年代,我们向编程专家征求了他们对知名编程语言,以及近些年快速发展的编程语言的看法. 作者 | Zan McQuade,Amanda Quinn 译者 | 明明如月,责 ...

  3. 叮!您收到一份超值Java基础入门资料!

    摘要:Java语言有什么特点?如何最大效率的学习?深浅拷贝到底有何区别?阿里巴巴高级开发工程师为大家带来Java系统解读,带你掌握Java技术要领,突破重点难点,入门面向对象编程,以详细示例带领大家J ...

  4. Java RMI 入门

    Java RMI 入门 如何通信 实战 完整代码   Java RMI 指 JDK 内置的关于实现远程方法调用(Remote Method Invocation)的 API.这些 API 位于包 ja ...

  5. swagger 怎么去掉get delete_自学 Java 怎么入门?

    给你推荐一个写得非常用心的Java基础教程:码邦主2020年最新的Java视频教程 这个教程将Java的入门基础知识贯穿在一个实例中,逐步深入,可以帮助你快速进入Java编程的世界.万事开头难,逐步跟 ...

  6. 来入门一下kotlin吧

    Kotlin是什么? Kotlin是一种在java虚拟机上运行的静态类型的编程语言,被称之为 Android 世界的Swift,由 JetBrains 设计开发并开源. Kotlin的优势! Kotl ...

  7. python kotlin_用Java和Python模仿Kotlin构建器

    python kotlin 介绍 Kotlin可能现在是我最喜欢的语言,可能它提供的最酷的功能之一是基于几个功能构建的类型安全的生成器(稍后解释). 我发现自己真的很想在其他两种主要语言(Java和P ...

  8. java 8入门与实践_30个Java入门技巧和最佳实践

    java 8入门与实践 Java是最流行的编程语言之一-无论是Win应用程序,Web应用程序,移动,网络,消费电子产品,机顶盒设备,Java随处可见. 在Java上运行的设备超过30亿. 据Oracl ...

  9. java gradle入门_Gradle入门:我们的第一个Java项目

    java gradle入门 这篇博客文章描述了如何使用Gradle编译和打包一个简单的Java项目. 我们的Java项目只有一个要求: 我们的构建脚本必须创建一个可执行的jar文件. 换句话说,我们必 ...

最新文章

  1. 支付宝钱包支付iOS SDK的方法
  2. vsftp的被动模式
  3. Android之数据转化崩溃问题
  4. 基于Opencv--图像上采样
  5. 从爬取的文章 HTML 中提取出中文关键字
  6. layui option 动态添加_layuiselect如何动态添加option
  7. vnpy学习_02各文件功能梳理
  8. Elasticsearch5.X Centos7安装过程
  9. vue.js笔记1.0
  10. 年会活动现场抽奖签到互动小程序开发制作
  11. 怎么才能写好技术文档——这是我的全部经验
  12. 第一章:计算机基础知识——知识点整理
  13. Servlet容器与Servlet的关系
  14. ionic4基础教程(案例和实战小demo)
  15. 正则表达式, email格式验证,邮箱地址验证
  16. 禅道 upgrade.php,zentao禅道安装升级
  17. Python软件的下载安装教程
  18. Windows Server 2016-客户端加域端口汇总
  19. 程序员,你真的会写简历吗?
  20. 阿里云快照如何恢复到另外一台服务器

热门文章

  1. C++11 移动语义与右值引用
  2. ARP-地址解析协议
  3. MongoDB在单机上搭建分片副本集群(windows)
  4. Https iOS需要做的事
  5. spring boot 定时间任务
  6. 如何吸引小白用户爱上你的游戏?
  7. spring配置文件中id与name
  8. hashmap面试问题
  9. Spring 层次性依赖查找Bean
  10. Spring Bean初始化的几种方法以及执行顺序