Programación funcional: Lambda y Stream
Podemos utilizar el método de escritura de clase interna anónima al crear un hilo e iniciarlo:
Se puede modificar usando el formato Lambda. La modificación es la siguiente:
El método existente se define de la siguiente manera, donde IntBinaryOperator es una interfaz. Primero llame a este método utilizando escritura de clase interna anónima.
Método de escritura Lambda:
El método existente se define de la siguiente manera, donde IntPredicate es una interfaz. Primero llame a este método utilizando escritura de clase interna anónima.
Cómo escribir Lambda:
El método existente se define de la siguiente manera, donde Función es una interfaz. Primero llame a este método utilizando escritura de clase interna anónima.
Método de escritura Lambda:
El método existente se define de la siguiente manera, donde IntConsumer es una interfaz. Primero llame a este método utilizando escritura de clase interna anónima.
Método de escritura Lambda:
Stream de Java8 utiliza un modelo de programación funcional, como su nombre indica, se puede utilizar para realizar operaciones de transmisión en cadena en colecciones o matrices. Nos facilita operar en conjuntos o matrices.
Podemos llamar al método getAuthors para obtener la colección de escritores. Ahora debe imprimir los nombres de todos los escritores menores de 18 años y prestar atención a los duplicados.
Colección de una sola columna: colección object.stream()
Matriz: Arrays.stream (matriz) o use Stream.of para crear
Doble columna colección: conversión Cree una colección de una sola columna
Puede filtrar condicionalmente los elementos en la secuencia, y solo aquellos que cumplan con las condiciones de filtrado pueden continuar en la secuencia.
Por ejemplo:
Imprime los nombres de todos los escritores cuya longitud de nombre sea mayor que 1
Los elementos en la corriente de convección se pueden calcular o convertir.
Por ejemplo:
Imprime los nombres de todos los escritores
Puede eliminar elementos duplicados de la secuencia.
Por ejemplo:
Imprime los nombres de todos los escritores sin elementos repetidos.
Nota: El método distinto se basa en el método igual de Objeto para determinar si son el mismo objeto. Por lo tanto, debe prestar atención a anular el método igual.
Los elementos de la secuencia se pueden ordenar.
Por ejemplo:
Ordene los elementos de la secuencia en orden descendente por edad y no debe haber elementos duplicados.
Nota: Si llama al método sorted() con parámetros vacíos, los elementos de la secuencia deben implementar Comparable.
Puedes establecer la longitud máxima de la transmisión y el exceso de longitud se descartará.
Por ejemplo:
Ordene los elementos de la secuencia en orden descendente por edad, y no debe haber elementos duplicados, y luego imprima los nombres de los dos escritores más antiguos.
Omita los primeros n elementos de la secuencia y devuelva los elementos restantes
Por ejemplo:
Imprima todos los escritores excepto el escritor más antiguo, requisitos No puede haber duplicados Los elementos y los elementos se ordenan en orden descendente de edad.
Map solo puede convertir un objeto en otro objeto como un elemento en la secuencia. FlatMap puede convertir un objeto en varios objetos como elementos de la secuencia.
Ejemplo 1:
Imprime los nombres de todos los libros. Es necesario eliminar elementos duplicados.
Ejemplo 2:
Imprimir todas las categorías de datos existentes. Se requiere deduplicar la clasificación. Este formato no puede aparecer: filosofía, amor
Para recorrer los elementos en la secuencia, utilizamos los parámetros entrantes para especificar las operaciones específicas que se realizarán en los elementos atravesados.
Ejemplo:
Muestra los nombres de todos los escritores
Se puede utilizar para obtener el número de elementos en la secuencia actual.
Ejemplo:
Imprime el número de libros publicados por estos autores, teniendo cuidado de eliminar elementos duplicados.
Se puede utilizar para obtener el valor máximo en la secuencia.
Ejemplo:
Obtenga las puntuaciones más altas y más bajas de los libros publicados por estos autores e imprímalos.
Convierte la transmisión actual en una colección.
Ejemplo:
Obtiene una colección de Lista que almacena los nombres de todos los autores.
Obtén un conjunto de todos los títulos de libros.
Obtener una colección de mapas. La clave del mapa es el nombre del autor y el valor es Lista.
Se puede utilizar para determinar si hay elementos que cumplan las condiciones de coincidencia. El resultado es de tipo booleano.
Ejemplo:
Determinar si hay escritores de 29 años o más
Se puede utilizar para determinar si todos cumplen las condiciones coincidentes y el resultado es de tipo booleano. Si todos coinciden, el resultado es verdadero; de lo contrario, el resultado es falso.
Ejemplo:
Determinar si todos los escritores son adultos
Puede determinar si ninguno de los elementos de la transmisión cumple con las condiciones coincidentes. Si ninguno coincide, el resultado es verdadero; en caso contrario, el resultado es falso.
Ejemplo:
Determina si los escritores no tienen más de 100 años.
Obtiene cualquier elemento de la secuencia. Este método no tiene forma de garantizar que se obtendrá el primer elemento de la secuencia.
Ejemplo:
Obtenga cualquier escritor cuya edad sea mayor de 18 años y genere su nombre si existe.
Obtenga el primer elemento de la secuencia.
Ejemplo:
Busque el escritor más joven y escriba su nombre.
Los datos del flujo de convección calculan un resultado según el método de cálculo que usted especifique. (Operación de reducción)
La función de reducir es combinar los elementos en la secuencia. Podemos pasar un valor inicial y calculará los elementos en la secuencia y el valor de inicialización en secuencia de acuerdo con nuestro. método de cálculo. , el resultado del cálculo se calcula con los siguientes elementos.
El método de cálculo interno de la forma sobrecargada de reducción con dos parámetros es el siguiente:
Entre ellos, la identidad es el valor inicial que podemos pasar a través del parámetro del método, y el El cálculo específico de la aplicación del acumulador también se determina mediante parámetros del método.
Ejemplo:
Utilice reducir para encontrar la suma de las edades de todos los autores
Utilice reducir para encontrar la edad máxima de todos los autores
Usar reducir Encuentra la edad mínima entre todos los autores
Cálculo dentro de la forma sobrecargada de reducir
Si usa el método sobrecargado de un parámetro para encontrar el valor mínimo, el código es de la siguiente manera:
La ocurrencia más común cuando escribimos código es la excepción de puntero nulo. Entonces, en muchos casos necesitamos hacer varios juicios no vacíos.
Por ejemplo:
Especialmente cuando las propiedades del objeto siguen siendo un objeto. Habrá más de este juicio.
Demasiadas declaraciones de juicio harán que nuestro código parezca inflado.
Por lo tanto, se introdujo Opcional en JDK8. Después de desarrollar el hábito de usar Opcional, puede escribir código más elegante para evitar excepciones de puntero nulo.
Opcional también se usa en muchas API relacionadas con la programación funcional. Si no sabe cómo usar Opcional, también afectará el aprendizaje de la programación funcional.
Opcional es como una clase de empaquetado que puede encapsular nuestros datos específicos dentro del objeto Opcional. Luego podemos usar el método encapsulado en Opcional para operar los datos encapsulados y evitar excepciones de puntero nulo de manera muy elegante.
Generalmente utilizamos el método estático Nullable de Opcional para encapsular datos en un objeto Opcional. No habrá ningún problema independientemente de si el parámetro pasado es nulo.
Puede que le resulte problemático agregar una línea de código para encapsular los datos. Pero si modificamos el método getAuthor para que su valor de retorno sea el Opcional encapsulado, nos resultará mucho más conveniente usarlo.
Y en el desarrollo real, muchos de nuestros datos se obtienen de la base de datos. Mybatis puede y ya soporta Opcional desde la versión 3.5. Podemos definir directamente el tipo de valor de retorno del método dao como tipo Opcional, y MyBastis encapsulará los datos en un objeto Opcional y los devolverá. El proceso de encapsulación no requiere que lo operemos nosotros mismos.
Si está seguro de que un objeto no está vacío, puede utilizar el método estático de Opcional para encapsular los datos en un objeto Opcional.
Pero asegúrese de tener en cuenta que los parámetros pasados al usar of no deben ser nulos. (Pruebe lo que sucederá si pasa nulo)
Si el tipo de valor de retorno de un método es Opcional. Y si encontramos que el valor de retorno obtenido por un determinado cálculo es nulo, necesitamos encapsular nulo en un objeto Opcional y devolverlo. En este momento, puede utilizar el método estático de Opcional vacío para encapsular.
Entonces, al final, ¿qué método crees que es más conveniente? ofNullable
Después de obtener un objeto opcional, definitivamente necesitamos usar los datos que contiene. En este momento podemos usar su par de métodos ifPresent para consumir el valor.
Este método determinará si los datos encapsulados en él están vacíos. Si no están vacíos, se ejecutará el código de consumo específico. Esto hace que su uso sea más seguro.
Por ejemplo, el siguiente método de escritura evita elegantemente excepciones de puntero nulo.
Si queremos obtener el valor y procesarlo nosotros mismos, podemos utilizar el método get, pero no es recomendable. Porque se producirá una excepción cuando los datos dentro de Opcional estén vacíos.
Si queremos obtener el valor de forma segura. No recomendamos utilizar el método get, pero utilice los siguientes métodos proporcionados por Opcional.
Podemos utilizar el método filter para filtrar datos. Si originalmente hay datos, pero no cumplen con el juicio, también se convertirá en un objeto opcional sin datos.
Podemos utilizar el método isPresent para determinar si existen datos. Si está vacío, el valor de retorno es falso, si no está vacío, el valor de retorno es verdadero. Sin embargo, este método no refleja los beneficios de Opcional. Se recomienda más utilizar el método ifPresent.
Opcional también proporciona un mapa que nos permite convertir datos, y los datos convertidos aún están empaquetados por Opcional, lo que garantiza nuestra seguridad.
Por ejemplo, queremos obtener una colección de libros por autores.
Una interfaz con un solo método abstracto se llama interfaz funcional.
Las interfaces funcionales de JDK están marcadas con la anotación @FunctionalInterface. Pero independientemente de si se agrega o no la anotación, siempre que solo haya un método abstracto en la interfaz, es una interfaz funcional.
Cuando usamos lambda, si solo hay una llamada a un método en el cuerpo del método (incluido el constructor), podemos usar referencias de métodos para simplificar aún más el código.
Cuando usamos lambda, no necesitamos considerar cuándo usar referencias de métodos, qué método usar y cuál es el formato de las referencias de métodos. Solo necesitamos usar teclas de método abreviado para intentar convertirlo en una referencia de método después de escribir el método lambda y descubrir que el cuerpo del método tiene solo una línea de código y es una llamada al método.
A medida que utilizamos más referencias de métodos, gradualmente podemos escribir referencias de métodos directamente.
Nombre de clase o nombre de objeto:: nombre del método
De hecho, se refiere al método estático de la clase
Si anulamos el método, el método El cuerpo solo tiene una línea de código, y esta línea de código llama a un método estático de una determinada clase, y pasamos todos los parámetros del método abstracto para que se anulen a este método estático en orden. En este momento, podemos hacer referencia al estático. método del método de clase.
Por ejemplo:
El siguiente código se puede simplificar usando referencias de métodos
Tenga en cuenta que si el método que anulamos no tiene parámetros, el método llamado también no tiene parámetros equivale a cumplir con las reglas anteriores.
La optimización es la siguiente:
Si estamos anulando un método, solo hay una línea de código en el cuerpo del método, y esta línea de código llama a un método miembro de un objeto, y todos los parámetros del método abstracto que se anulará se pasan a este método miembro en orden. En este momento, podemos referirnos al método de instancia del objeto
Por ejemplo:
.Después de la optimización:
Si estamos anulando un método, solo hay una línea de código en el cuerpo del método, y esta línea de código llama al método miembro del primer parámetro, y colocamos el restante en el método abstracto que se anulará. Todos los parámetros se pasan a este método miembro en orden. En este momento, podemos referirnos al método de instancia de la clase.
Por ejemplo:
Después de la optimización, es el siguiente:
Si una línea de código en el cuerpo del método es un constructor, puede usar un constructor referencia.
Si estamos anulando un método, solo hay una línea de código en el cuerpo del método, y esta línea de código llama al constructor de una determinada clase, y colocamos todos los elementos en el método abstracto en ser anulado Los parámetros se pasan al constructor en orden y podemos hacer referencia al constructor en este momento.
Por ejemplo:
Después de la optimización:
Muchos de los métodos Stream que usamos antes usan genéricos. Por lo tanto, los parámetros y valores de retorno involucrados son todos tipos de datos de referencia.
Aunque estamos operando con números enteros y decimales, en realidad utilizamos sus clases de empaquetado. El empaquetado automático y el desempaquetado automático introducidos en JDK5 nos hacen tan conveniente usar la clase de empaquetado correspondiente como usar tipos de datos básicos. Pero debes saber que empacar y desempaquetar definitivamente llevará tiempo. Aunque esta vez el consumo es muy bajo. Pero cuando una gran cantidad de datos se encajona y se desempaqueta repetidamente, no se puede ignorar esta pérdida de tiempo.
De modo que nos permita optimizar esta parte del consumo de tiempo. Stream también proporciona muchos métodos específicos para tipos de datos básicos.
Por ejemplo: mapToInt, mapToLong, mapToDouble, flatMapToInt, flatMapToDouble, etc.
Cuando hay una gran cantidad de elementos en el flujo, podemos utilizar flujos paralelos para mejorar la eficiencia de las operaciones. De hecho, el flujo paralelo consiste en asignar tareas a varios subprocesos para que las completen. Si lo implementamos nosotros mismos en el código, en realidad será muy complicado y requerirá que usted tenga suficiente comprensión y conocimiento de la programación concurrente. Y si usamos Stream, solo necesitamos modificar la llamada de un método para usar flujos paralelos que nos ayuden a implementarlo, mejorando así la eficiencia.
El método paralelo puede convertir un flujo en serie en un flujo paralelo.
Los objetos de flujo paralelo también se pueden obtener directamente a través de paraleloStream.