google为何选择kotlin?kotlin如何解决java开发痛点?
wptr33 2024-12-03 18:45 14 浏览
一、google为何选择kotlin?
我们先来聊点有趣的八卦:谷歌为何选择kotlin,而不是继续改造java?
谷歌选择kotlin的原因真的是因为kotlin比java更好用吗?
大叔可以肯定的说,“kotlin比java更好用”,这肯定不是谷歌选择kotlin的原因。
以谷歌的研发实力,完全有能力,参与到java的发展中来,让java变得越来越好用。甚至比kotlin还要好用。
2011~2014年java连续三年 拖更,2014年~2017年,又拖更三年。
之后恢复了发版节奏【1年2个版本】。随后的更新确实让java越来越好用了。
甚至有些人说,java越来越像kotlin了。
我们在上一篇中讨论的:
kotlin字符串支持,三引号""" java14也有这个特性了。【java14今年三月份发布的】
kotlin的use函数,自动关闭closeable java7 也有try-with-resources的写法,解决类似的问题。
我们下文会讨论的:
when表达式,java14,switch也支持了类似的表达式了。
智能类型转换 java14的类型转换也开始越来越智能了。
说这么多,想表达的观点就是: java完全可以越来越好用。谷歌完全可以参与到java的迭代,让java越来越好用,甚至可以坐等sun公司借鉴更多语言的特性。没有必要伤筋动骨,把android首选语言换成kotlin,说实话这么多开发者,换一门语言的成本得有多高。并不是所有开发者都像朋友们还有大叔这样热爱学习。
谷歌选择kotlin的最直接原因,是因为sun公司碰瓷。
2010开始sun公司 起诉 谷歌:在Android上使用Java代码侵犯版权和专利权。
历史是惊人的相似。sun公司曾经成功碰瓷过微软。哈哈哈。。。
13年后,sun公司,故技重施,你说谷歌愿意重蹈微软的覆辙吗?
我们再来,看看android官方网站,关于room的java的教程:
All rights reserved. Java is a registered trademark of Oracle and/or its affiliates.
谷歌的用到java的教程中,明确标出了:版权所有。Java是Oracle公司所有。
谷歌选择kotlin只是为了摆脱专利诉讼而已。当然kotlin自己也争气。确实表现优异。
再请大家吃一个瓜:
google前CEO,埃里克·施密特,担任过sun公司高管,而且是特别高的那种。
1983年,施密特加盟Sun公司,先后担任首席技术官和首席执行官。
首任工程部副总裁韦恩.罗森(Wayne Rosen),也曾经任职过sun公司。
以上,只是大叔个人观点,纯属意淫,没有sun公司和谷歌公司的实锤资料。请大家保持独立思考。
二、kotlin如何解决java开发痛点【续】?
我们进入今天的第二个主题。继续一个个语法特性来讲,kotlin如何解决java开发痛点。
没有看上一篇 kotlin如何解决java开发痛点,让程序员happier 的朋友们,可以先看下上一篇,这样会更有连续性。
2.1 操作符:== 和 ===
我们先从一道java考题入手。大叔还是一位亮仔的时候,被这道题折磨的痛并快乐着,哈哈~
大多数 java老鸟 都认识这道题。
JavaEqualMain.java
public static void intEqual(){
Integer int127First = 127;
Integer int127Second = 127;
System.out.println("int127First == int127Second :" + (int127First == int127Second));
Integer int128First = 128;
Integer int128Second = 128;
System.out.println("int128First == int128Second :" + (int128First == int128Second));
}
大叔的灵魂拷问:日志会输出什么?
大叔的灵魂拷问:日志会输出什么?
大叔的灵魂拷问:日志会输出什么?
眼熟吗,是不是面试的时候遇到过?
是不是大学考试的时候考过?哈哈~
日志输出:
int127First == int127Second :true
int128First == int128Second :false
原理解析:
public static void intEqual(){
Integer int127First = 127;
Integer int127Second = 127;
//因为 -128到127 的整数 都在常量池里
//所以 int127First 与 int127Second 指向了,常量池中同一个对象,所以这里输出true
System.out.println("int127First == int127Second :" + (int127First == int127Second));
Integer int128First = 128;
Integer int128Second = 128;
//因为128不在常量池里,所以 int128First和int128Second 是不同的对象,所以这里输出false
System.out.println("int128First == int128Second :" + (int128First == int128Second));
}
我们再来看看 kotlin的代码:
KtEqualMain.kt
fun intEqual() {
val int127First = 127
val int127Second = 127
println("int127First == int127Second :" + (int127First == int127Second))
val int128First = 128
val int128Second = 128
println("int128First == int128Second :" + (int128First == int128Second))
}
大叔的灵魂拷问:日志会输出什么?
大叔的灵魂拷问:日志会输出什么?
大叔的灵魂拷问:日志会输出什么?
日志输出:
int127First == int127Second :true
int128First == int128Second :true
对你没有看错,两个结果都是true。
why?
为什么?
kotlin 提供了两个相等操作符 == 和 ===
结构相等 ==:用 equals() 判断相等性
引用相等=== :判断两个引用是否指向同一对象
大叔自我拷问,结构相等这个操作符有什么用呢?他能解决什么痛点呢?
大叔自我拷问,结构相等这个操作符有什么用呢?他能解决什么痛点呢?
大叔自我拷问,结构相等这个操作符有什么用呢?他能解决什么痛点呢?
jvm中存在常量池机制,字符串、部分包装类对象有可能存在常量池,也可能不在常量池。
引用相等运算结果,与常量池耦合,如果两个对象都在常量池中,运算结果为true,如果有一个不在常量池中,或者都不在常量池中,即使两个对象内容相同,运算结果也是false。
导致,引用相等运算,有点复杂,一不留神可能就搞错了。
kotlin的结构相等,跟常量池无关了,直接通过equal方法判断,运算结果与常量池不耦合,不管对象在不在常量池,运算结果都是一样的。
不仅减少了初学者的学习成本。也减少了研发老鸟的犯错成本。
三等号“===” kotlin的三等号运算效果,就是java的双等号“==”,熟悉python的朋友,应该一点都不陌生。因为python也是这样的。
并且,并且,并且,kotlin中,结构相等 == 还会帮我们自动判空。我们看下面两段代码。
首先是java代码。JavaEqualMain.java
/**
* 判断字符串是否相等
*/
public static boolean isTextEqual(String str1, String str2){
if(str1 == str2){
return true;
}
if(str1 != null && str2 != null){//因为str1和str2可能有一个为null,所以我们要判空
return str1.equals(str2);
}
return false;
}
我们再看看看kotlin,怎么实现:KtEqualMain.kt
/**
* 判断字符串是否相等
*/
fun isTextEqual(str1: String?, str2: String?): Boolean {
return str1 == str2
}
是的,你没有看错,kotlin就是这么简洁。
kotlin的 isTextEqual()方法,会编译器被翻译成isTextEqual2():
fun isTextEqual2(str1: String?, str2: String?):Boolean{
return str1?.equals(str2) ?: (str1 === null)
}
上面这段代码段,是官网文档的解释。www.kotlincn.net/docs/refere…
kotlin不熟悉的同学,可能会比较迷茫。
大叔把他改一下,你就明白了。
fun isTextEqual3(str1: String?, str2: String?):Boolean{
if (str1 == null){
return str2 == null
}
return str1.equals(str2)
这就是,会自动判空的原因。
总结一下:
kotlin 提供了两个相等操作符 == 和 ===
== 【结构相等】,用 equals() 检测。
相当于调用 Object.equals() 方法,并且处理了,对象为null情况,无需手动判空处理。
=== 【引用相等】,两个引用是否指向同一对象
相当于java的 ==
再来个面试考试常考的题
这个题也是面试常考的题,我们一起举一反三一下哈。
欢迎,老铁们,在评论区说出你的答案:
java代码:JavaEqualMain.java
public static void stringEqual(){
String strBuilder1 = new StringBuilder("IT互联网大叔").toString();
String strBuilder2 = new StringBuilder("IT互联网大叔").toString();
System.out.println("strBuilder1 == strBuilder2 :" + (strBuilder1 == strBuilder2));
String str1 = "IT互联网大叔";
String str2 = "IT互联网大叔";
System.out.println("str1 == str2 :" + (str1 == str2));
}
大叔的灵魂拷问:日志会输出什么?
kotlin代码:KtEqualMain.kt
fun stringEqual() {
val strBuilder1 = StringBuilder("IT互联网大叔").toString()
val strBuilder2 = StringBuilder("IT互联网大叔").toString()
println("strBuilder1 == strBuilder2 :" + (strBuilder1 == strBuilder2))
val str1 = "IT互联网大叔"
val str2 = "IT互联网大叔"
println("str1 == str2 :" + (str1 == str2))
}
大叔的灵魂拷问:日志会输出什么?
2.2 智能类型转换(Smart Casts)
我们来看一段Java代码:
public static void close(Object obj) throws IOException {
//已经判断他是Closeable,依然需要强转
if(obj instanceof Closeable){
((Closeable) obj).close();
}
}
我们再来看看kotlin
@Throws(IOException::class)
fun close(obj: Any) {
if (obj is Closeable) {
obj.close()//obj已经是一个Closeable类型了
}
}
我们继续
再继续
上面这种写法,java代码段是不是看的有点迷茫,看不懂,你忙就对了,大叔也迷茫。
java对泛型的强转,已经严重影响到,代码的可读性了。
kotlin的类型转换,对代码的可读性提升了太多。
2.3 if、when表达式
val max = if (a > b){
print("a is bigger")
a
} else if(a == b){
print(" a == b")
a
}else {
print("b is bigger")
b
}
//....
上面代码也可以用when表达式,实现:
val max = when {
a > b -> {
print("a is bigger")
a
}
a == b -> {
print(" a == b")
a
}
else -> {
print("b is bigger")
b
}
}
比java的 三元运算符(条件 ? 然后 : 否则),if表达式可读性要更高,对初学者也更友好。
而且比 三元运算符 更灵活。
另外,java14的switch也变成表达式了。
对了kotlin的try catch,也可以当表达式用。
2.4 解构声明(Destructuring Declarations)
什么是解构申明?解构申明能干什么?
2.4.1 通过解构申明,遍历Map
我们先来看看,java是怎么遍历Map的。
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("one", 1);
map.put("two", 2);
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + "->" + entry.getValue());
}
上面的代码,所有java程序员都非常熟悉。
不是大叔吹牛,从大学,到现在,大叔写过的for循环遍历,比你家娃,吃过的盐还多。
可以说这种对Map遍历的方式,已经彻底扎根在我的思维里。我觉得全天下所有程序都应该是这么遍历的。
直到有一天,大叔遇见了kotlin的解构申明:
val map = mapOf("one" to 1, "tow" to 2)
for ((key, value) in map) {//通过解构申明来遍历Map
println("$key->$value")
}
一声直呼,我靠,还能这样遍历Map。
这才是人的思维方式啊,兄弟们啊啊啊。。。。
这种语法是如此的亲切简洁。基本上都不用学习,看一眼就懂这是什么意思。
想想刚学编程的那会,学c语言,一个for循环遍历就能学一周。。。。
接着我们找到Maps.kt的源码:
kotlin正是通过 component1() 和 component2() 两个函数实现了Map.Entry类的解构申明。
接着我们来看一个代码段:
fun main() {
val people = People("IT互联网大叔", 18)
var (myName, myAge) = people//注意这行代码,解构申明
println("my name is $myName, i am $myAge")
}
class People(val name: String, val age: Int) {
operator fun component1() = name //注意
operator fun component2() = age //注意
}
因为People重载了函数component1()和component2(),所以可以将其解构成name和age。
我们一起看看kotin是怎么做到的吧。
我们先来看看他的字节码吧。
什么,字节码?大叔别逗我了。这怎么看?
看起来麻烦?不容易理解。
嗯,大叔非常同意。
所以大叔准备了另一份代码段,把上面的字节码反编译成java代码。
这种解构申明的语法,本质是个语法糖,在编译器做了一些优化。
只是编译器帮我们,调用了people.component1()并帮我们赋值了。
String myName = people.component1();
int myAge = people.component2();
3.4.2 通过解构申明,实现函数返回多个值
众所周知,java的函数只能有一个返回值。不能同时返回多个值。
但是有了解构申明之后,我们可以假装,函数能返回多个值,如下代码:
fun main() {
val (myName, myAge) = getFirstPeople()//返回值为People,我们可以直接把返回值结构
println("my name is $myName, i am $myAge")
}
fun getFirstPeople() = People("IT互联网大叔", 18)
3.5、无符号整型
我们知道java里面是没有无符号整型的,但是kotlin有,哈哈哈。
kotlin.UByte: 无符号 8位,范围是 0 到 255
kotlin.UShort: 无符号 16位,范围是 0 到 65535
kotlin.UInt: 无符号 32位,范围是 0 到 2^32 - 1
kotlin.ULong: 无符号 64位,范围是 0 到 2^64 - 1
大叔的自我拷问 :这能解决啥痛点,劳资java写了这么多年了,没有无符号整形,不是照样写的好好的么。
大叔的自我拷问 :这能解决啥痛点,劳资java写了这么多年了,没有无符号整形,不是照样写的好好的么。
大叔的自我拷问 :这能解决啥痛点,劳资java写了这么多年了,没有无符号整形,不是照样写的好好的么。
在痛点3.4 解构申明 里面我们写了一个类People:
class People(val name: String, val age: Int) {}
我们的age是int类型。int是可以是负数的。
但是 “年龄” 这种东西有负数吗?
但是 “年龄” 这种东西有负数吗?
但是 “年龄” 这种东西有负数吗?
我们把age传进来的时候,是不是要做个数据检查。
假如有同事传了个负数,导致程序出bug,就只能怪自己不严谨。
类似,打破你的认知,java,除以0一定会崩溃吗? blog里描述的bug。
于是我们改造了下代码,我们先假如kotlin没有无符号整型:
class People {
private val name: String
private val age: Int
constructor(name: String, age: Int) {
this.name = name
if (age >= 0) {
this.age = age
} else {
this.age = 0
println("illegal age $age")
}
}
}
UInt类型,自从有了你,世界变得好美丽 ------ ˙这句要唱出来
class People(val name: String, val age:UByte) {}
不仅更优雅而且更健壮。
三、结尾
好了,聊完了技术。大叔再碎碎念一些事儿吧。
前两天,有位很资深的老鸟,年纪比大叔还要大,跟大叔聊天。
资深的老鸟:“我做的这个需求,要延期了“
大叔:“怎么了?”
资深的老鸟:“这个模块,之前的实现大量使用了LiveData,我还没用过LiveData,而且,他用的好复杂,代码好难看懂啊……”
大叔:“额,那你打算怎么弄?”
资深的老鸟:“我打算,重写一下这个模块,xxx同事,这个LiveData太复杂了,一个很简单的逻辑,写的好复杂啊……我改不动……”
资深的老鸟:“哎,这种团队还没普及的技术,最好不要随便乱用吧,而且他用的也很复杂,一个很简单的功能,绕来绕去的……搞的现在项目紧张情况下,让我难受……”
大叔:“额,好吧”
大叔心里其实挺为这位同事捏把汗的,我觉得,他选择了一个很冒险的方式。在这种紧急的情况下,重写一个模块,往往风险只会更高。
小伙伴们,你们怎么看呢?如果你是老鸟,你会怎么选择?
最后是 Kotlin 的学习资料免费获取:
需要的小伙伴,麻烦各位转发一下(可以帮助更多的人看到哦!),记得一定要关注+转发,然后私信@芜湖Android“Kotlin”,即可回复免费下载的方式!!
- 上一篇:Kotlin基本语法
- 下一篇:可以用Kotin写项目了--Kotlin基础入门
相关推荐
- Python自动化脚本应用与示例(python办公自动化脚本)
-
Python是编写自动化脚本的绝佳选择,因其语法简洁、库丰富且跨平台兼容性强。以下是Python自动化脚本的常见应用场景及示例,帮助你快速上手:一、常见自动化场景文件与目录操作...
- Python文件操作常用库高级应用教程
-
本文是在前面《Python文件操作常用库使用教程》的基础上,进一步学习Python文件操作库的高级应用。一、高级文件系统监控1.1watchdog库-实时文件系统监控安装与基本使用:...
- Python办公自动化系列篇之六:文件系统与操作系统任务
-
作为高效办公自动化领域的主流编程语言,Python凭借其优雅的语法结构、完善的技术生态及成熟的第三方工具库集合,已成为企业数字化转型过程中提升运营效率的理想选择。该语言在结构化数据处理、自动化文档生成...
- 14《Python 办公自动化教程》os 模块操作文件与文件夹
-
在日常工作中,我们经常会和文件、文件夹打交道,比如将服务器上指定目录下文件进行归档,或将爬虫爬取的数据根据时间创建对应的文件夹/文件,如果这些还依靠手动来进行操作,无疑是费时费力的,这时候Pyt...
- python中os模块详解(python os.path模块)
-
os模块是Python标准库中的一个模块,它提供了与操作系统交互的方法。使用os模块可以方便地执行许多常见的系统任务,如文件和目录操作、进程管理、环境变量管理等。下面是os模块中一些常用的函数和方法:...
- 21-Python-文件操作(python文件的操作步骤)
-
在Python中,文件操作是非常重要的一部分,它允许我们读取、写入和修改文件。下面将详细讲解Python文件操作的各个方面,并给出相应的示例。1-打开文件...
- 轻松玩转Python文件操作:移动、删除
-
哈喽,大家好,我是木头左!Python文件操作基础在处理计算机文件时,经常需要执行如移动和删除等基本操作。Python提供了一些内置的库来帮助完成这些任务,其中最常用的就是os模块和shutil模块。...
- Python 初学者练习:删除文件和文件夹
-
在本教程中,你将学习如何在Python中删除文件和文件夹。使用os.remove()函数删除文件...
- 引人遐想,用 Python 获取你想要的“某个人”摄像头照片
-
仅用来学习,希望给你们有提供到学习上的作用。1.安装库需要安装python3.5以上版本,在官网下载即可。然后安装库opencv-python,安装方式为打开终端输入命令行。...
- Python如何使用临时文件和目录(python目录下文件)
-
在某些项目中,有时候会有大量的临时数据,比如各种日志,这时候我们要做数据分析,并把最后的结果储存起来,这些大量的临时数据如果常驻内存,将消耗大量内存资源,我们可以使用临时文件,存储这些临时数据。使用标...
- Linux 下海量文件删除方法效率对比,最慢的竟然是 rm
-
Linux下海量文件删除方法效率对比,本次参赛选手一共6位,分别是:rm、find、findwithdelete、rsync、Python、Perl.首先建立50万个文件$testfor...
- Python 开发工程师必会的 5 个系统命令操作库
-
当我们需要编写自动化脚本、部署工具、监控程序时,熟练操作系统命令几乎是必备技能。今天就来聊聊我在实际项目中高频使用的5个系统命令操作库,这些可都是能让你效率翻倍的"瑞士军刀"。一...
- Python常用文件操作库使用详解(python文件操作选项)
-
Python生态系统提供了丰富的文件操作库,可以处理各种复杂的文件操作需求。本教程将介绍Python中最常用的文件操作库及其实际应用。一、标准库核心模块1.1os模块-操作系统接口主要功能...
- 11. 文件与IO操作(文件io和网络io)
-
本章深入探讨Go语言文件处理与IO操作的核心技术,结合高性能实践与安全规范,提供企业级解决方案。11.1文件读写11.1.1基础操作...
- Python os模块的20个应用实例(python中 import os模块用法)
-
在Python中,...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
因果推断Matching方式实现代码 因果推断模型
-
git pull命令使用实例 git pull--rebase
-
面试官:git pull是哪两个指令的组合?
-
git 执行pull错误如何撤销 git pull fail
-
git pull 和git fetch 命令分别有什么作用?二者有什么区别?
-
git fetch 和git pull 的异同 git中fetch和pull的区别
-
git pull 之后本地代码被覆盖 解决方案
-
还可以这样玩?Git基本原理及各种骚操作,涨知识了
-
git命令之pull git.pull
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)