Kotlin与java8的SAM转换对比(进阶)

什么是sam 转换

Single Abstract Method 实际上这是java8中提出的概念,你就把他理解为是 一个方法的接口 的就可以了

看一下我们每天都在使用的线程池

ExecutorService executorService= Executors.newScheduledThreadPool(3);

  executorService.execute(new Runnable() {
   @Override
   public void run() {
    System.out.println("hello world");
   }
  });

用下面的java8中的lambda 来写 也是可以的。

xecutorService.execute(()->System.out.println("hello world"));

所以说 这两种写法是 等价 的。 但是这里要强调的是 java中的lambda是没有类型的,所以他必须需要一个接口来接受他。

kotlin中的sam

 val executorService: ExecutorService = Executors.newScheduledThreadPool(3)
 //kotlin中的 匿名内部类的标准写法
 executorService.submit(object :Runnable{
  override fun run() {
   System.out.println("hello world")
  }
 })

kotlin中的lambda 这里可以这么写

executorService.submit { System.out.println("hello world") }

这里要注意的是 java的lambda是没有类型的,但是kotlin的lambda有类型

上文中的例子 这个kotlin的lambda的类型就是 ()->Unit 是一个没有参数也没有返回值的类型

对于kotlin中的lambda来说,仔细看上面的图 就可以知道。

这里实际上是创建了一个runnable 并且在这个runnable里面 包装了一下lambda,并不是直接转换的

//kotlin中 匿名内部类 还可以这么写
 executorService.submit(Runnable { println("hello world") })

上面的代码 我们再解释一下 ,kotlin的编译器 再遇到上面的代码的时候 实际上 是 帮我们生成了 一个函数

这个函数的作用就是接收一个 lambda表达式 然后帮我们生成对应的代码

kotlin中sam 转换的坑

java中的lambda是假的,只是一个sam而已。 kotlin的lambda是真的,只不过他还支持sam。是支持sam转换的。

下面定义一个kotlin的接口 以及kotlin的方法

interface Invokable{
 fun invoke()
}

fun submit(invokable: Invokable){
 invokable.invoke()
}

然后我们看看调用:

看看报错的原因

Type mismatch: inferred type is () -> Unit but Invokable was expected

提示我们 这里 是需要一个invokable,但是给了一个lambda ,不符合要求,所以编译不能通过。

这个可以理解吧,前面已经讲过了。

fun submit2(block:()->Unit){
 block.invoke()
}

如果我们定义一个这样的函数 那显然就是可以的了。就可以直接使用lambda了。

当然如果每次这么写,函数参数也比较难写,所以我们干脆 就起个别名

typealias Funtionx = () -> Unit

fun submit2(block: Funtionx) {
 block.invoke()
}

另外就是在kotlin中使用sam转换的时候 一定要小心remove的写法,例如:

我们定义一个简单的event类:

public class EventManager {
 interface OnEventListener {
  void onEvent(int event);
 }

 private List<OnEventListener> onEventListeners=new ArrayList<OnEventListener>();

 public void addOnEventListener(OnEventListener listener){
  onEventListeners.add(listener);
 }

 public void removeEventListener(OnEventListener listener){
  onEventListeners.remove(listener);
 }
}

现在 kotlin代码 我们要add 一个监听

 val eventManager = EventManager()
 eventManager.addOnEventListener {
  println("onEvent$it")
 }

lambda写起来很方便,但是你要小心了,你这么写的话 你是没办法remove的。 你仔细想一想,上面的写法 等于是

 eventManager.addOnEventListener(object : EventManager.OnEventListener {
  override fun onEvent(event: Int) {
   {
    println("onEvent$event")
   }()
  }
 })

也等于是

 eventManager.addOnEventListener(object : EventManager.OnEventListener {
  override fun onEvent(event: Int) {
   println("onEvent$event")
  }
 })

这个创建匿名对象的过程 被编译器做了,你是接触不到这个object的。

所以自然也就没办法去remove了。

遇到这种需要remove的情况 我们就可以用如下写法:

 val onEvent = EventManager.OnEventListener {
  println("onEvent$it")

 }

 eventManager.addOnEventListener(onEvent)
 eventManager.removeEventListener(onEvent)

或者

val onEvent2 = object : EventManager.OnEventListener {
  override fun onEvent(event: Int) {
   println("onEvent$event")
  }
 }

这种写法虽然丑是丑了一点,但是言简意赅,不会出歧义 也不会出错。

