Leyendo sobre la especificación Java-8, sigo viendo referencias a 'tipos de SAM'. No he podido encontrar una explicación clara de lo que es esto.
¿Qué es un tipo SAM y cuál es un escenario de ejemplo de cuándo se puede usar uno?
Leyendo sobre la especificación Java-8, sigo viendo referencias a 'tipos de SAM'. No he podido encontrar una explicación clara de lo que es esto.
¿Qué es un tipo SAM y cuál es un escenario de ejemplo de cuándo se puede usar uno?
Respuestas:
Para resumir el enlace Jon registró 1 en caso de que alguna vez se cae, "SAM" significa "método abstracto sola", y "SAM-tipo" se refiere a interfaces como Runnable
, Callable
, etc. Las expresiones lambda, una nueva característica en Java 8, son, se considera un tipo SAM y se puede convertir libremente a ellos.
Por ejemplo, con una interfaz como esta:
public interface Callable<T> {
public T call();
}
Puedes declarar Callable
usando expresiones lambda como esta:
Callable<String> strCallable = () -> "Hello world!";
System.out.println(strCallable.call()); // prints "Hello world!"
Las expresiones lambda en este contexto son principalmente azúcar sintáctico. Se ven mejor en código que las clases anónimas y son menos restrictivos en la denominación de métodos. Tome este ejemplo del enlace:
class Person {
private final String name;
private final int age;
public static int compareByAge(Person a, Person b) { ... }
public static int compareByName(Person a, Person b) { ... }
}
Person[] people = ...
Arrays.sort(people, Person::compareByAge);
Esto crea el Comparator
uso de un método específico que no comparte el mismo nombre que Comparator.compare
, de esa manera, no tiene que seguir el nombre de la interfaz de los métodos y puede tener múltiples anulaciones de comparación en una clase, luego cree los comparadores sobre la marcha a través de Las expresiones lambda.
Yendo más profundo ...
En un nivel más profundo, Java los implementa utilizando la invokedynamic
instrucción de código de bytes agregada en Java 7. Dije anteriormente que declarar un Lambda crea una instancia de una clase anónima Callable
o Comparable
similar, pero eso no es estrictamente cierto. En cambio, la primera vez que invokedynamic
se llama, crea un controlador de función Lambda utilizando el LambdaMetafactory.metafactory
método , luego usa esta instancia en caché en futuras invocaciones de Lambda. Se puede encontrar más información en esta respuesta .
Este enfoque es complejo e incluso incluye código que puede leer valores primitivos y referencias directamente desde la memoria de la pila para pasar a su código Lambda (por ejemplo, para evitar la necesidad de asignar una Object[]
matriz para invocar su Lambda), pero permite futuras iteraciones de la implementación de Lambda para reemplazar implementaciones antiguas sin tener que preocuparse por la compatibilidad de bytecode. Si los ingenieros de Oracle cambian la implementación subyacente de Lambda en una versión más nueva de la JVM, Lambdas compilada en una JVM anterior usará automáticamente la implementación más nueva sin ningún cambio por parte del desarrollador.
1 La sintaxis en el enlace no está actualizada. Eche un vistazo al Lambda Expressions Java Trail para ver la sintaxis actual.