沉思录| Kotlin的「丑与美」,以及「最佳实践」

31eaa8f6dbb16446ce8c9f409ee6c539.png

/   今日科技快讯   /

近日,抖音本地生活发布《2022年生活服务软件服务费政策通告》,自6月1日起抖音生活服务将调整软件服务费政策,这意味着抖音将告别“0服务费”的时代。但即便如此,不少商家表示,仍然不会放弃抖音这块流量“肥肉”,还会加大对抖音的投入力度。

/   作者简介   /

明天就是周六啦,大家好好休息,我们下周再见!

本篇文章来自朱涛的投稿,文章分享了对于Kotlin的深度思考,相信会对大家有所帮助!同时也感谢作者贡献的精彩文章。

原文地址:

https://mp.weixin.qq.com/s/24f1ojIUpba0Bvflx2XVsw

/   引言   /

大家好,我是朱涛。

博客两年没怎么更新了,过去的两年里发生了很多事情:

  • 第一,我成为了一名父亲;

  • 第二,郭霖大佬鼓励了我,让我去申请了GDE,很荣幸,我通过了Google的筛选和面试,成为了Kotlin、Android的GDE。(希望疫情赶紧过去,我还欠大佬一顿饭。)

  • 第三,我从上家公司离职,花了半年写了一个技术专栏《Kotlin编程第一课》,体验了一次自由职业者的感觉。

在撰写技术专栏的过程中,我成长了很多,既有技术方面的成长,也有技术之外的成长。

在过去的半年里,我做的最多的事情就是:深度思考。我要想尽一切办法,将自己脑子里的知识掏出来,然后,以最简单、最直观的方式呈现给我的读者。比如说,为了解释清楚Kotlin协程的“挂起和恢复”,我掉了很多头发才找到下面这个灵感:

说实话,我写专栏,根本不是为了钱,单纯就是因为喜欢做这样的事情。这半年里,我写作的态度比从前的工作还拼命;半年里挣的钱,还不如我一个月工资多。但我乐在其中啊,哈哈!

62de536ea3f0185d6224cdc9c23d493d.png

对我来说,读者对课程的赞扬,就是我快乐的源泉。其实,很多互联网的大佬写博客、写书,也是同理。

关于「沉思录」

其实,在这半年里,我还积累了许多创作灵感,这些灵感,大都非常的琐碎,并不足以成为专栏系统课程的一部分。但这些灵感如果不写出来,就太可惜了。所以,我决定将其取名为:「沉思录」,以博客的形式发出来。

「沉思录」,大约分为三个板块:

  • Kotlin沉思录,记录我在Kotlin领域的思考,包括Kotlin JVM,协程,也包括KMM;

  • Android沉思录,记录我在Android、Jetpack领域的思考,两年前我写的《Kotlin Jetpack实战》还是太浅了;

  • Compose沉思录,自然就是Jetpack Compose领域的思考,它的编程理念,实现原理都非常有趣。

今天,我们主要看看Kotlin沉思录。


/   Kotlin 沉思录   /

初学Kotlin的时候,我更多的只是看到了Kotlin的「美」,但经过5年多的沉淀,我也渐渐发现了Kotlin「丑」的一面。

世界上不存在完美的语言,Kotlin也不例外。

其实,一直以来,总有读者问我这样问题:

“Kotlin的最佳实践是什么?”

对于这样的问题,我的回答总是非常的谨慎,说实话,我不敢仅凭我个人的经验就妄下定论。然而,最近,问我这个问题的人越来越多了,有专栏的读者,也有公司的同事。

接下来,我们就来聊聊具体的思路吧,关于Kotlin的「丑」与「美」。

「丑」与「美」

人们常说,穿衣服,要尽量遮住自己「丑」的部位,尽量凸显自己「美」的部分。我的思路也是类似的,简单来说,就是:扬长避短

  • Kotlin的「弱点」

