简体   繁体   English

与匿名内部类相比,Kotlin lambda的表现如何?

[英]How does Kotlin lambda perform compared to Anonymous inner class?

Android Studio suggests to replace anonymous inner class with lambda. Android Studio建议用lambda代替匿名内部类。

titleTextView.setOnClickListener(object : View.OnClickListener {
    override fun onClick(v: View?) {
        Log.d("MY_TAG", "textView clicked in anonymous inner class")
    }
})

Decompiled Java code: 反编译的Java代码:

var10000 = this.titleTextView;
if (this.titleTextView == null) {
    Intrinsics.throwUninitializedPropertyAccessException("titleTextView");
}

var10000.setOnClickListener((OnClickListener)(new OnClickListener() {
    public void onClick(@Nullable View v) {
        Log.d("MY_TAG", "textView clicked in anonymous inner class");
    }
}));

Before lambda, to avoid creation of new object for each of views that were set OnClickListener, it was better to have Activity/Fragment implement View.OnClickListener interface or use Butterknife 's @OnClick annotation. 在使用lambda之前,为避免为设置了OnClickListener的每个视图创建新对象,最好让Activity / Fragment实现View.OnClickListener接口或使用Butterknife@OnClick批注。

How different the performance will be with lambda like below? 如下所示的lambda的性能会有何不同?

titleTextView.setOnClickListener { Log.d("MY_TAG", "textView clicked in lambda") }

Decompiled Java code: 反编译的Java代码:

TextView var10000 = this.titleTextView;
if (this.titleTextView == null) {
    Intrinsics.throwUninitializedPropertyAccessException("titleTextView");
}

var10000.setOnClickListener((OnClickListener)null.INSTANCE);

In case of lambda I don't see the Log.d("MY_TAG", "textView clicked in lambda") in decompiled code. 在使用lambda的情况下,在反编译的代码Log.d("MY_TAG", "textView clicked in lambda")不到Log.d("MY_TAG", "textView clicked in lambda")

The performance of a lambda will be at least as good as creating an anonymous inner class. Lambda的性能至少与创建匿名内部类一样好。

  • If it doesn't capture any references, the compiler will make it a singleton inside whatever class it's used in as an optimization measure. 如果未捕获任何引用,则编译器会将其用作优化措施所使用的任何类中的一个。 This is what happens in your case, as the contents of your listener don't refer to anything outside of the lambda. 这就是您的情况,因为侦听器的内容没有引用lambda之外的任何内容。 (This singleton instance is what the null.INSTANCE is trying to refer to, the decompiler just has trouble with resolving the name of the class generated for the lambda.) So in this case, the cost of the lambda is just 1 object allocation. (此单例实例是null.INSTANCE试图引用的实例,反编译器在解析为lambda生成的类的名称时遇到了麻烦。)因此,在这种情况下,lambda的开销仅为1个对象分配。

  • If your lambda does capture something, eg like this: 如果您的lambda确实捕获到某些东西,例如:

     val random = Random().nextInt() titleTextView.setOnClickListener { Log.d("MY_TAG", "textView clicked in lambda, random value was $random") } 

    ... then whenever you set the listener, a new instance will have to be allocated, because these instances have to store references to variables, which might be different each time they're created. ...然后,每当您设置侦听器时,都将必须分配一个新实例,因为这些实例必须存储对变量的引用,每次创建变量时引用可能会有所不同。 In this case, you get as many object allocations as many times you run the method the lambda's in. Note that if this is only done during setup, like in onCreate , this will mean just 1 object allocation as well. 在这种情况下,您获得的对象分配与运行lambda的方法的次数一样多。请注意,如果仅在安装过程中完成此操作(如onCreate ,则这也将意味着仅分配1个对象。

So you may get: 这样您可能会得到:

  • 0 extra allocations, if your listeners are methods of your already existing class (Fragment or Activity). 如果您的侦听器是您现有类的方法(片段或活动),则额外分配0个。
  • 1 extra allocation if you use a lambda that doesn't capture anything. 如果您使用不捕获任何内容的lambda,则额外分配1个。
  • N extra allocations if you use a lambda that captures something, N being the number of times you run the code where the lambda is used, which could be 1 if this is only during initialization. 如果您使用捕获了某些内容的lambda,则N个额外的分配,N为您运行代码使用lambda的次数,如果仅在初始化期间,则为1。
  • N extra allocations if you use an anonymous inner class, as there's no optimization there for non-capturing classes. 如果使用匿名内部类,则没有N个额外的分配,因为那里没有针对非捕获类的优化。 Again, this may actually be 1 in a lot of cases. 同样,在很多情况下,这实际上可能是1。

Even though using methods inside the existing class would mean 0 additional allocations, I wouldn't go with that approach for performance - any gains will probably be completely unnoticeable. 即使在现有类中使用方法意味着增加0个分配,我也不会采用这种方法来提高性能-任何收益都可能完全不明显。 Go with the solution that's more readable and maintainable for you instead. 而是选择对您而言更具可读性和可维护性的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM