Colección de citas famosas - Mensajes de felicitación - Por qué Kotlin puede usar Lambda al llamar a Java

Por qué Kotlin puede usar Lambda al llamar a Java

1. Expresiones Lambda en Kotlin

Si ya has empezado a utilizar Koltin, o tienes algún conocimiento sobre él, entonces debes estar familiarizado con este método de escritura:

// Código 1: Código Kotlin view.setOnClickListener{

println("click")

}1234

Es similar al siguiente Java el código es equivalente:

//Código 2: código java view.setOnClickListener(new View.OnClickListener() { @Override

public void onClick(View v) {

System.out.println("click");

}

}); 1234567

Al igual que Java8, Kotlin admite expresiones Lambda, como que se muestra en el código 1, es una aplicación específica de Lambda.

Se puede ver que el uso de lambda reduce mucha redundancia, lo que hace que el código sea más conciso y elegante de escribir, y que la lectura sea más fluida y natural.

Pero, ¿alguna vez has pensado por qué Kotlin se puede escribir así y por qué se puede usar lambda aquí?

2. ¿Por qué se puede escribir así?

En Kotlin, una Lambda es una función anónima.

El código uno es en realidad la abreviatura del código tres a continuación:

// Código tres: código Kotlin view.setOnClickListener({

v -gt; println( "click")

})1234

La razón por la que se abrevia como código 1 se basa en estas dos características:

Si lambda es una función, solo parámetro, entonces puedes omitir los paréntesis al llamar a esta función

Si la función anónima representada por lambda tiene solo un parámetro, entonces puedes omitir su declaración y el símbolo -gt; para omitirlo) Nombre del nombre del parámetro)

OK, de la estructura del código tres, se puede ver más claramente que la función view.setOnClickListener aquí recibe una lambda como parámetro. En Kotlin, ¿qué tipo de función puede tomar lambda (es decir, otra función) como parámetro?

——Sí, es una función de orden superior.

¿Qué son las funciones de orden superior?

Las funciones de orden superior son funciones que utilizan funciones como parámetros o valores de retorno.

Esta es una de las diferencias entre Kotlin y Java. No hay soporte para funciones de orden superior en Java (java8 tiene funciones de orden superior). Cuando necesitamos usar conceptos similares en Java, el enfoque habitual es pasar una clase anónima como parámetro y luego implementar algunos de sus métodos abstractos, como en el código 2 anterior.

De hecho, si observa la definición de la función view.setOnClickListener del código Kotlin en Android Studio, encontrará que la firma de la función que ve es la definición de una función de orden superior:

Consejo para la firma de la función

Como se muestra arriba, la firma de la función es:

public final fun setOnClickListener(l: ((v: View!)-gt; Unit )!) : Unidad

Por supuesto, debido a que el método está definido en Java, también enumera la declaración de Java, así:

public void setOnClickListener(OnClickListener l)

Sabemos que muchos tipos de Kotlin y Java son diferentes, por lo que cuando se llamen entre sí, habrá una conversión de acuerdo con la relación correspondiente.

En cuanto a la conversión anterior del método setOnClickListener, es fácil de entender en otros lugares. Lo que es más difícil de entender es por qué el parámetro se convierte del tipo OnClickListener a (View) -gt;

(Ver) -gt; ¿Unidad? es un tipo de función, que representa una función que recibe un parámetro de tipo Vista y devuelve Unidad.

Es esta conversión de tipos de parámetros la que hace que el método setOnClickListener se convierta en una función de orden superior en Kotlin, razón por la cual puede usar lambda como parámetro.

Y esta conversión es la protagonista de este artículo mencionado en nuestro título - Conversión SAM (Single Abstract Method Conversions).

3. ¿Qué es la conversión SAM?

Vale, después de hablar tanto, finalmente fui al grano.

La conversión SAM, es decir, conversiones de método abstracto único, es la conversión de interfaces con un solo método abstracto no predeterminado; para las interfaces que cumplen esta condición (llamadas "tipo SAM"), puede hacerlo directamente. conviértalo en Kotlin Utilice Lambda para representarlo; por supuesto, la premisa es que el tipo de función representado por Lambda puede coincidir con el método en la interfaz.

