Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

探索 Kotlin 中的隐性成本(第一部分) #1843

Merged
merged 4 commits into from
Jul 13, 2017

Conversation

Feximin
Copy link
Contributor

@Feximin Feximin commented Jul 4, 2017

Exploring Kotlin’s hidden costs — Part 1
初翻完成,请校对大佬指正T__

Issue 地址:#1812

@CACppuccino
Copy link
Contributor

@sqrthree 校对认领

@linhe0x0
Copy link
Member

linhe0x0 commented Jul 9, 2017

@CACppuccino 好的呢 🍺

Copy link
Contributor

@CACppuccino CACppuccino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

无大问题 注意斜体问题 @sqrthree @Feximin

@@ -3,58 +3,58 @@
> * 原文作者:[Christophe B.](https://medium.com/@BladeCoder)
> * 译文出自:[掘金翻译计划](https://github.com/xitu/gold-miner)
> * 译文地址:[github.com/xitu/gold-miner/blob/master/TODO/exploring-kotlins-hidden-costs-part-1.md](https://github.com/xitu/gold-miner/blob/master/TODO/exploring-kotlins-hidden-costs-part-1.md)
> * 译者:
> * 译者:[Feximin](https://github.com/Feximin)
> * 校对者:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


Kotlin supports assigning functions to variables and passing them as arguments to other functions. Functions accepting other functions as arguments are called *higher-order functions.* A Kotlin function can be referenced by its name prefixed with `::` or declared directly inside a code block as an anonymous function or using the [lambda expression syntax](https://kotlinlang.org/docs/reference/lambdas.html#lambda-expression-syntax) which is the most compact way to describe a function.
Kotlin 支持将函数赋值给变量并将他们做为参数传给其他函数。接收其他函数做为参数的函数被称为*高阶函数*。Kotlin 函数可以通过在他的名字前面加 `::` 前缀来引用,或者在代码中中直接声明为一个匿名函数,或者使用最简洁的 [lambda 表达式语法](https://kotlinlang.org/docs/reference/lambdas.html#lambda-expression-syntax) 来描述一个函数。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

斜体改为粗体


- For *capturing expressions*, a new `Function` instance will be created every time a lambda is passed as argument then garbage-collected after execution;
- For *non-capturing expressions* (pure functions), a singleton `Function` instance will be created and reused during the next calls.
- 对*捕获表达式*来说,每当一个 lambda 做为参数传递的时候都会生成一个新的 `Function` 实例,执行完后就会进行垃圾回收。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

斜体转粗体

@@ -125,22 +125,22 @@ public interface Function1<in P1, out R> : Function<R> {
}
```

This means that calling a function passed as argument in a higher-order function will actually involve **systematic boxing and unboxing** when the function involves primitive types (like `Int` or `Long`) for input values or the return value. This may have a non-negligible impact on performance, especially on Android.
这意味着调用一个做为参数传递给高阶函数的方法时,如果输入值或者返回值涉及到基本类型(如 `Int` `Long`),实际上调用了**系统的装包和拆包**。这在性能上可能有着不容忽视的影响,特别是在 Android 上。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[做为参数] => [作为参数]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

装包还是装箱-。-

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

装箱哈,我改过来


First, it is possible to completely avoid any method call by declaring the value as a [compile-time constant](https://kotlinlang.org/docs/reference/properties.html#compile-time-constants) using the `**const**` keyword. This will effectively inline the value directly in the calling code, *but you can only use this for primitive types and Strings*.
首先,通过 **`const`** 关键字声明值为[编译时常量](https://kotlinlang.org/docs/reference/properties.html#compile-time-constants)来完全避免任何的方法调用是有可能的。这将有效地在调用代码中直接内联这个值,*但是只有基本类型和字符串才能如此使用*。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[编译时常量] =>[编译时间常量]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里我同意译者的翻译


First, it is possible to completely avoid any method call by declaring the value as a [compile-time constant](https://kotlinlang.org/docs/reference/properties.html#compile-time-constants) using the `**const**` keyword. This will effectively inline the value directly in the calling code, *but you can only use this for primitive types and Strings*.
首先,通过 **`const`** 关键字声明值为[编译时常量](https://kotlinlang.org/docs/reference/properties.html#compile-time-constants)来完全避免任何的方法调用是有可能的。这将有效地在调用代码中直接内联这个值,*但是只有基本类型和字符串才能如此使用*。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

斜体转粗体

@@ -302,7 +303,7 @@ class MyClass {
}
```

Second, you can use the `[@JvmField](https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#instance-fields)` annotation on a public field in the companion object to instruct the compiler to not generate any getter or setter and expose it as a static field in the class instead, just like pure Java constants. In fact, this annotation has been created solely for Java compatibility reasons and I would definitely not recommend to clutter your beautiful Kotlin code with an obscure interop annotation if you don’t need your constant to be accessible from Java code. *Also, it can only be used for public fields.* In the context of Android development, you will probably only use this annotation to implement `Parcelable` objects:
第二,你可以在伴生对象的公共字段上使用 [`@JvmField`](https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#instance-fields) 注解来告诉编译器不要生成任何的 getter setter 方法,就像纯 Java 中的常量一样做为类的一个静态变量暴露出来。实际上,这个注解只是单独为了兼容 Java 而创建的,如果你的常量不需要从 Java 代码中访问的话,我是一点也不推荐你用一个晦涩的交互注解来弄乱你漂亮 Kotlin 代码的。*同样地,这只能运用在公共变量上*。在 Android 的开发环境中,你可能只在实现 `Parcelable` 对象的时候才会使用这个注解:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

斜体改加粗

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这(也)只能用在公共变量上

@phxnirvana
Copy link
Contributor

领~

@phxnirvana
Copy link
Contributor

校对认领(测试自动回复)

@linhe0x0
Copy link
Member

@phxnirvana 妥妥哒 🍻

Copy link
Contributor

@phxnirvana phxnirvana left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

完成。。问题不大


This is the tool of choice to figure out how Kotlin code gets translated to bytecode. With the Kotlin plugin installed in Android Studio, select the “Show Kotlin Bytecode” action to open a panel showing the bytecode of the current class. You can then press the “Decompile” button in order to read the equivalent Java code.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Show Kotlin Bytecode
Decompile
这两个不需要翻译吧?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

对的哈,^_

- Generating extra methods. As you may know, in Android applications [the number of allowed methods inside a single dex file is limited](https://developer.android.com/studio/build/multidex.html), and going above it requires configuring multidex which comes with limitations and performance penalties, particularly on Android versions before Lollipop.
- 基本类型装包,分配短期对象
- 实例化额外的对象在代码中不是直接可见的
- 生成额外的方法。正如你可能已知,在 Android 应用中[一个 dex 文件中允许的方法数量是有限的](https://developer.android.com/studio/build/multidex.html),超限了就需要配置 multidex,然而这有局限性且有损性能,尤其是在 Lollipop 之前的 Adnroid 版本中。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adnroid。。

@@ -98,24 +98,24 @@ class MyClass$myMethod$1 implements Function1 {
}
```

In your Android dex file, each lambda expression compiled as a `Function` will actually [add 3 or 4 methods](https://gist.github.com/JakeWharton/ea4982e491262639884e) to the total methods count.
在你的 Android dex 文件中,每一个 lambda 表达式都被编译成一个 `Function`,这将在方法总数上[增加3个或4个](https://gist.github.com/JakeWharton/ea4982e491262639884e)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这将最终[增加3到4个方法]

@@ -125,22 +125,22 @@ public interface Function1<in P1, out R> : Function<R> {
}
```

This means that calling a function passed as argument in a higher-order function will actually involve **systematic boxing and unboxing** when the function involves primitive types (like `Int` or `Long`) for input values or the return value. This may have a non-negligible impact on performance, especially on Android.
这意味着调用一个做为参数传递给高阶函数的方法时,如果输入值或者返回值涉及到基本类型(如 `Int` `Long`),实际上调用了**系统的装包和拆包**。这在性能上可能有着不容忽视的影响,特别是在 Android 上。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

装包还是装箱-。-


In our compiled lambda above, you can see that the result is boxed to an `Integer` object. The caller code will then immediately unbox it.
在上面编译好的 lambda 中,你可以看到结果被装包成了 `Integer` 对象。然后调用者代码马上将其拆包。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这边也是。。好像都叫装箱吧。。


First, it is possible to completely avoid any method call by declaring the value as a [compile-time constant](https://kotlinlang.org/docs/reference/properties.html#compile-time-constants) using the `**const**` keyword. This will effectively inline the value directly in the calling code, *but you can only use this for primitive types and Strings*.
首先,通过 **`const`** 关键字声明值为[编译时常量](https://kotlinlang.org/docs/reference/properties.html#compile-time-constants)来完全避免任何的方法调用是有可能的。这将有效地在调用代码中直接内联这个值,*但是只有基本类型和字符串才能如此使用*。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里我同意译者的翻译

@@ -302,7 +303,7 @@ class MyClass {
}
```

Second, you can use the `[@JvmField](https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#instance-fields)` annotation on a public field in the companion object to instruct the compiler to not generate any getter or setter and expose it as a static field in the class instead, just like pure Java constants. In fact, this annotation has been created solely for Java compatibility reasons and I would definitely not recommend to clutter your beautiful Kotlin code with an obscure interop annotation if you don’t need your constant to be accessible from Java code. *Also, it can only be used for public fields.* In the context of Android development, you will probably only use this annotation to implement `Parcelable` objects:
第二,你可以在伴生对象的公共字段上使用 [`@JvmField`](https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#instance-fields) 注解来告诉编译器不要生成任何的 getter setter 方法,就像纯 Java 中的常量一样做为类的一个静态变量暴露出来。实际上,这个注解只是单独为了兼容 Java 而创建的,如果你的常量不需要从 Java 代码中访问的话,我是一点也不推荐你用一个晦涩的交互注解来弄乱你漂亮 Kotlin 代码的。*同样地,这只能运用在公共变量上*。在 Android 的开发环境中,你可能只在实现 `Parcelable` 对象的时候才会使用这个注解:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这(也)只能用在公共变量上

> Always declare primitive type and String constants using the **const** keyword to avoid this.
> For other types of constants you can’t, so if you need to access the constant repeatedly, you may want to cache the value in a local variable.
> 与 Java 相比,在 Kotlin 中从伴生对象里读取一个 `static` 常量会增加 2 到 3 个额外的间接级别并且每一个常量都会生成 2 到 3个方法。
> 始终用 **const** 关键来声明基本类型和字符串常量从而避免这些(成本)。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

关键(字)


---

That’s all for this first article. Hopefully this gave you a better understanding of the implications of using these Kotlin features. Keep this in mind in order to write smarter code without sacrificing readability nor performance.
这就是第一篇文章的所有了。希望这些可以让你更好的理解使用这些 Kotlin 特性的影响。牢记这一点以便在不损失可读性和性能的情况下编写更智能的的代码。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这就是第一篇文章的所有了

这就是第一篇文章的全部内容了


Keep reading by heading to [part 2](https://medium.com/@BladeCoder/exploring-kotlins-hidden-costs-part-2-324a4a50b70): *local functions*, *null safety* and *varargs*.
继续阅读[第二部分](https://medium.com/@BladeCoder/exploring-kotlins-hidden-costs-part-2-324a4a50b70):*本地函数*,*空值安全*,*可变参数*。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

斜体改粗体

@linhe0x0
Copy link
Member

@Feximin 两位校对者都已经校对好了~ 可以来根据校对意见进行调整了哈 ┏ (゜ω゜)=☞

@Feximin
Copy link
Contributor Author

Feximin commented Jul 12, 2017

调整完毕了哈,感谢两位校对大佬。 @sqrthree @CACppuccino @phxnirvana

@linhe0x0 linhe0x0 merged commit f50ff9f into xitu:master Jul 13, 2017
@linhe0x0
Copy link
Member

@Feximin 已经 merge 啦~ 快快麻溜发布到掘金专栏然后给我发下链接,方便及时添加积分哟。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants