Kotlin:每桶蜂蜜中有两汤匙焦油

Kotlin的出现对开发人员来说是一个重要的奖励。 与Java无缝集成的高级语言极大地扩展了程序员的能力。 但是,无论用哪种语言,我们都会不断遇到一些麻烦,相反,这些麻烦会产生限制,而科特林当然也不例外。 今天我们将讨论它们。



Kotlin对社区充满热情,因为新的编程语言极大地简化了代码编写,取代了Java。 这一点在Android上尤其明显,在Android上出现了Java的新版本。 许多设备的更新延迟很长,甚至更多-它们根本不接收固件更新。 在最佳情况下,对设备的支持将在其发布后约2年后终止,这将保证最多进行两次系统更新。 但是,人们仍在继续使用设备,这意味着开发人员必须依赖(到目前为止)最新的Android 8和Android 5,甚至更早的版本,那里肯定不仅有最新的Java,而且甚至包括当前的Java实现。 作为参考,现在Android 7和8(系统库支持Java 8的版本)的总份额为42.9%,其余为Java 7。

有人可能会说Java已过时。 但是,也有一种观点认为Java是一种“按原样”良好的语言,不应被触及。 就像数学中的GCD(最大公因数)一样。 它包含一个绅士的功能集,对于那些今天需要附加功能的人,可以使用已经在JVM之上运行的特殊语言。 这些语言中有很多已经产生了:Scala,Clojure,JRuby,Jython,Groovy和其他不太知名的语言。 但是,Kotlin具有许多优势。 这种语言为程序员提供了更大的自由度:它允许您同时使用Java和新代码,同时使用Java中现成的片段。

但是,尽管在开发过程中我们毫无争议地拥有了新语言的所有优点,但仍发现了一些缺点。 今天,很高兴听到同事们对他们是否以与我们相同的方式干扰工作的意见。

无法隐藏表演?


像往常一样,包是按名称空间组织类的一种相当普遍的方式。 但是它们的优点不仅在于此,在Java中它们还充当了限制类及其成员的可见性的一种手段。

让我提醒您,在Java中,有4个不同的类别可让您区分可见性。 它们只有两个用于类-在包中(包私有)或完全打开(公共)可见。 但是方法或字段已经可以设为私有的(在类外部无法访问),仅对包可见(私有的包),可以将方法或字段设置为使得继承人无论在其包中还是在包外部(受保护)都可以看到该方法,并且您还可以使其对所有人(公共)可见。

Java 9引入了将代码分解为模块的功能,现在可以使部分代码在模块内部的任何位置可见,而从外部看不到。 事实证明,这对于构建明智的API很有用。

简而言之,Java中的选项已绰绰有余。 但是由于某种原因,他们在Kotlin的工作仅限于引入公共和私人可见性,以及继承人的可见性。 然而,此外,他们引入了按模块的区分,但是变得不可能通过包来区分对方法和类的访问。 模块不再是语言本身的构建,因此人们经常用这个术语理解完全不同的事物。 Kotlin正式将该模块定义为“一组一起编译的Kotlin文件 ”。

问题在于,该模块通常会导致额外的资源成本。 同时,如果您创建一个单独的程序包并将带有仅在该程序包中可见的功能的类放入其中,则不会有问题,因为所有程序包都将一起编译,并且不需要其他资源。

例如,如果您像往常一样组装Android应用程序,则在Gradle中收集项目,这尤其明显。 模块通常做得比较大,因此它们是一个完整的功能单元。 在一个模块中,无法使一种方法对一个人可见,而对其他类不可见。 而且,如果我们想使方法的外观更精细,则会出现问题。

在这里,我立即想起这些软件包,因为在Kotlin中,这种本质并未消失,但是可惜的是,它并不影响可见性。 当然,您总是可以制作更多的模块,但是,鉴于Gradle的功能,这简直是不合理的:构建速度会降低。 是的,可以将类放在一个文件中,但是对于大型项目,该文件将变得非常“繁重”。 因此,我想获得其他隐藏方法的方法,例如,以Java为模型。

