Las expresiones Java Lambda son una nueva característica introducida por Java 8. Se puede decir que son un azúcar de sintaxis para la programación funcional simulada. Son similares a los cierres en JavaScript, pero son algo diferentes. El objetivo principal es proporcionar una sintaxis funcional para simplificar nuestra codificación.
Sintaxis básica de lambda
La estructura básica de Lambda es (argumentos) -> cuerpo, y hay varias situaciones:
El cuerpo debe incluir declaraciones con {}, y {} se puede omitir cuando solo hay una declaración.
Los métodos de escritura comunes son los siguientes:
(a) -> a * a
(int a, int b) -> a + b
(a, b) -> {return a - b;}
() -> System.out.println (Thread.CurrentThread (). GetId ())
FuncionalInterface
concepto
Las expresiones Java Lambda se basan en interfaces funcionales. ¿Qué es una interfaz funcional? En pocas palabras, es una interfaz con solo un método (función). El propósito de este tipo de interfaz es para una sola operación, que es equivalente a una sola función. Las interfaces comunes como Runnable y Comparator son interfaces funcionales, y se anotan con @FunctionalInterface.
Dar un ejemplo
Es fácil de entender usando el hilo como ejemplo. La interfaz Runnable es una interfaz comúnmente utilizada cuando pasamos por la programación, que incluye un método void run (), que es la lógica en ejecución del hilo. Según la sintaxis anterior, generalmente usamos la clase anónima Runnable para crear nuevos hilos, de la siguiente manera:
new Thread (new Runnable () {@Override public void run () {System.out.println (Thread.CurrentThread (). GetId ());}}). Start ();Si escribes demasiado, ¿no es aburrido? Las reglas de escritura basadas en Lambda se vuelven concisas y claras, de la siguiente manera:
new Thread (() -> System.out.println (Thread.CurrentThread (). GetId ())). Start ();
Presta atención a los parámetros del hilo. La implementación anónima de Runnable se implementa en una oración, y se escribe como la siguiente para comprender mejor.
Runnable r = () -> system.out.println (thread.currentThread (). GetId ());
nuevo hilo (r) .Start ();
Por supuesto, el propósito de Lambda no es solo escribir de manera concisa, sino resumir el propósito de nivel superior después de entenderlo.
Veamos otro ejemplo de un comparador. Según el método de escritura tradicional, como sigue:
Entero [] a = {1, 8, 3, 9, 2, 0, 5}; arrays.sort (a, nuevo comparador <integer> () {@Override public int Compare (Integer O1, Integer O2) {return o1 - o2;}});Las expresiones Lambda se escriben de la siguiente manera:
Entero [] a = {1, 8, 3, 9, 2, 0, 5};
Arrays.sort (a, (o1, o2) -> o1 - o2);
Interfaces funcionales en JDK
Para que la biblioteca de clases existente use directamente las expresiones Lambda, hubo algunas interfaces en Java 8 que se habían marcado como interfaces funcionales:
Se ha agregado un nuevo paquete java.util.function a Java 8, trayendo la interfaz funcional de uso común:
Además, se agregan funciones más específicas al procesamiento de tipos básicos, que incluyen: booleanSupplier, doubleBinaryOperator, DoubleConsumer, DoubleFunction <r>, DoublePredicate, DoubleUpplier, DoubleTointFunction, DoubleTolongFunction, DoubleTolongFunction, DoubleNoPoperator, intbinaryOperator, intbinaryperation, intconsumer, intconsumer, REFUNTRIONE <R, R, intbinary, intbinaryperation, intbinaryperation, intbinary, intbinaryCeation, intbinary, intb paray, intbinaryConation. Intsupplier, inttodoubleFunction, inttolongfunction, intunararioperator, longBinaryOperator, longConsumer, longFunction <r>, longPredicate, longSupplier, longTodoLoubleFunction, longTointFunction, longUnaryoperator, doundlbiFunction <T, u>, a doublefunction <T>, to t, t, t, uTbiMiS TointFunction <T>, tolongbifunción <t, u>, tolongfunction <t>. Combinado con las interfaces funcionales anteriores, puede ver el papel de la interfaz de un vistazo a través del nombre de clase de estas interfaces funcionales básicas.
Crear una interfaz funcional
A veces necesitamos implementar una interfaz funcional nosotros mismos, y el método es muy simple. Primero, debe asegurarse de que esta interfaz solo pueda tener una operación de función y luego anotar @FunctionalInterface en el tipo de interfaz.
Derivación de tipo
La derivación del tipo es la base de las expresiones lambda, y el proceso de derivación de tipo es el proceso de compilación de las expresiones lambda. El siguiente código es un ejemplo:
Function <string, integer> strToint = str -> integer.parseInt (str);
Durante la compilación, el proceso de derivación del tipo que entiendo es el siguiente:
El tipo de destino aquí es la clave, y la firma del método se obtiene a través del tipo de destino y luego lo compara con la expresión de Lambda.
Referencia de método
La base de la referencia del método (referencia del método) también es una interfaz funcional, que puede implementarse directamente como una interfaz funcional, tiene la misma función que las expresiones lambda y también depende de la derivación del tipo. Las referencias de métodos pueden verse como simplificación de las expresiones lambda que llaman solo un método.
La sintaxis mencionada por el método es: Tipo :: MethodName o InstanceName :: MethodName, y el nombre de método correspondiente al constructor es nuevo.
Por ejemplo, los ejemplos se usaron anteriormente:
Function <string, integer> strToint = str -> integer.parseInt (str);
La referencia del método correspondiente es
Function <string, integer> strToint = integer :: parseInt;
De acuerdo con el tipo de método, las referencias del método se dividen principalmente en los siguientes tipos: referencia del método del constructor, referencia del método estático, referencia del método de instancia en la instancia, referencia del método de instancia en el tipo, etc.
Referencia del método del constructor
La sintaxis es: tipo :: nuevo. Por ejemplo, la siguiente función es convertir una cadena en una matriz
Escritura de referencia de método
Function <string, integer> strToint = integer :: new;
Escritura lambda
Function <string, integer> strToint = str -> new Integer (str);
Escritura tradicional
Function <string, integer> strToint = new function <String, Integer> () {@Override public Integer Aplicar (String Str) {return new Integer (str); }};
Referencia del constructor de matriz
La sintaxis es: tipo [] :: nuevo. Por ejemplo, la siguiente función es construir una matriz de cadenas de longitud especificada
Escritura de referencia de método
Function <integer, string []> fiedArray = string [] :: new;
Escritura de referencia de método
Function <integer, string []> fiedArray = longitud -> new String [longitud];
Escritura tradicional
Function <integer, string []> fixedArray = new function <integer, string []> () {@Override public string [] aplicar (longitud entera) {return new String [longitud]; }};Referencia de método estático
La sintaxis es: tipo :: nuevo. Ya que la siguiente función también se usa para convertir cadenas en matrices
Escritura de referencia de método
Function <string, integer> strToint = integer :: parseInt;
Escritura lambda
Function <string, integer> strToint = str -> integer.parseInt (str);
Escritura tradicional
Function <String, Integer> strToint = new Function <String, Integer> () {@Override public Integer Aplicar (String Str) {return Integer.ParseInt (str); }};Referencia del método de instancia en una instancia
La sintaxis es: InstanceName :: MethodName. Por ejemplo, la siguiente función de juicio se usa para determinar si el nombre de pila existe en la lista
Lista <String> Names = Arrays.aslist (nueva cadena [] {"Zhang San", "li si", "wang wu"});
Predicado <String> checkNameExists = nombres :: contiene;
System.out.println (checkNameExists.test ("zhang san"));
System.out.println (checkNameExists.test ("zhang si"));
Referencia del método de instancia en el tipo
La sintaxis es: Tipo :: MethodName. La referencia de tiempo de ejecución se refiere a un objeto en el contexto, como la siguiente función para devolver la longitud de la cadena
Function <string, integer> calcStrlength = string :: long -long; system.out.println (calcStrlength.apply ("zhang san")); list <string> nombres = arrays.aslist (new String [] {"Zhangsan", "lisi", "wangwu"}); nombres.stream ().
Por ejemplo, la siguiente función ha especificado un separador para dividir la cadena en una matriz
Bifunción <string, string, string []> split = string :: split;
String [] nombres = Split.apply ("Zhangsan, Lisi, Wangwu", ",");
System.out.println (Arrays.ToString (nombres));
Objetos de transmisión
concepto
¿Qué es la transmisión? La transmisión aquí es diferente de InputStream y OutputStream en IO. Stream se encuentra en el paquete java.util.stream y también se agrega recientemente a Java 8. La transmisión es solo un conjunto de elementos que admiten operaciones de agregación paralela en serie, que puede entenderse como una versión mejorada de una colección o iterador. ¿Qué es una operación de agregación? Para dar un ejemplo simple, los comunes incluyen media, máxima, mínima, suma, clasificación, filtrado, etc.
Varias características de la transmisión:
Procesamiento único. Después de completar un procesamiento, el flujo actual está cerrado.
Admite formas comunes de obtener corrientes en operaciones paralelas
Obtenga de la colección
Colección.stream ();
Colección.ParallelStream ();
Fábrica estática
Arrays.stream (matriz)
Stream.of (t ...)
Intstream.range ()
Aquí solo daremos una breve introducción a la transmisión, y habrá aplicaciones específicas a continuación. Si desea hablar sobre la relación entre las expresiones de Stream y Lambda, en realidad no hay una relación particularmente cercana. Es solo que las expresiones de Lambda facilitan enormemente el uso de la corriente. Sin expresiones lambda, se generará una gran cantidad de clases anónimas durante el uso de la transmisión, lo cual es muy incómodo.
Dar un ejemplo
Las siguientes demostraciones dependen del objeto del empleado y del objeto de lista compuesto por el objeto del empleado.
Empleado de clase pública {nombre de cadena privada; sexo de cuerda privada; edad privada int; empleado público (nombre de cadena, sexo de cadena, int age) {super (); this.name = name; this.sex = sexo; this.age = edad; } public String getName () {nombre de retorno; } public String getsex () {return sex; } public int getAge () {return Age; } @Override public string toString () {StringBuilder Builder = new StringBuilder (); builder.append ("empleado {name ="). append (name) .append (", sex ="). append (sexo) .append (", age ="). append (edad) .append ("}"); return builder.ToString (); }} List <Eltage> Employes = New ArrayList <> (); empleados.Add (nuevo empleado ("Zhang San", "hombre", 25)); empleados.Add (nuevo empleado ("Li si", "mujer", 24)); empleados.Add (nuevo empleado ("Wang Wu", "mujer", 23)); empleados.add (nuevo empleado ("sábado", "masculino", 22)); empleados.add (nuevo empleado ("Sun Qi", "mujer", 21)); empleados.add (nuevo empleado ("liu ba", "masculino", 20));Imprima a todos los empleados
La colección proporciona el método foreach para nosotros para operar objetos individuales uno por uno.
empleados.ForEach (E -> System.out.println (e));
o
empleados.stream (). foreach (e -> system.out.println (e));
Ordenar por edad
Colección.sort (empleados, (e1, e2) -> e1.getage () - e2.getage ());
empleados.ForEach (E -> System.out.println (e));
o
empleados.stream (). Sorted ((e1, e2) -> e1.getage () -e2.getage ()). foreach (e -> system.out.println (e));
Imprima la empleada más antigua
Máx/min devuelve el elemento más grande/min en condiciones de clasificación especificadas
Empleado MaxageFeMaleEmployee = Employes.stream () .Filter (E -> "femenino" .equals (e.getSex ()) .max ((e1, e2) -> e1.getage () -e2.getage ()) .get (); system.println (maxageFemaleEmployee);
Imprimir empleados masculinos mayores de 20 años
filtra los elementos que cumplen con los criterios
Empleados.stream ()
.filter (e -> e.getage ()> 20 && "masculino" .equals (e.getSex ())))
.ForEach (E -> System.out.println (e));
Imprima los dos empleados masculinos más antiguos
El método límite intercepta elementos limitados
empleados.stream () .filter (e -> "masculino" .equals (e.getsex ())) .sorted ((e1, e2) -> e2.getage () -e1.getage ()) .limit (2) .forEach (e -> system.out.println (e));
Imprima los nombres de todos los empleados masculinos, use, separe
Mapa para formar una nueva transmisión después de ejecutar la función dada.
String MaleEmployeEsNames = empleados.stream () .map (e -> e.getName ()) .collect (coleccionista.Joining (",")); System.out.println (maleEmployEeseSnames);Información estadística
IntSummaryStatistics, Doubleummarystatistics, LongSummarystatistics contiene los datos resumidos en la corriente.
IntsummaryStatistics stat = empleados.stream () .maptoint (empleado :: getage) .sumMaryStatistics (); system.out.println ("Número total de empleados:" + stat.getCount ()); system.out.println ("edad máxima:" + stat.getmax ()); system.println ("minimum edad:" + " +" + " +" + " +" + " +" stat.getmin ()); system.out.println ("edad promedio:" + stat.getaverage ());Resumir
Las expresiones de Lambda pueden reducir mucho código y mejorar la productividad. Por supuesto, hay desventajas, es decir, expresiones complejas serán poco legibles, o puede ser porque no están muy acostumbrados a ello. Si te acostumbras, creo que te gustará. Todo tiene dos lados, depende de cómo equilibramos los pros y los contras, especialmente en un equipo.
Lo anterior es la información que clasifica Java8 Javalambda. Continuaremos agregando información relevante en el futuro. ¡Gracias por su apoyo para este sitio web!