考虑到我GDE的身份,不能大肆宣扬Kotlin的缺点。因此,关于Kotlin「丑」的部分,我会以「弱点」、「坑」为标题。毕竟「丑」与「美」都是非常主观的一种判断,「弱点」则是一种更客观的描述。(没错,我就是比较怂。)

以下是部分主题:

  • 02 | 枚举类的弱点在哪?

  • 03 | Data Class的弱点在哪?

  • 06 | Lambda的弱点在哪?

  • 09 | 扩展函数的弱点在哪?

  • 15 | Channel的弱点在哪?

  • 16 | Flow的弱点在哪?

  • Kotlin之美

聊完Kotlin的「丑」之后,我们就知道Kotlin的「弱点」还有「坑」在哪了,在平时使用的时候,我们就可以很好的避开它的弱点了。

接下来,我们就可以来看看Kotlin的「美」了,欲扬先抑嘛。

以下是部分主题:

  • 17 | 如何理解Kotlin语法之美?

  • 18 | 如何理解sealed之美?

  • 21 | 如何理解Delegation之美?

  • 23 | 如何理解协程之美?

  • 26 | 如何理解Flow之美?

  • 30 | 如何理解inline之美?

Kotlin的「最佳实践」到底是什么?看完上面的这些系列以后,我相信每个读者都会有一个自己的答案吧!

Kotlin其实是一个非常宽泛的话题,除了语法特性层面的「丑」与「美」,其实还有许多能聊的东西,比如:编程范式、DSL设计、数据结构与算法、设计模式,KMM、Compose Multiplatform。这些内容,我都会尝试在这个系列的博客里去做一些涉猎。

关于深度

沉思录这个系列不是面向0基础读者的,这里主要会记录我平时的一些灵感和思考,它更像是不成体系的Android、Kotlin随笔。如果你是有一定经验的开发者,应该能让你有所启发。(不敢保证哈。)

如果你对Kotlin没有一个全面的认识,那我建议你先去看看Kotlin官方文档。如果你觉得官方文档枯燥乏味,也可以去看看我公众号里的历史文章,我自认为讲的还不错。

b2de1b5082309ffb0e370d2be558a3d4.png

OK,闲聊结束,我们进入正题。

/   「又爱又恨」的特性   /

我们都知道,Kotlin会为成员属性自动生成getter、setter。不论是使用var、还是使用val,Kotlin编译器都会自动帮我们处理getter、setter的问题。

// 代码段1

class GetterSetterDeepDive {
    // var
    var name: String = "朱涛的自习室"
    // val
    val desc: String = "Kotlin, Android and more."
}

如果将上面的Kotlin代码反编译成Java的话,它大致会长这样:

// 代码段2

public final class GetterSetterDeepDive {

   private String name = "朱涛的自习室";
   private final String desc = "Kotlin, Android and more.";

   public final String getName() {
      return this.name;
   }

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

   public final String getDesc() {
      return this.desc;
   }
}

在我初学Kotlin的时候,我曾对着这个案例感叹:Kotlin 666!一行顶十行啊!用Kotlin开发,果然能大大提升效率啊!

说实话,现在回过头来看,当时的我就跟个“脑残粉”一样,大家不要学我。

好了,言归正传,有一说一,Kotlin自动生成getter、setter,它这样的行为,对比Java确实是一大进步,因为它可以避免外部的类直接访问Kotlin类当中的字段(Field)。毕竟,我们都知道,类似下面这样的Java代码是非常不合理的。

// 代码段3

public class FieldJavaBean {
    public String name = "朱涛的自习室";
    public final String desc = "Kotlin, Android and more.";
}

上面的代码,既不符合开放封闭的原则,也难以维护。对比之下,Kotlin生成的代码段2的代码,则要顺眼很多。然而,Kotlin这样的策略其实也有它丑陋的一面。让我们来看看下面的例子。

Getter、Setter的第一个弱点

Kotlin的Getter、Setter主要有两个弱点,我们先来看它的第一个弱点,请看下面的代码。

// 代码段4

class GetterSetterDeepDive {
    var name: String = "朱涛的自习室"
    val desc: String = "Kotlin, Android and more."