到此这篇关于Kotlin与java8的SAM转换对比的文章就介绍到这了,更多相关Kotlin与java8的SAM转换 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Kotlin中的sam(函数式接口)详解

    用lambda表达式去表示java中的匿名类实例 在使用java去给一个按钮设置监听我们通常会通过创建匿名类实例,如下 Button.setOnClickListener(new OnClickListener()){ @Override public void onClick(View v){ Toast.makeText(this,"Hello World",Toast.LENGTH_LONG).show() } } 在kotlin我们可以通过传递一个lambda表达式去代替这个实

  • Kotlin与java8的SAM转换对比(进阶)

    什么是sam 转换 Single Abstract Method 实际上这是java8中提出的概念,你就把他理解为是 一个方法的接口 的就可以了 看一下我们每天都在使用的线程池 ExecutorService executorService= Executors.newScheduledThreadPool(3); executorService.execute(new Runnable() { @Override public void run() { System.out.println("

  • 关于Kotlin中SAM转换的那些事

    前言 随着 Kotlin 1.4 正式发布,关于 SAM 转换的一些问题就可以盖棺定论了.因为这里要讲的都是些旧的东西,所以这是一篇灌水文. Kotlin对SAM转换的支持情况 在 1.4 发布之前,经常有新人在群里提出关于 SAM 转换的问题. 为了说明这个问题,要分成几个情况来讨论. 我们需要区分这个接口是Java接口还是Kotlin接口: // 这是Java interface JavaSome { void some(); } // 这是Kotlin interface KotlinSo

  • Kotlin 挂起函数CPS转换原理解析

    目录 正文 1.什么是CPS转换 2.CPS的过程是怎么让参数改变的 3.CPS的过程是怎么让返回值改变的 4.挂起函数的反编译 5.非挂起函数的分析 正文 普通函数加上suspend之后就成为了一个挂起函数,Kotlin编译器会将这个挂起函数转换成了带有参数Continuation<T>的一个普通函数,Continuation是一个接口,它跟Java中的Callback有着一样的功能,这个转换过程被称为CPS转换. 1.什么是CPS转换 挂起函数中的CPS转换就是把挂起函数转换成一个带有Ca

  • Kotlin中单例模式和Java的对比浅析

    前言 单例模式,一直以来是我们在日常开发中最常用的一种设计模式,更是面试中非常重要,也非常容易被问到的问题.在日常开发中,大家常用的语言还是Java,但今天我给大家带来的是在Kotlin语言中,单例模式是怎么编写的,并且会对比Java方式,下面话不多说了,来一起看看详细的介绍吧 一.懒人写法(恶汉式) java中 public class Singleton{ public static final Singleton instance = new Singleton(); public Sin

  • Kotlin中?和!!的区别详细对比

    前言 很多同学刚上手使用Kotlin知道它有针对Java NullPointerException的管理,而在Kotlin中?和!!均是和NullPointerException有关系,可他们的区别到底是什么呢?为什么别人开发的项目中出现了好多"?",而我读起来却满脸问号. 不懂就问百度呀,确实有人解释它们的区别,比如: 这是输入"kotlin ?和!!"搜索到的百度第一条答案,确实这位说的没错.不过我觉得对于一个刚接触KT(Kotlin)的新手来说,他恐怕需要有汉

  • kotlin实战教程之lambda编程

    前言 ambda即lambda表达式,简称lambda.本质上是可以传递给其它函数的一小段代码.有了lambda,可以轻松地把通用代码结构抽取成库函数.lambda最常见的用途是和集合一起配合.kotlin甚至还拥有带接收者的lambda,这是一种特殊的lambda. 本文是对<<kotlin实战>>中 "lambda编程"一章的总结,主要记录了一些我认为比较重要的点 在kotlin中常见的lambda用法主要由以下几种: 与集合一起使用 lambda可以与任意

  • 关于Kotlin的自动类型转换详解

    前言 Kotlin 1.4 正式版在好早以前就已经发布了.关于那些"看得见"的新特性,比如SAM转换.参数列表末尾的可选逗号什么的,已经有无数文章介绍过了.所以本文打算介绍一些可能是鲜为人知的.Kotlin 官方团队偷偷塞进 1.4 的新特性. 不过单独讲这些东西会显得文章太过单薄,于是我打算把其他相似的东西拉一起凑凑字数. 本文使用的 Kotlin 版本为 Kotlin 1.4. 本文要讲的东西 看题目就知道了,Kotlin 里自动类型转换(automatic type conver

  • 一文讲解Kotlin中的contract到底有什么用

    目录 前言 测试 查看 contract 函数 returns callsInPlace 总结 前言 我们在开发中肯定会经常用Kotlin提供的一些通用拓展函数,当我们进去看源码的时候会发现许多函数里面有contract {}包裹的代码块,那么这些代码块到底有什么作用呢?? 测试 接下来用以下两个我们常用的拓展函数作为例子 public inline fun <T, R> T.run(block: T.() -> R): R { contract { callsInPlace(block

  • Kotlin中的contract到底有什么用详解

    目录 前言 测试 总结 前言 我们在开发中肯定会经常用Kotlin提供的一些通用拓展函数,当我们进去看源码的时候会发现许多函数里面有contract {}包裹的代码块,那么这些代码块到底有什么作用呢?? 测试 接下来用以下两个我们常用的拓展函数作为例子 public inline fun <T, R> T.run(block: T.() -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } ret

  • Java与Kotlin互调原理

    目录 一.Kt调用-Java参数非null的处理 @NotNull Kotlin中调用 二.Kt调用-Java中使用kt关键字声明的变量和方法 Kotlin中调用 三.Kt调用Java-SAM转换 在Kotlin中调用 四.Kt中禁止Java调用某方法 @JvmSynthetic 五.Java调用Kt-扩展函数 @file:JvmName(“xx”) 六.Java调用kt-成员变量 @JvmField Kotlin @get:JvmName,@set:JvmName Kotlin 七.Java调

随机推荐