- 原文作者 : Kirill Rozov
- 原文链接 : Kotlin: cleaning Java bytecode before release
- 译者 : 邓士伟
- 校对者: 邓士伟
- 状态 : 完成
Kotlin
中删除了大量需要我们手写或者由 IDE
、第三方框架生成的模板代码。最好的例子就是 Kotlin
是空安全的,由于这个特性,我们不需要写空判断语句 if(value != null)
,这是 Kotlin/JVM
中额外添加在 Java
字节码中实现的。所以说好的功能必然需要付出一定的代价来换取。
下面让我们一起来看看 Kotlin
编译后的字节码,并学习如何降低这种代价。
函数参数
示例代码:
// Sample.kt
fun sample(arg1: String) {
}
复制代码
编译后的 Java
字节码:
public final class SampleKt {
public static final void sample(@NotNull String arg1) {
Intrinsics.checkParameterIsNotNull(arg1, “arg1”);
}
}
复制代码
在上面的字节码中,可以看到调用了 kotlin.jvm.internal.Intrinsics 类中的 checkParameterIsNotNull
方法进行空检查。但是实际上我们是否都需要这些代码呢?让我们看下另一个例子。
平台类型
Kotlin
中有特定的 types
—[platform type](http://platform type/)。你不能声明这些类型,只能通过其它代码返回。
// Utils.java
public class Utils {
public static String getValue() {
throw new RuntimeException();
}
}
// Sample.kt
fun sample() {
val value: String = Utils.getValue()
}
复制代码
编译后的字节码:
public final class SampleKt {
public static final void sample() {
Intrinsics.checkExpressionValueIsNotNull(
Utils.getValue(), "Utils.getValue()"
);
}
}
复制代码
可以看到字节码非常精简,如果我们能将开发期间写的调试代码在 Release
版本中进行移除,这个特性肯定很实用。
移除代码
ProGuard/R8
你可以在你的 ProGuard 文件中添加下面的混淆配置来移除工具类的字节码。
// proguard.pro
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
public static void checkExpressionValueIsNotNull(...);
public static void checkNotNullExpressionValue(...);
public static void checkReturnedValueIsNotNull(...);
public static void checkFieldIsNotNull(...);
public static void checkParameterIsNotNull(...);
}
复制代码
-assumenosideeffects
需要你自己保证你所选择的类的方法没有边界效应(简单来说就是删掉也不会影响程序运行),然后 proguard
会帮你删掉这些方法的调用。
Kotlin 编译参数
通过 kotlin
编译参数配置可以删除一些 assert
。
-Xno-call-assertions
:不对platform types
的参数生成空检查-Xno-receiver-assertions
:不对platform types
的接收参数生成空检查-Xno-param-assertions
:不对Java
方法参数生成非空检查
// build.gradle
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile)
.all {
kotlinOptions {
freeCompilerArgs += [
'-Xno-call-assertions',
'-Xno-receiver-assertions',
'-Xno-param-assertions'
]
}
}
复制代码
你可以在这里查看更多关于 Kotlin/JVM
的编译参数信息。
总结
Kotlin
是一门很棒的开发语言,尽管它的一些特性支持需要一些代价。但是那些说 Java
没有添加太多额外字节码的操作,而 Kotlin
添加很多的说法是愚蠢的。例如 Java
中的特性(泛型和 switch
支持 String
)都是通过生成其它的字节码实现的。Kotlin
生成更多的附加字节码,因此您在源代码中写的更少。
同时,你可以通过 ProGuard
/R8
降低这些影响。我建议在发布版本时使用这两种方法。为什么只针对发布版本?因为高质量的 Android
应用程序必须速度快,每秒 60 帧,而且体积小。但仅限于终端用户,不要从调试版本中删除任何内容,以获得尽可能多的有关应用程序错误行为的信息,从而简化应用程序的调试。
作者:邓士伟
链接:https://juejin.im/post/5e1c6163f265da3e4736b37f
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。