    fun printName() {
        println("name = $name,desc = $desc")
    }
}

请问,这段代码的问题在哪?抛开当前文章的语境,如果你是在面试当中遇到这样一个问题,你会给出怎样的答案?

你可以停下来思考一下,心里有了答案以后再继续往后看。

Kotlin最大的问题就在于,大部分的开发者很难意识到Kotlin编译器背后自动生成的那些getter、setter方法,从而导致这个特性被滥用。

让我们将上面的代码反编译来看看。

// 代码段5

public final class GetterSetterDeepDive {

   private String name = "朱涛的自习室";
   private final String desc = "Kotlin, Android and more.";
   // 1
   public final String getName() {
      return this.name;
   }
   // 2
   public final void setName(@NotNull String var1) {
      this.name = var1;
   }
   // 3
   public final String getDesc() {
      return this.desc;
   }

   public final void printName() {
      // 并不会用到getter、setter
      String var1 = "name = " + this.name + ",desc = " + this.desc;
      System.out.println(var1);
   }
}

可以看到,注释1、2、3对应的这三个自动生成的getter、setter方法,它们根本就没被用到!这样的问题,如果是在一个非常小的规模,其实是无伤大雅的,但对于一个大的工程来说,当这样的问题积少成多,就会极大增加方法数,还有应用的包体积。这一点对Android应用尤为重要。

那么,以上的问题该怎么解决呢?答案其实也很简单:

// 代码段6

class GetterSetterDeepDive {
// 变化在这里
//     ↓
    private var name: String = "朱涛的自习室"
    private val desc: String = "Kotlin, Android and more."

    fun printName() {
        println("name = $name,desc = $desc")
    }
}

我们将其反编译成Java看看:

// 代码段7

public final class GetterSetterDeepDive {
   private String name = "朱涛的自习室";
   private final String desc = "Kotlin, Android and more.";

   public final void printName() {
      String var1 = "name = " + this.name + ",desc = " + this.desc;
      System.out.println(var1);
   }
}

这样的 Java 代码看起来是不是干净了很多?这就对了!

反思

Kotlin编译器自动生成Getter、Setter的操作,它对比Java确实是存在优势的,因为它更符合「开放封闭」的原则。我们Kotlin开发者随手写出的var、val,它背后都会转换成Java当中的「最佳实践」,真的很方便。这个设计最精彩的地方在于:「简洁」,简单的var背后代表了:Field + Getter + Setter,这样的信息密度是Java所不能比拟的。不得不佩服Kotlin设计者的精妙构思。

然而,几乎所有的技术都是一种trade-off,Kotlin这样「方便」、「简洁」的设计,让它丢失了许多底层的信息。许多开发者只看到了var的方便,却很容易忽略它底层自动生成的Field + Getter + Setter。Kotlin官方其实也在想办法解决类似这样的问题,但这远远不够。

f0ec9ef925d045deefa70f48cb5370e8.png

当我们写出有问题的代码时,IDE其实是会有警告的。可是,它只告诉了我们:desc可以变成private,并没有告诉我们具体的后果。当我们看到这样的提示时,我们脑子里很难将“private”与“Getter、Setter”建立对等的关系。

  • 对于var属性来说,加上private修饰,就意味着方法数减2;

  • 对于val属性来说,加上private修饰,就意味着方法数减1;

其实,许多事物发展到一定程度,最后都会开始拼细节。考试是如此、商业是如此、编程也是如此。

好,考虑到篇幅限制,我们之后再聊Getter、Setter的第二个弱点吧!我们下期再见!

推荐阅读:

我的新书,《第一行代码 第3版》已出版!

我为Android版Microsoft Edge所带来的变化

Android蓝牙开发攻略,就是这么easy!

欢迎关注我的公众号

学习技术或投稿

09d1d632e3b99f7f7db5a09a8711df0c.png

4036becf778c5ffb6bcbc0876457ad1f.png

长按上图,识别图中二维码即可关注

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值