What is Sam transformation

Single Abstract Method is actually a java8 concept that you can think of as an interface to a Method

Take a look at the thread pool we use every day

ExecutorService executorService= Executors.newScheduledThreadPool(3);

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

It is also possible to write using lambda in java8 below.

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

Copy the code

So these two ways are equivalent. But it is important to note that lambdas in Java are untyped, so they must need an interface to accept them.

Sam in the kotlin

val executorService: ExecutorService = Executors. NewScheduledThreadPool (3) / / kotlin anonymous inner class standard in writing the ExecutorService. Submit (object: a Runnable { override funrun() {
            System.out.println("hello world")}})Copy the code

Lambda in Kotlin could be written this way

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

Note here that Java lambdas are untyped, but Kotlin lambdas are typed.

The type of kotlin’s lambda in the example above is ()->Unit is a type with no arguments and no return value

For the lambda in Kotlin, take a closer look at the figure above.

This is actually creating a runnable and wrapping a lambda around the runnable, not a direct conversion.

Executorservice. submit(Runnable {println())"hello world")})Copy the code

When kotlin’s compiler encounters the above code, it actually generates a function for us

All this does is take a lambda expression and help us generate the corresponding code

Pit for Sam conversion in Kotlin

Lambda in Java is fake, just a Sam. Kotlin’s lambda is real, except he supports Sam. Sam conversion is supported.

Let’s define a Kotlin interface and a Kotlin method

interface Invokable{
    fun invoke()
}


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

Copy the code

Then let’s look at the call:

Look at the reason for the error

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

We need an invokable, but we gave a lambda, so the compile failed.

This is understandable. We’ve already talked about this.

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

Copy the code

If we define a function that looks like this then obviously it works. You can use lambda directly.

Of course, if you do this every time, it’s going to be a little bit harder to write the parameters, so we’ll just give it a different name

typealias Funtionx = () -> Unit

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

Copy the code

When using Sam conversions in Kotlin, be careful to write remove. For example:

Let’s define a simple event class:

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); }}Copy the code

Now kotlin code we’re going to add a listener

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

Lambda is easy to write, but be careful, you can’t remove lambda if you write it this way. If you think about it, the way it’s written is equivalent to

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

Also,

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

The process of creating an anonymous object is done by the compiler, so you can’t touch the object.

So there’s no way to remove it.

If you need remove, you can write it like this:

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

    }

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

Copy the code

or

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

Although this writing method is ugly ugly, but concise and comprehensive, no ambiguity will not make mistakes.