不要处理...即使有必要


第二个是有争议的(因为有些人认为使用它们是坏消息),但是,缺点是缺少检查异常。 这些工具使用Java,但是Kotlin决定不实施它们。 官方文档中有一个有关Appendable接口的示例。 您可以将字符串附加到Appendable,并且由于字符串可以连接到与I / O相关的对象,例如,当写入文件或网络时,调用接口方法时可能会出现IOException。 这样的情况使得检查异常的使用不方便。

该语言的创建者对它们的论点解释如下:如果我们使用StringBuilder,通过Appendable访问它,那么即使您确定它基本上不会发生,我们也需要处理IOException:

Appendable log = new StringBuilder(); try {    log.append(message); } catch (IOException e) {    // Must be safe } 

摆脱困境的方法:例外是“抓到”,但他们对此无能为力,这当然不好。 但是,出现了一个问题:如果我们显然通过Appendable接口使用StringBuilder,为什么不直接与StringBuilder交互呢? 有一个重要的区别:使用Appendable时,如果我们不知道它下面是哪个特定的实现,则输入/输出的例外情况确实有可能出现,但是StringBuilder不会准确给出它,并且在其中声明了相应的方法,尽管它们实现接口。 所以这个例子很紧密...

特别有趣的是,文档作者参考《有效Java》中的第77章,其中指出不能捕获和忽略异常。 但是只有在下一章中写到,如果明智地使用,可以并且应该使用检查异常。 如果有选择地引用,则任何观点均可辩解。

结果,Kotlin开发人员做到了这一点,从本质上讲,所有方法都可能引发某种异常。 但是,使用新语言处理错误的工具在哪里呢? 现在如何了解异常可能出现的位置? 遗憾的是,在语言级别上,我们在这些问题上没有找到帮助,即使使用源代码(在不考虑各种技巧的情况下,源代码始终无法使用),也很难理解在每种特定情况下该怎么做。

如果您问开发人员一个问题,他们只是耸耸肩,说其他语言中没有经过检查的异常,什么没有 ,他们还创建了大型而可靠的程序。 但是,它们也成功地用坦白不成功的语言编写,这不是争论。 在StackOverflow上,他们说类似的问题:“ 您需要阅读文档 ” –一个很好的答案,在这种情况下非常方便。 只有文档可能不存在,文档可能不完整或已过时-编译器不会对其进行检查。 最后,您可能找不到答案。

是的,确实,检查异常会导致API的不便。 当检查异常显然是多余的,以便使编译器“满意”时,您必须编写try ... catch并实际上只是创建垃圾代码,因为在处理这些异常时什么也没做。 而且在功能代码中使用它们不方便的事实也是如此。 但是检查异常只是在必要时可以很好地使用的工具。

目前还不清楚为什么语言会抓住这个机会,如果Kotlin的理念是信任更多的工具给程序员(至少在我们看来,这是对我们而言),并且如果代码的作者能够正确地描述哪里会有任何例外,为什么不相信他呢? 采取从Java中删除的相同的重载运算符,因为它们可能导致带有非显而易见动作的API出现-这是为了保护程序员自己。 相比之下,Kotlin具有重载运算符和执行许多其他操作的能力-那么为什么没有可检查的异常? 创造者能够做到这一点,是因为它根本不像Java中那样吗?

我们正在等待改变...


在Android 11上,我们可以指望的最大数量是Java 7或Java 8(但有一些限制和警告),而使用Java 11的时候,使用Kotlin,在Android上编程要容易得多,减少了文本行数。

只能希望开发人员将这些非常有用的语言补充由于显而易见的原因而今天不可用的那些功能。 也许在将来的版本中,将会有新的工具来分析IDE中的异常,以及新的隐私类别。 但是,很显然,在遥远的将来,这是最好的情况,因为语言开发人员甚至没有提出任何承诺。

Source: https://habr.com/ru/post/zh-CN418377/


All Articles