La definición de OnClickListener en java es la siguiente: // Código 4: La definición de la interfaz OnClickListener en java public interface OnClickListener { void onClick(View v

}1234<; /p>

—— Resulta que es un tipo ?SAM calificado y el tipo de función onClick es ?(View) -gt; Por lo tanto, en Kotlin, la expresión lambda { println("click")} se puede utilizar en lugar de OnClickListener como parámetro de la función setOnClickListener.

4. Desambiguación de la conversión SAM

La existencia de la conversión SAM nos facilita llamar a Java. Puede funcionar muy bien la mayor parte del tiempo.

Por supuesto, existen excepciones ocasionales. Por ejemplo, considere el siguiente código: // Código 5 public class TestSAM {

SamType1 sam1,

SamType2. sam2,; setSam vacío público (SamType1 sam1) { this.sam1 = sam1;

} setSam vacío público (SamType2 sam2) { this.sam2 = sam2;

} interfaz pública SamType1; { void hacerAlgo(valor int);

} interfaz pública SamType2 { void hacerAlgo2(int valor

}

}123456789101112131415161718

< p); >—— TestSAM tiene dos métodos setSam sobrecargados,

—— y sus parámetros (SamType1, SamType2) son todas interfaces de tipo SAM.

——Y el tipo de función del único método abstracto de SamType1 y SamType2 es ?(Int) -gt?.

o(╯□╰)o

Esta situación se parece más a una barandilla para colgar, pero aún así puede suceder. En este momento, si usa un código similar directamente en Kotlin, se informará un error: // Código 6: llamado en Kotlin, este código no se puede compilar TestSAM().setSam {

println (" dodo") ?

}1234

provocará esta ambigüedad. El compilador no sabe qué interfaz entre SamType1 y SamType2 representa este Lambda.

La solución es indicar manualmente el tipo de interfaz que Lambda necesita reemplazar. Hay dos formas de indicarlo: // Código 7: Eliminación de desambiguación // Método 1 TestSAM().setSam (SamType1 { println. (" dodo") ?})

// Método 2 TestSAM().setSam ({ println("dodo") } as SamType1)12345

Por supuesto, también existe otro método: en lugar de utilizar el mecanismo de conversión SAM, utilice directamente una instancia de SamType1 como parámetro: // Código 8: utilice una clase anónima que implemente la interfaz como parámetro TestSAM().setSam(object: TestSAM.SamType1 { override divertido doSomething(value: Int) {

println("dodo")

}

})123456

Por supuesto, este método También es posible. En comparación con lambda, parece menos elegante (¡¡la elegancia es muy importante !!!).

5. Limitaciones de la conversión SAM

Hay dos limitaciones principales de la conversión SAM:

5.1 solo admite Java

Es decir, solo aplicable La llamada a Java en Kotlin no admite la llamada a Kotlin

La explicación oficial es que Kotlin ya admite tipos de funciones y funciones de orden superior, por lo que no es necesario convertirlo.

Si desea utilizar operaciones similares que requieren lambda como parámetros, debe definir usted mismo una función de orden superior que requiera un tipo de función específico.

5.2 solo admite interfaces, no clases abstractas.

El funcionario no dio más explicaciones.

Creo que probablemente sea para evitar confusiones. Después de todo, si se admiten clases abstractas, habrá demasiados lugares que deberán forzarse. Además, la clase abstracta en sí permite una gran cantidad de código lógico en su interior. Si se abrevia directamente como Lambda, será mucho más difícil localizar el error si algo sale mal.

6. Resumen

OK, eso es todo.

En resumen, la conversión SAM es la razón por la que Kotlin puede usar Lambda al llamar al código Java. Comprender sus principios puede hacernos sentir más cómodos escribiendo código y podemos resolver problemas mejor y más rápido cuando surgen problemas ocasionales.