代码之家  ›  专栏  ›  技术社区  ›  Marat

与匿名内部类相比,kotlin lambda的性能如何?

  •  0
  • Marat  · 技术社区  · 6 年前

    android studio建议用lambda替换匿名内部类。

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

    反编译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");
        }
    }));
    

    在lambda之前,为了避免为onclicklistener设置的每个视图创建新对象,最好让activity/fragment实现 View.OnClickListener 接口或使用 Butterknife @OnClick 注释。

    下面的lambda会有多大的不同?

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

    反编译Java代码:

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

    如果是lambda我看不到 Log.d("MY_TAG", "textView clicked in lambda") 在反编译代码中。

    1 回复  |  直到 6 年前
        1
  •  3
  •   zsmb13    6 年前

    lambda的性能至少与创建匿名内部类一样好。

    • 如果它不捕获任何引用,编译器将使它成为任何类中的一个单例,并将其用作优化度量。这就是在你的情况下发生的事情,因为你的倾听者的内容不涉及lambda之外的任何内容。(这个单例实例是 null.INSTANCE 试图引用时,反编译器在解析为lambda生成的类的名称时遇到问题。)因此,在本例中,lambda的开销仅为1个对象分配。

    • 如果您的lambda确实捕获了一些东西,例如:

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

      …然后,无论何时设置侦听器,都必须分配一个新实例,因为这些实例必须存储对变量的引用,而这些引用在每次创建时可能会有所不同。在这种情况下,只要运行lambda所在的方法,就可以获得尽可能多的对象分配。注意,如果这只是在安装过程中完成的,比如 onCreate ,这也意味着只分配一个对象。

    所以你可能会得到:

    • 如果侦听器是已存在类(片段或活动)的方法,则为0个额外分配。
    • 如果使用不捕获任何内容的lambda,则为1个额外分配。
    • n额外的分配,如果您使用一个lambda来捕获某些内容,n是您运行lambda所在代码的次数,如果这只是在初始化期间,则可以是1。
    • n如果使用匿名内部类,则需要额外的分配,因为没有针对非捕获类的优化。同样,在很多情况下,这可能是1。

    即使在现有类中使用方法意味着0个额外的分配,我也不会使用这种方法来提高性能——任何收益都可能是完全看不到的。改为使用更具可读性和可维护性的解决方案。