Transcripciones
1. Introducción: Hola a todos,
bienvenidos a la clase Java ocho streams, una introducción
práctica. Mi nombre es jornero, y en esta clase te
estaré contando todo sobre las transmisiones
en su uso. Esta clase está dirigida a dosificar, tener poca o ninguna
experiencia con arroyos es gasa para darte una idea la posibilidad de arroyos. Reconoces situaciones en las
que las transmisiones pueden ser útiles. Profundizaremos en el uso de
arroyos y ampliamente. Quieres utilizarlos en interfaces
funcionales
y lambdas. Voy a explicar las operaciones de
uso común para aquellos ansias o enfoque
más práctico. Este curso también
ofrece ejercicios para poner en práctica los conocimientos
aprendidos. Empecemos.
2. Stream uso y uso de estuches: Transmite el uso y el caso de uso. Las corrientes de agua utilizan
para simplemente dicho, una corriente puede ser utilizada para
procesar una colección de artículos. En un capítulo posterior, profundizaremos en algunas de las formas específicas de
procesar una colección. Pero por ahora, solo piensa en
procesar como filtrar, cambiar y enriquecer
los datos para su recolección. Tenga en cuenta, sin embargo,
las producciones utilizadas como entrada para las transmisiones
en realidad no son cambiadas por las transmisiones. En cambio, ejecutar
un stream nos da resultados
separados desconectados de la colección original. Estos pasos
de procesamiento de operaciones se escriben de manera funcionalmente
descriptiva. decir, una transmisión se lee como
una historia cuando se hace correctamente, que es lo que los hace
tan increíblemente útiles. Para mostrar esto. Aquí hay un ejemplo de una forma
convencional de filtrar, recopilar, clasificar
e imprimir algunos datos. Yo uso la misma lógica
escrita en arroyos. Si bien estoy seguro de que eventualmente podrás
entender ambos
lados, creo que todos podemos estar de acuerdo en que usar streams hace que sea mucho, mucho más fácil entender
lo que hace el código. Entonces ahí lo tienes.
Los streams se utilizan para procesar una colección de artículos
de una manera muy razonable. ¿Cómo funcionan las transmisiones? Como se acaba de decir, los arroyos trabajan
en una colección de artículos. Es posible que te hayas dado cuenta de que la colección de palabras
coincide con una interfaz. En Java. interfaz que se encuentra en
el paquete Java util es nuestro enlace para trabajar
con streams. La mayoría de las veces, comúnmente usa una
lista o un conjunto para iniciar una transmisión que extiende la interfaz de
recopilación. Hay otras formas
de crear una corriente. No vamos a entrar en
ellos en esta clase. Los puedes encontrar
en los recursos. Con la llegada de Java ocho, un método predeterminado llamado ha agregado
un método predeterminado llamado
stream a
la interfaz de colección. Para aquellos que no estén familiarizados
con los métodos predeterminados. Los métodos predeterminados le
permiten agregar nuevas funcionalidades a
las interfaces de sus bibliotecas y garantizar la compatibilidad
binaria con el código escrito para
versiones anteriores de las interfaces. Este método predeterminado stream devuelve una instancia
del stream cuesta la clase API central que nos permite
trabajar con ellos. Después de crear la transmisión, ahora
puede encadenar operaciones juntas y ejecutar la transmisión. Más sobre esto más adelante. Resumamos lo que hemos aprendido hasta ahora. Los streams se utilizan para procesar una colección de elementos
de una manera muy legible. Las transmisiones no cambian
esta colección de fuentes, sino que crean
un resultado separado desconectado de la colección
original. La interfaz de flujo es el costo central de API de
trabajar con streams. Cualquier cosa que extienda
o implemente la interfaz de recopilación tiene un método de flujo predeterminado para interactuar con conjuntos de clase API
central.
3. Interfaces funcionales y Lambda: Interfaces funcionales
y lambdas. Antes de que podamos comenzar a
hablar de operaciones de transmisión, tendremos que hablar
sobre los requisitos previos usar tiras. Las lambdas. Las lambdas son básicamente clases
internas anónimas, interfaces
funcionales de las cuales el compilador Java implícito denota la información necesaria. Empecemos desde el principio. Clases internas anónimas. Al implementar una interfaz, vas a implementar
todos sus métodos. Aquí hay un ejemplo
en el que creas clase
implementada
y la instancias. Aquí tenemos una interfaz llamada mi interfaz
con la impresión. Algo importante método es implementado por mi interfaz. Pero y si necesito una implementación ligeramente
diferente de las impresiones, algo
importante método. En este escenario,
tendría que crear otra clase que
implemente mi interfaz. Otra vez. Imagina que si tienes
diez varianzas diferentes, pronto
se volverá
abarrotada real. Esa es una señal para clases internas
anónimas. La clase interna anónima es
una extensión de una clase. Una implementación
de una interfaz sin nombre, de ahí anónima. Nos centraremos en la parte de
interfaz S. Esa es la importante
en el contexto de las corrientes. Como no tienen nombre, no
podemos crear por sí sola una instancia de la
clase interna anónima. En cambio, es necesario declarar e instanciar la clase interna
anónima en una sola expresión. Esta expresión
se ve de la siguiente manera, lo que se traduce
a lo siguiente. Al crear la versión anónima de clase
interna de mi interfaz info. Como puedes ver, hemos
creado una instancia de mi interfaz sin necesidad una clase implementando
la interfaz. Y si deseo agregar una nueva implementación de mi interfaz, simplemente
puedo hacerlo.
Ahí lo tenemos. Las clases internas anónimas se
pueden usar para implementar una interfaz sin
necesidad de definir una clase rígida. Simplemente puedes
crearlos sobre la marcha. Interfaces funcionales. La interfaz funcional es solo una interfaz excepto que solo contiene un único método que
debe implementarse. Cualquier interfaz que cumpla con ese criterio es una interfaz
funcional. Al igual que nuestro
ejemplo de mi interfaz hace un momento. Si bien no es necesario, puede agregar la
anotación de interfaz funcional para mostrar su intención. Como un bono adicional, el compilador lanzará una excepción en tiempo de compilación
cuando
en realidad no es una interfaz funcional al usar esta anotación. Repasemos por las interfaces funcionales más
comunes se utilizan cuando se trabaja con streams. Son primero uno es el
proveedor con admitido consigue. No espera ningún argumento, pero sí devuelve algo. El proveedor
le suministra algo, generalmente un objeto nuevo,
vacío, limpio. Se podía ver como una fábrica. El siguiente es
predicado. Con admitido. Espera un argumento, lo
evalúa y
devuelve un Booleano. Como su nombre lo indica, es básicamente una prueba. ¿El argumento t cumple con los criterios
dados sí o no? consumidor con sus
métodos acepta, acepta un argumento,
hace algo con él, pero no devuelve nada, literalmente consumiendo los
argumentos en el proceso. El consumidor de bicicletas hace
lo mismo que consumidor, salvo que espera dos argumentos. Función con sus métodos aplican. Espera un argumento, t
hace algo con él. Y las devoluciones en argumentos son básicamente mapear o enriquecer el argumento en el proceso, el argumento r y t
pueden ser la misma clase. La función by hace lo
mismo que la función. Exceptuados espera dos argumentos, T y U hacen
algo con ellos. Soy devoluciones son
igual que la función. Los argumentos pueden ser de la
misma clase si es necesario. Y en esa nota, llegamos a la última interfaz
funcional común. Operador binario. El operador binario es una extensión
de por función donde T, U y R son
exactamente la misma clase. Asegúrese de tener una comprensión
decente de las interfaces funcionales en general y fuera de estas
comunes antes de continuar. Ya que te ayudará a entender lambdas y
las operaciones de stream más fácilmente. Expresiones lambda. La mayoría de nosotros más agrupados son clases internas
anónimas de interfaces
funcionales de
las cuales el compilador Java
conoce implícitamente la información necesaria. Ahora sabemos lo que
es una clase interna
anónima y cómo todavía necesitamos implementar todos los métodos
de una interfaz. Observamos que las interfaces funcionales
son interfaces regulares, excepto que solo tienen un único método que
debe implementarse. Dado que una interfaz funcional
solo tiene un método único, el compilador es
capaz de entender mucha información
basada en el contexto. Tú, como desarrollador puedes
dejar fuera esa información. Entonces, deja saber al compilador
que estás dejando las cosas fuera. Los problemas de sintaxis Lambda. Comenzaremos con una clase interna
anónima irregular y convertiremos en una expresión
lambda completa pieza por pieza. O use el predicado de la
interfaz funcional para probar si un entero dado
es mayor que uno. Cuidando el signo igual, notamos el nombre de la
interfaz que estamos implementando. El cuerpo de la clase interna
anónima, la firma del método y el cuerpo de los métodos
que estamos implementando. Mire más de cerca el nombre
de la interfaz y la firma del método. ¿Ves cómo el compilador
podría inferir este conocimiento? Observe cómo los
nombres de la interfaz ya están en el lado izquierdo de
las declaraciones iguales. Observe cómo dado que
el predicado es una interfaz funcional, solo
hay un único
método a implementar. Entonces ya sabemos qué
métodos estamos implementando. Ambos tipos de información pueden ser
inferidos por el compilador. Nuestro primer paso es escribir esto usando la
sintaxis agrupada como, la flecha. Con él. Nos desharemos del nombre de la
interfaz, nombre del método. Esto ya se ve
mucho más limpio ¿verdad? Aquí vemos la entrada
de los métodos, el entero en el
lado izquierdo de la flecha, y el cuerpo del
método en el lado derecho. Pero aún queda
alguna información que podemos dejar fuera en este caso. Como hay un
solo método y el compilador conoce
la firma del mismo, el compilador puede inferir el tipo de
entrada del contexto. Los corchetes alrededor de las entradas también
han desaparecido. Esto sólo es posible
porque es un solo parámetro. En caso de que tengas dos o más, los corchetes son obligatorios. Hay una cosa más que ahora
podemos inferir. Tiene que ver con el cuerpo
y la declaración de retorno. En el caso de tener una sola línea de código en
el cuerpo del método, el compilador puede inferir
que esa línea de código es de hecho la
sentencia return del cuerpo. Con este paso final, hemos llegado a la expresión
lambda en toda regla. Verás todo el tiempo
cuando trabajas con cuerdas. En realidad, hay una manera de
escribir la lambda aún más corta. En algunos casos. A esto se le llama referencia de método. Pero sugiero que
lo busques tú mismo cuando
tengas una buena comprensión de lo
largo hace en general. Una última cosa importante a mencionar sobre nosotros agrupados es que las variables
locales utilizadas en ellas deben ser finales o
efectivamente finales. Efectivamente final
significa una variable que no tiene
la palabra clave final, pero su valor no cambia
después de su primera asignación. La razón de esto es que
agrupados somos básicamente una pieza de código que puedes
ejecutar dentro de otros métodos. Como puede
pasar nuestro predicado a una operación de filtro
dentro de una cadena. Por esta razón,
Java necesita crear una copia de la variable local
para ser utilizada dentro de los pulmones. Para evitar problemas de concurrencia. El alfa ha decidido
restringir por completo
las variables locales. Resumamos lo que hemos aprendido hasta ahora. Las clases internas anónimas
son clases internas que implementan una interfaz
sin tener un nombre, sí necesitan ser declaradas
e instanciadas que una vez. Las interfaces funcionales
son regularmente interfaces excepto que las únicas contienen un único método que
debe implementarse. La anotación de
interfaz funcional se
puede utilizar para hacer cumplir
esta regla no es necesaria. Nos agrupan son clases
internas anónimas de
interfaces funcionales de las cuales el compilador Java puede inferir información
faltante en
función del contexto. Ahora sabemos cómo crear una expresión lambda y de clase interna anónima
irregular. Y por último, las variables locales utilizadas en nosotros agrupados deben ser
definitivas o efectivamente bien.
4. Operaciones de transmisión: En los próximos capítulos, voy a explicar
las operaciones de uso común en cadenas. Pero primero, deberíamos hablar los dos tipos de operaciones
posibles, las operaciones intermedias y
terminales. Un flujo solo se
ejecuta completamente cuando se usa una
operación de terminal. Por lo tanto, una corriente
siempre termina en una operación terminal y solo puede tener una de
ellas en una corriente. Las operaciones intermedias son todas operaciones antes de llegar a la operación final de la
terminal. Las operaciones intermedias
devuelven una instancia de stream, lo que permite
encadenarlas todas juntas. Dado que todas
las operaciones intermedias devuelven flujo, puede almacenar una cadena sin operaciones de
terminal
en una variable. Gracias hoy, por lo que
realmente puedes agregar pasos a tu stream en función de influencias
externas, como un filtro diferente o una forma diferente de
enriquecer los datos. Sin embargo, preste atención,
aunque pueda almacenar
operaciones intermedias en variables, no
es posible ejecutar el mismo flujo dos veces con
una operación de terminal. El compilador no
reconoce esto, pero obtendrás una excepción
como esta durante el tiempo de ejecución. Una vez más. Las operaciones intermedias
devuelven un flujo y, por lo tanto, pueden vincularse
y almacenarse en variables. Las operaciones intermedias por sí solas
no ejecutan una transmisión. Una operación de terminal ejecuta el flujo completo y devuelve
un valor que no sea un flujo. Un flujo solo se puede ejecutar una vez con una operación de
terminal. Intentar hacerlo dos veces
resulta en una excepción
durante el tiempo de ejecución. Con este conocimiento,
pasaremos a
las operaciones de uso común.
5. Operación intermedia: filtro: Empecemos por lo básico. Filtro. El filtro es una
operación intermedia que permite filtrar objetos de cadenas que no
pasan la prueba dada. Se podría ver el filtro de operación
intermedia como el equivalente
de flujo de una sentencia if. entrada es un predicado que como aprendimos,
recibe un objeto, realiza una prueba sobre él, devuelve verdadero o falso dependiendo de si
pasó la prueba o no. He aquí un ejemplo de su uso. Y no te preocupes por
las otras operaciones. Pronto llegaremos a esos. En este ejemplo,
usamos filter para continuar la transmisión solo con objetos cuya lista de
números de teléfono está vacía. Antes de regresar a
los clientes restantes como una lista, filtrado se puede hacer usando
cualquier valor final efectivo. Aquí, estamos filtrando
en función de nuestra variable local, por ejemplo, también
podemos
encadenarlos usando múltiples
filtros seguidos. La operación del filtro es un excelente ejemplo de cómo las transmisiones hacen que su
código sea más legible. Especialmente si almacenaste
mucho tiempo en un valor así. Ahora puedes ver lo que estamos
filtrando de un vistazo.
6. Operación de terminales: para cada: Nuestra primera
operación terminal para cada uno. El FOREach es una operación terminal muy
sencilla. Se utiliza para realizar una determinada acción sobre todos los
elementos de la corriente. Asumiendo los elementos
en el proceso, sus insumos, es un consumidor. Entonces toma un objeto, hace algo con él, pero no devuelve ningún valor. Después. Hemos visto
su implementación en la operación previamente
discutida, pero aquí está una vez más. En este ejemplo, imprimimos el nombre de cada industria de
clientes. Ten en cuenta que para
cada uno solo operan sobre los elementos una vez que hayan pasado por el
resto de la corriente. Entonces, si ponemos un filtro antes de
la operación del terminal, así, entonces solo los clientes con menos de tres dispositivos obtienen su nombre de pila, imprímalo. Por último, ¿sabía que un método normal se puede
utilizar en un agrupado también? Toma este método, por ejemplo ¿
no te parece eso una implementación de
consumidor? Acepta un solo objeto, hace algo con él, pero no devuelve
ningún valor después. Y de hecho, podemos usar este
método en nuestro foreACH, haciéndolo más legible
en el proceso. Y eso es todo. Para cada uno simplemente realiza
una acción específica para cada elemento de la corriente que lo hace a través
del resto de la corriente.
7. Operación intermedia: mapa: Otra
operación intermedia básica, mapa. Map es una
operación intermedia que
se usa comúnmente para mapear de un tipo
de objeto a otro. Pero normalmente también se utiliza
para realizar lógica de negocios. Sus entradas es una función
que como ahora sabemos, toma un objeto de clase a, hace algo con él, y devuelve un objeto de clase b donde las cláusulas a y
B pueden ser la misma clase. Aquí hay un ejemplo donde
mapeamos de la clase A a la B. Aquí tenemos un
objeto cliente como entradas. Mapeamos eso a una
cadena compuesta
por su nombre y
apellido antes de imprimirla. En este caso, estamos mapeando
de la clase a a la clase B, del cliente a la cadena. En este siguiente ejemplo, tenemos un objeto cliente como entrada en el trabajo móvil
a sus dispositivos. Luego devuelve el mismo objeto
del cliente, enriqueciendo
efectivamente
tu propio objeto. En este caso, estamos
mapeando de cliente a cliente y llegando al
objeto en el camino. Tenga en cuenta que dado que el cuerpo de Lambda contiene
dos declaraciones, tuve que agregar los corchetes
y devolver la palabra clave de nuevo en. Finalmente, al igual que con cualquier operación
intermedia, es posible tener múltiples operaciones matemáticas
dentro de una misma corriente.
8. Operación intermedia: flatMap: A continuación, FlatMap. Como su nombre indica, FlatMap es similar a map. Se trata de una
operación intermedia que se
utiliza comúnmente para mapear de un tipo
de objeto a otro. Con la diferencia de que FlatMap trabaja en relaciones
uno a muchos. Su entrada también es una función, pero se
impone una restricción al objeto de retorno. Se debe devolver una corriente. Aquí vemos el método
firma de map y flatMap lado a lado para
mostrarte la diferencia. Mientras que ambos esperan la función, flatMap espera que el valor r
sea de tipo string. Echemos un vistazo a lo que hace y en qué se
diferencia de eso. En nuestros ejemplos, hemos
utilizado el objeto cliente, que tiene una lista de dispositivos. ¿Qué crees que
pasaría si usáramos operación
del mapa para
convertir a cada cliente
a sus dispositivos? Como puede ver en la salida, mapear de un cliente
a una lista de dispositivos, da como resultado un flujo
de listas de dispositivos. Cuando se imprimen, estas listas
se imprimen una por una. Esto podría ser algo que necesites para tu caso de uso funcional. Pero la mayoría de las veces, te interesan
todos los dispositivos separados en lugar de
listas separadas de dispositivos. Aquí es donde entra FlatMap. Como se dijo antes. Flatmap impone una restricción en el objeto
de retorno de la función. Se puede ver que la lambda
ha cambiado ligeramente para FlatMap y ahora devuelve
el dispositivo es un stream. En lugar de como lista. Observe en las salidas
que los dispositivos ahora se imprimen uno por uno
en lugar de lista por lista. La clave aquí es que
FlatMap espera arroyos como resultados que luego se aplanan en una
sola secuencia nuevamente. Una vez más juntos. Ahora puede
ver claramente la diferencia entre el mapa y la operación
FlatMap. Para resumir, los mapas
deben usarse al convertir objetos
con una relación uno a uno. Mientras que FlatMap
debe usarse al convertir objetos con
una relación de uno a muchos. Cuando se usa FlatMap, el valor de retorno es
un flujo de objetos.
9. Operaciones intermedias: secuenciales y paralelas: Dos operaciones de una misma
moneda, secuencial y paralela. Secuenciales y paralelas son
ambas operaciones intermedias que hacen que el flujo completo secuencial o paralelo
respectivamente. Dado que son operaciones
intermedias, se
pueden agregar a la transmisión juntas incluso varias veces. No importa en qué parte del arroyo se coloque la
operación. Toda la corriente es
secuencial o paralela. Ni un poco de ambos. tener en cuenta que la última operación secuencial
o paralela mencionó
la industria, la que realmente se utiliza. Eso quiere decir que esta corriente es exactamente la
misma que esta corriente. Un flujo es secuencial
por defecto, lo que significa que los elementos
se ejecutan en el orden en que aparecen
en la colección estadounidense. Eso también significa que
estas corrientes tienen la misma salida. Como se puede ver. Esto da como resultado la impresión
de uno a diez en orden con o sin la operación
secuencial. Cuando cambiamos eso a paralelo, sin embargo, como puedes ver, obtenemos un resultado diferente
cada vez que ejecutamos el Stream. Stream se ejecuta
multi-hilo, lo que significa que el trabajo realizado se divide entre
diferentes ejecutes. Las llamadas amenazas. Tenga en cuenta que hacer que
una transmisión se ejecute en paralelo no
significa automáticamente que la transmisión se
pueda ejecutar a prueba de subprocesos. Tú, como desarrollador, tienes que asegurarte de que tu
código funcione exactamente igual, 1236 o cualquier amenaza. Como no quiere. Otra cosa a tener en
cuenta al ejecutar las cosas en paralelo es que no necesariamente significa que el
trabajo se haga más rápido. Hacer algo
multi-hilo significa que necesita dividir
el trabajo en partes, crear un ejecutado
para cada parte. Trabajo delegado, emergen los
diferentes resultados en uno solo. Esto da como resultado
algo de sobrecarga al ejecutar el código o
stream, en nuestro caso, lo que solo será beneficioso si tienes suficientes elementos en tu stream o si tu stream
es muy pesado de cómputo. Para resumir, las operaciones secuenciales
y paralelas permiten hacer rápidamente todo
el flujo
secuencial o paralelo. ejecutar una transmisión paralela, usted, como desarrollador, tiene que
asegurarse de que el código
sea seguro para subprocesos.
10. Operación intermedia: peek: Vamos con uno
simple antes de pasar a los complejos. Pq. Pq es una operación
intermedia que literalmente
te permite echar un vistazo detrás de escena al
ejecutar una cadena. Su uso principal es la depuración
y el registro de sus entradas. Como consumidor, es
decir, recibe un valor y hace algo con él sin
que haya un valor de retorno. Si bien es posible modificar los datos dentro de la operación pico, se arriesga al hacerlo. Dependiendo de su
versión de Java y si
su operación de terminal tiene
o no su operación de terminal tiene necesidad de procesar los
objetos en la cadena. El código dentro de peek
puede o no ejecutarse. Tenga mucho cuidado
al usar peak para cualquier cosa que no sea la
depuración y el registro. He aquí un ejemplo de su uso. En este ejemplo, usamos
peak para imprimir el nombre de
un dispositivo antes de continuar mapeándolo a los detalles de su pedido, recopilando esos posibles procesamientos
adicionales. Un resultado de esta transmisión
es una lista de detalles del pedido. Gracias a la operación pico, podemos obtener algunos registros con un dispositivo que los objetos utilizan
para los resultados. Y vi pico es simplemente una manera de conseguir algo de
tala durante un arroyo. Puedes usarlo para modificar
datos, pero es arriesgado, así que te desaconsejaría cuando aún no estés
familiarizado con las transmisiones.
11. Operación de terminales: recolecta: Nuestra segunda
operación terminal, recoger. Collect es una
operación terminal que recoge todos los elementos de
una corriente en algo. Se usa comúnmente para poner los elementos resultantes de
una transmisión en una lista. Hay dos implementaciones
para esta. El primero espera
una implementación de la interfaz del
colector. Sin embargo, esta no es una
interfaz funcional
y, por lo tanto, no se puede reescribir
como una expresión lambda. Por suerte para nosotros, sí, Lava ha sido tan
amable como para proporcionar a los colectores
clústeres que contienen todo tipo de métodos útiles. Muchos están más allá del
alcance de este taller. Pero hay uno
que
usarás frecuentemente coleccionistas puntean dos listas. Como cabría esperar. Esto devuelve una implementación de la interfaz recopiladora que recoge todos los elementos de la cadena en una
lista y la devuelve. Yo personalmente uso este 190, 9% de las veces que
necesito para recoger algo y espero
que experimentes lo mismo. Pero para entender un poco mejor
lo que hace, repasemos la
segunda implementación. Este espera un proveedor
y dos por consumidores. El doc de Java nos da una buena
visión general de lo que hace. El proveedor
nos suministra eso, lo que esperamos como resultado
de la operación de recolección. Que el primer
consumidor de bicicletas se utiliza para consumir un elemento de la
corriente en estos resultados. Esto continúa hasta que
todos los elementos de la corriente o consumidos
en los resultados finales. Esto no nos muestra lo que hace
el segundo consumidor bi en
combinarlo, sin embargo, eso es
porque el combinador solo
es necesario cuando el
stream se ejecuta en paralelo. En ese caso, es posible que tengas dos o más hilos
comenzando con el proveedor. Después de que se hayan hecho todas las amenazas, resultados de esos
hilos deben
combinarse en un solo resultado, que es exactamente para lo que se utiliza un
combinador. Pongámoslo en práctica. Usando un proveedor y
dos por consumidores. Replicaré
la recolección de los elementos del cliente
en una transmisión. Empezaremos con el proveedor. Cuando las llamadas obtendrán la lista vacía donde pondremos todos los elementos de la corriente en. A continuación, necesitamos un consumidor de
bicicletas que acumule todos los elementos de la cadena en la lista de suministros. Esto deja claro que nuestro resultado es efectivamente
esa lista y que todos los elementos del cliente de la transmisión se acumulan
en la lista de conjuntos. En caso de una corriente secuencial, ese será el final de la misma. Pero para permitir el procesamiento
paralelo, se necesitará una final por consumidor que combine dos
resultados en uno solo. Usando esto por consumidor, agregamos los elementos
del segundo resultado
al primero. Esto es repetido por
la transmisión hasta que todos los resultados de las amenazas se
fusionan de nuevo en uno. Aquí se llenan en
la operación de recolección. Y con eso, ya sabes cómo personalizar
tus propias colectas. Para reiterar, hay dos implementaciones de
la cooperación colecta. El primero espera
un recopilador del cual Java ha preparado algunas opciones para ti usando la cláusula
colectores. El segundo espera un
proveedor y que vincula a los consumidores, haciéndolo mucho
más personalizable. Utilizarás la colección preparada de esta clase la
mayor parte del tiempo. Pero al menos ahora
ya sabes cómo funciona.
12. Operación de terminales: reduce: El operador final
discutirá reducir. Reducir es una
operación de terminal que se puede utilizar para reducir todos los elementos de un
flujo en un solo objeto. Es un poco como cobrar
operación que discutimos. Pero mientras que collect
aplica todos los elementos de la corriente al
contenedor inmutable como una lista o conjunto. Reduce no
recopila sino que aplica todos los elementos a un solo
objeto. La identidad. Reducir, toma su identidad, acumula o elementos
en la identidad, luego combina múltiples resultados juntos en uno en
caso de que se ejecute en paralelo. Reducir es la
operación más difícil de comprender. Así que no te sientas mal si
no lo consigues todo a la vez. Solo tómate tu tiempo para
seguir esta sección y probar los ejercicios
al final de la clase. Si te queda alguna duda, no dudes en preguntarlas
usando la plataforma. Bien, vamos a sumergirnos. Deep reduce espera
un valor inicial llamado la
función de identidad que se usa como acumulación y
un operador binario utilizado para combinar resultados
de subprocesos separados. El perro alfa nos da una buena
visión general de lo que hace. Esta identidad nos da
el inicio de los resultados. Debe ser pizarra limpia, vacía, tal que agregar cualquier
valor del arroyo a esta identidad tenga ese resultado
y alterado como producto. Entonces, por cada elemento
de la corriente, se acumula en el valor resultante
usando la función by. Al igual que con para recopilar, esto no nos muestra lo que hace
el operador binario,
el combinador. Lo mismo se aplica aquí. El combinador solo se usa
para combinar los resultados de múltiples hilos juntos en caso de que el flujo se ejecute en paralelo. Pongámoslo en práctica. Para nuestro ejemplo,
elegiremos a todos los
clientes en un número entero que represente la cantidad total de dispositivos que pertenecen
a esos clientes juntos. Nuestra identidad debe
ser un entero. Como resultado, queremos
salir de esta corriente. En cuanto al valor. Recuerda cómo agregar
cualquier resultado a la identidad debería tener que
resultar en alterado como producto. En nuestro caso, tendremos que
sumar el tamaño de toda la lista de dispositivos juntos para llegar a
nuestros resultados finales. Qué valor de la
identidad significa que identidad más el tamaño de la lista de
dispositivos es igual a dos. El dispositivo esto,
Así es, cero. Entonces nuestra identidad
será así. A continuación, necesitamos una función que produzca un elemento de la
corriente en esta identidad. Los primeros genéricos utilizados
en la función by son un entero que representa el valor actual
de los resultados. El subtotal, si se quiere. El segundo uso de genéricos es
el elemento del arroyo, que se reducirá
al subtotal. El tercer
uso de genéricos es el tipo
del resultado de la
operación un entero. Este tercer genérico debe ser
el mismo que el primero, lo cual es lógico ya el primer término genérico
representa el subtotal. En caso de una corriente secuencial, ese sería el final de la misma. Pero para permitir el procesamiento
paralelo, necesitará operador binario para combinar dos resultados en uno. Usando este operador binario, combinamos los resultados
de dos hilos juntos. Esto es repetido por
la corriente hasta que todos los resultados de los hilos se
fusionan de nuevo en uno. Aquí se llenan en
la operación de reducción. Para reiterar,
comenzamos con una pizarra limpia y
vacía como identidad
cero. En nuestro caso. Luego agregamos el tamaño
de la lista de dispositivos de cada elemento desde el
stream a esta identidad. Si el stream se ejecuta en paralelo, usamos para combinarlos
para sumar dos subtotales en uno hasta que nos quede
un solo resultado. En nuestro ejemplo, reducimos nuestros objetos complejos
en un solo entero. Pero reducido también
se puede usar para reducir todos los elementos de una corriente en
un solo objeto complejo. Por ejemplo, podríamos reducir a
nuestros clientes en un solo
cliente que contenga nuestra información. Pero dejaré
esa como parte de los ejercicios que
puedes hacer por tu cuenta.
13. Resumen y palabra Afterword: Hemos llegado al
final de esta clase. Vamos a resumir para ver
lo que hemos aprendido en nuestro viaje hacia la API de ocho flujos de
Java. Empezamos
aprendiendo para qué
se utilizan las transmisiones y cómo funcionan. Luego desglosamos cómo se puede crear una
expresión lambda a partir de una clase interna anónima gracias
a las interfaces funcionales. Discutimos brevemente, pero las interfaces
funcionales son, y cuáles
usa comúnmente cuando se trabaja con transmisiones. Finalmente, repasamos operaciones intermedias
y terminales de
uso común. Gracias por
ver esta clase. Espero que hayas aprendido lo suficiente
sobre las transmisiones para reconocer situaciones en las que puedes
y eres capaz de utilizarlas. Si deseas ayudarme a
mejorar esta clase y dinos si la
encontraste o no útil. Le agradecería que
dejara una reseña. Según lo prometido. He preparado algunos
ejercicios para que los revises para que veas si puedes aplicar los conocimientos aprendidos
durante este curso. Cada ejercicio tiene una solicitud, un resultado esperado
para que verifiques si lo hiciste bien. Si hay algo
poco claro sobre esta clase ya
brindó ejercicios, no dude en enviarme un
mensaje con sus preguntas. Te ayudaré lo
mejor que pueda. Una vez más. Gracias por ver
y hasta la próxima vez.