0% encontró este documento útil (0 votos)
34 vistas52 páginas

Marco de Colecciones en Java

El capítulo aborda el marco de colecciones de Java, que utiliza herencia e interfaces para manejar colecciones de objetos de manera eficiente. Se describen las interfaces principales como Collection y Map, así como sus implementaciones concretas y la introducción de genéricos para mejorar la seguridad de tipo en las colecciones. Además, se discuten las diferencias entre estructuras de datos como ArrayList y LinkedList, y su uso en la programación orientada a objetos.

Cargado por

digranada8
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
34 vistas52 páginas

Marco de Colecciones en Java

El capítulo aborda el marco de colecciones de Java, que utiliza herencia e interfaces para manejar colecciones de objetos de manera eficiente. Se describen las interfaces principales como Collection y Map, así como sus implementaciones concretas y la introducción de genéricos para mejorar la seguridad de tipo en las colecciones. Además, se discuten las diferencias entre estructuras de datos como ArrayList y LinkedList, y su uso en la programación orientada a objetos.

Cargado por

digranada8
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd

12

El marco de colecciones y los genéricos

En este capítulo, veremos algunas clases del marco de colecciones de Java que se pueden usar para contener
colecciones de otros objetos. Este marco hace un uso extensivo de la herencia y las interfaces para proporcionar
reutilización y consistencia. al otro lado de muchos diferente tipos de recopilación. El componentes de el El marco
incluye estructuras de datos conocidas, como matrices, listas, mapas y colas, así como operaciones algorítmicas
relacionadas, como búsqueda y ordenación. El marco de colecciones comienza de el idea eso cada tipo de recipiente
es cualquiera a Recopilación o un mapa. Tanto Collection como Map son interfaces que proporcionan un conjunto
común de firmas de métodos que todas las clases implementadoras deberían admitir. Una colección es algo eso
contiene elementos, mientras a Mapa define a mapeo entre Llaves y objetos.

12.1 Objetos eso Contener Objetos

Una colección es un objeto que existe únicamente para contener una colección dinámica o no modificable de otros
objetos. A diferencia de una relación de composición, los objetos de una colección dinámica no son fijos; se pueden
agregar y eliminar a voluntad. En capítulos anteriores, hemos utilizado matrices como estructuras de datos simples
que pueden contener objetos, pero las matrices no brindan servicios más allá del acceso indexado y no se pueden
redimensionar dinámicamente. El marco de Colecciones proporciona un enfoque orientado a objetos más sólido y
poderoso para implementar colecciones de objetos. La API de Colecciones es un marco unificado para representar y
manipular colecciones, independientemente de su implementación. Diferentes estructuras de datos subyacentes
pueden variar en las formas en que contienen e indexan los objetos que implementan. coherente interfaces, que
comprende a estándar colocar de métodos para acceder y mantener colecciones. Por ejemplo, todas las clases de
colección tienen un método “ add ” para agregar nuevos elementos. Además de tener varios métodos públicos,
colecciones son también iterable ; ellos poder devolver un “ Iterador ” objeto eso

© Saltador Naturaleza Suiza Estado 2020


299
D. Parsons, Foundational Java , Textos en Ciencias de la Computación,
[Link]
300 12 The Collections Framework and
Generics
Los iteradores pueden explorar el contenido de una colección de a un objeto por vez. Los iteradores proporcionan un
mecanismo simple para examinar cualquier tipo de colección, independientemente de si esa colección en particular
proporciona métodos para hacerlo directamente o no. La clase Deque (que se pronuncia " deck " y es la abreviatura
de " double ended queue " ), por ejemplo, no permite acceder directamente a todos sus elementos porque es una
estructura de datos que normalmente permite acceso solo a el objetos en cualquiera fin de el cola. Por Sin embargo, al
utilizar un iterador, podemos ver el contenido de un Deque sin tener que agregar métodos a su interfaz pública que
normalmente no serían apropiados para objetos de cola.
De curso, no todo datos estructuras son el mismo, cualquiera conceptualmente ([Link] a Una cola, un conjunto y una
lista tienen semánticas diferentes) o en sus implementaciones (por ejemplo, no todas las colecciones están indexadas).
Por lo tanto, además del conjunto genérico de métodos, cada clase de colección tiene sus propias características
únicas.

12.1.1 Asociaciones y Colecciones

Las colecciones tienen un papel importante en la implementación de asociaciones entre objetos. Las relaciones “ uno
a muchos ” o “ muchos a muchos ” se implementan mejor con colecciones (en lugar de matrices). Por ejemplo, el
diagrama de clases UML de la figura 12.1 muestra cuatro clases de a bancario dominio. Un cuenta poder tener
muchos Transacciones Una cuenta (conjunta) puede tener muchos clientes, un cliente puede tener muchas cuentas.
Todas estas relaciones “ muchas ” deben implementarse para que un objeto pueda mantener relaciones con muchos
objetos de otra clase y, en la mayoría de los casos, una colección. o a mapa quería ser el mayoría adecuado forma de
haciendo este. Para Por ejemplo, una cuenta bancaria podría mantener una colección de objetos de transacción
registrados en ella, mientras que un banco podría tener un mapa de cuentas bancarias, utilizando los números de
cuenta como claves. Por supuesto, en un ejemplo de dominio empresarial como este, las relaciones subyacentes a
largo plazo entre estos objetos se representarían en un almacén de datos, pero para la programación procesos como
generando informes, declaraciones, etc., estos Las relaciones tienen a ser modelado en tiempo de ejecución objetos,
cual es dónde clases de el Los marcos de cobro son importantes.

* Bank

* *
Customer * * BankAccount * Transaction

Higo. 12.1 Asociaciones en a bancario dominio eso debería ser implementado con colecciones
12.2 The Core Collection 301
Interfaces
12.2 El Centro Recopilación Interfaces

El marco de Colecciones se basa en un conjunto de interfaces que proporcionan un enfoque coherente para las clases
que implementan sus métodos. Figura 12.2 muestra las interfaces principales en el marco de Colecciones. Un aspecto
de la notación UML que se utiliza aquí es la palabra clave estereotipada “ interfaz ” . Las palabras clave
estereotipadas se encierran entre “ guille-mets ”. (pronunciado “ vaya, vaya ” ) cual mirar como de doble punta
soportes. Usando Esta notación deja claro que se trata de interfaces, no de clases.
La interfaz Iterable, que extienden todas las demás interfaces de colección, representa un grupo de objetos sobre
los que se puede iterar. La interfaz declara el método “ iterador ” , cual devoluciones un Iterador objeto eso poder
acceso cada elemento de a colección a su vez. También permite el uso de un bucle “ for ” especial , que
proporciona una forma más encapsulada de usar un iterador.
La interfaz “ Colección ” es la interfaz raíz de la jerarquía de la Colección en términos de el recopilación objetos
ellos mismos. Representa una grupo de objetos eso se pueden agregar a. Además de que las clases pueden
implementar múltiples interfaces, las interfaces ellos mismos poder extender otro interfaces. Interfaces semejante
como Cola, Colocar y lista más extender el Recopilación interfaz. A Cola poder representar ambos Primero en
entrar (FIFO)

Allows an object «interface»


to be the target of Iterable Maps keys to values
a ‘foreach’ state- No duplicate keys
ment

Represents a
"interfaz" «interface»
"interfaz" 2 «interface»
"interfaz"
Cola
group of objects Collection
Colocar Lista Map

(elements)

Represents FIFO An ordered collection


(first-in-first-out) No duplicate
Allows duplicate el-
queues or LIFO (last- elements
ements
in-first-out) stacks

Higo. 12.2 El centro interfaces en Las colecciones estructura


302 12 The Collections Framework and
Generics
(primero en entrar, primero en salir) colas y LIFO (último en entrar, primero en salir) pilas, dependiente en cómo él
Se utiliza una lista simplemente es una secuencia ordenada de elementos, mientras que un conjunto también es una
secuencia de elementos pero que no contiene ningún duplicado.
Otra interfaz central del marco es el Mapa, que representa objetos que asignan claves a valores. En un mapa, cada
clave debe ser única y asignarse a un valor como máximo. A pesar de a Mapa es no a subtipo de Recopilación, él se
relaciona cercanamente a el descansar del estructura, porque el llaves y valores en a mapa son ellos mismos
colecciones (Un mapa es una composición de dos colecciones). En la sección 12.2 no se muestran SortedSet (que
extiende Set) ni SortedMap (que extiende Map).
Nota
Todas las interfaces y clases del marco de Colecciones están en el paquete [Link], con la excepción de la interfaz
Iterable, que está en [Link].

12.2.1 Parcial Implementaciones de el Centro Interfaces

Las interfaces principales en la figura 12.2 se implementan parcialmente en un grupo de clases abstractas (Fig. 12.3 ).
Esto hace que las interfaces principales sean más fáciles de implementar. Las clases concretas en el marco de
Colecciones heredan de estas clases abstractas.

Object

AbstractCollection AbstractMap
Conjunto abstracto Lista abstracta Cola abstracta

Lista secuencial abstracta

Higo. 12.3 Abstracto clases en el Colecciones estructura


12.2 The Core Collection 303
Interfaces
12.2.2 Concreto Implementaciones de el Centro Interfaces

Tabla 12.1 muestra las principales clases de propósito general que implementan las interfaces principales. Su nombres
son basado en combinatorio el implementación de el datos estructura (primera) con la interfaz que se está
implementando (segunda), donde las interfaces son Set, List, Deque y Map, y las implementaciones son HashTable,
Array, Tree, LinkedList y HashTable + LinkedList. Por ejemplo, TreeSet es una implementación de árbol balanceado
de la interfaz Set, y ArrayList es una implementación de matriz redimensionable. de el Lista Interfaz. Nota que el
Lista enlazada implementos de clase ambos Las interfaces List y Deque. Hay otras clases en el marco, pero son más
especializadas.
En ejemplos anteriores, hemos utilizado matrices para almacenar colecciones de objetos. El tipo de colección más
cercano a una matriz es una ArrayList. En algunos aspectos, una ArrayList es muy similar a una matriz, en el sentido
de que contiene un ordenado colección de objetos a los que se puede acceder mediante un índice basado en cero. Sin
embargo, una ArrayList es mucho más poderosa que una matriz. Una ArrayList se redimensionará dinámicamente si
ya está llena cuando un intentar es hecho a agregar un objeto a él. Un formación, en contraste, voluntad simplemente
lanza una excepción ArrayIndexOutOfBounds. La clase ArrayList también encapsula muchos métodos y
características útiles que no están disponibles con matrices simples. cual tener No métodos y solo a soltero " longitud
" campo. El otro Las clases de colección proporcionan a rango de datos estructuras eso poder abastecer para mayoría
solicitud necesidades. Nosotros podría aún usar matrices ocasionalmente, generalmente para Razones de eficiencia,
pero en En la mayoría de los casos, deberíamos utilizar colecciones en lugar de matrices.

12.2.3 Legado Clases

Las clases Vector, HashTable y Stack estaban originalmente en JDK 1.0. Han sido reemplazado por el Lista de
matrices, Mapa hash y Matriz Deque clases respectivamente, pero se han incluido retrospectivamente en el marco de
Colecciones al ser modernizados con métodos que son consistentes con el marco, aunque para versiones anteriores
compatibilidad su viejo métodos permanecer. Su continuado existencia es en parte Para apoyar legado aplicaciones
pero también porque ellos son aún requerido en Java A MÍ

Mesa 12.1 General objetivo clases en el Colecciones estructura, con nombres basado en Una combinación de
interfaz e implementación

Interfaces Implementaciones
Tabla hash Matriz Árbol equilibrado Lista enlazada Tabla hash + Lista enlazada
redimensiona
ble
Colocar Conjunto de Conjunto de Conjunto de hash vinculado
hash árboles
Lista Lista de matrices Lista enlazada
Deque Matriz Deque Lista enlazada
Mapa Mapa hash Mapa de árboles Mapa de hash vinculado
304 12 The Collections Framework and
Generics
(Micro Edición) programación dónde allá es No colecciones marco. A diferencia de Las clases del marco de colección
más nuevas están sincronizadas (son de un solo subproceso).

12.3 Tipo seguro Colecciones con Genéricos

En las primeras versiones del marco de Colecciones, las clases de colección solo podían contener Objeto referencias.
Este quiso decir eso colecciones eran no tipo seguro. Constructores de colecciones eran no capaz a especificar el tipos
de objetos eso ellos eran destinado para contener. Aquí hay una llamada al constructor que crea una LinkedList sin
tipo:

Lista enlazada lista = nuevo Lista enlazada();

A esta lista enlazada se le puede agregar cualquier tipo de objeto sin ningún tipo de verificación de tipo. Aquí
agregamos una cadena:

[Link]("A Cadena");

Para recuperar un objeto de una colección sin tipo, es necesario convertirlo a su tipo apropiado. Por ejemplo, si
quisiéramos eliminar el primer objeto String de la lista (usando el comando “ getFirst ”) método, que es específico
para colecciones LinkedList), sería necesario convertirlo de Objeto a Cadena.

Cadena s = (Cadena)[Link]();

Conocimiento eso el recopilación contiene Instrumentos de cuerda es algo eso, como a Si es un programador,
tendría que inferir de otras partes del código. El compilador no puede ofrecer ninguna ayuda y, sin la comprobación
de tipos en tiempo de compilación, existe la posibilidad de que el tiempo de ejecución sea incorrecto. Excepciones de
ClassCast ser arrojado si nosotros intentar a elenco a el equivocado tipo. Para superar este problema, Java ha incluido
genéricos en el marco de Colecciones desde Java 5, lo que hace que las colecciones sean seguras en cuanto a tipos.
Las clases admiten genéricos cuando permiten que se incluya una variable de tipo en sus declaraciones. Este tipo de
variable se utiliza para especificar el tipo de objeto que almacenarán las colecciones. El tipo almacenado en la
colección se declara dentro de corchetes angulares después del tipo de colección cuando se declara una referencia.
Esto también se aplica a la llamada al constructor. Por ejemplo, para declarar una referencia genérica para una
ArrayList de números enteros, incluiríamos el tipo que se almacenará en la colección después de la referencia de la
colección.

ListaEnlazada<Entero> lista = nulo;

El constructor llamar también incluye el tipo a ser almacenado, entre el nombre del constructor y los paréntesis:

lista = nuevo ListaEnlazada<Entero>();


12.3 Tipo seguro Colecciones con Genéricos 305

Nota
No se puede escribir una colección utilizando un tipo primitivo. Solo se pueden almacenar tipos de referencia. Los
valores de los tipos primitivos se deben colocar en objetos de una clase contenedora adecuada antes de que se
puedan agregar a una colección.
Una lista de tipos seguros elimina la necesidad de conversión. Si usamos genéricos de modo que la colección esté
tipificada para contener, por ejemplo Por ejemplo , objetos String, entonces el compilador puede inferir que “ getFirst ” El
método devuelve una cadena, no un objeto y no se requiere conversión.

Lista enlazada<Cadena> lista de cadenas = nuevo LinkedList<String>(); [Link]("Una


cadena");
Cadena s2 = [Link]();

Si observa el Javadoc del método “ getFirst ” , verá que la firma se declara de la siguiente manera:

público mi obtenerPrimero()

El “ Mi ” representa el elemento tipo eso el Lista enlazada contiene (dónde Los genéricos se utilizan para clases
fuera del marco de colecciones (la convención normal es utilizar “ T ” para representar el tipo en Javadoc).
A pesar de el colecciones estructura aún permite sin tipificar colecciones a ser creado, este es para hacia atrás
compatibilidad y es no recomendado para nuevo código. El El compilador lo hará dar tú a advertencia si tú intentar a
crear recopilación objetos sin usando genéricos.

12.4 A Concreto Recopilación Clase: El Lista de matrices

Las ArrayLists son colecciones extensibles de objetos arbitrarios que le permiten agregar, acceder, buscar y eliminar
elementos. Un Lista de Array capacidad crece de forma incremental. Debido a que se construyen utilizando
diferentes implementaciones subyacentes, las ArrayLists y LinkedLists tienen algunos métodos diferentes. Por
ejemplo, con una LinkedList podemos eliminar el primero o último objetos en el recopilación, mientras con un Lista
de matrices tú Sólo se pueden eliminar elementos utilizando su índice en la colección. Además de pequeñas
diferencias en cómo el dos tipos de lista poder ser usado, a Lista enlazada poder trabajar levemente de forma más
eficiente si cambia el contenido de la colección con frecuencia.
Si se crea una ArrayList utilizando el constructor de cero argumentos, la capacidad inicial predeterminada es 10.

Lista de matrices<Cadena> Nombres de los meses = nuevo Lista de Arrays<Cadena>();

Sin embargo, establecer la capacidad inicial utilizando un constructor parametrizado puede mejorar la eficiencia
si evita cambios de tamaño innecesarios en la colección:

Lista de matrices<Cadena> Nombres de los meses = nuevo Lista de matrices<Cadena>(12);


306 12 The Collections Framework and
Generics
12.4.1 Añadiendo y Recuperando Objetos

Uno de los métodos de la interfaz Collection es “ add ” , lo que significa que todas las colecciones (incluidas las
ArrayList) tendrán un método “ add ” disponible. Aquí, creamos una ArrayList de cadenas y le agregamos algunas
cadenas:

Lista de matrices<Cadena> Nombres de los meses = nuevo ArrayList<String>();


[Link]("Enero");
[Link]("Febrero");

Para recuperar un objeto de una colección, no hay común " conseguir " método en la interfaz Collection. Esto se
debe a que los diferentes tipos de colección tienen diferentes formas de permitir el acceso a los elementos, según sus
estructuras de datos subyacentes. Dado que ArrayList representa una colección ordenada, implementa la interfaz “
List ” . Esta interfaz admite un método “ get ” que puede tomar un parámetro entero. a acto como un índice en el
recopilación. Estos índices son basado en cero, muchísimo como el índices usado con a básico Java formación.
Acceso a Listas de matrices, Sin embargo, solo a través de sus métodos; no se puede acceder a ellos utilizando la
sintaxis de corchetes utilizada con las matrices.
Este línea de código usos el " conseguir " método con un formación índice de cero, entonces para nuestro
ejemplo Lista de matrices él quería imprimir afuera " Enero " :

[Link]([Link](0));

Contrasta este “ obtener ” método con, por ejemplo, los métodos de la clase PriorityQueue, que implementa la
interfaz Queue y no tiene “ get ” métodos, proporcionando en cambio a “ echar un vistazo ” (o " eliminar " ) método
a acceso el objeto en el cabeza de el cola. La siguiente código fragmento demuestra alguno de el otro métodos
de la clase ArrayList. Al igual que las otras clases del marco, algunos métodos son comunes a todo colecciones
(semejante como el " eliminar " método eso acepta un objeto como un parámetro) pero otros son específicos de
las implementaciones de la interfaz List, como el " agregar " , " conseguir " y " eliminar " métodos eso son capaz a
usar índice valores (solo Lista
tipos apoyo indexado acceso a elementos).

[Link]([Link]("Marzo")); // falso
[Link]([Link]("Febrero")); // 1
[Link]([Link](0)); // "Enero"

A diferencia de una matriz, una ArrayList cambiará de tamaño dinámicamente a medida que agregue elementos, y
poder también insertar elementos en a especificado índice. Sin embargo, tú necesidad a asegurar Ese elemento
inserción es hecho en a válido posición. Tú no puedo insertar un elemento usando un valor de índice que está más allá
de los límites actuales de ArrayList. En el siguiente ejemplo, el comentarios mostrar qué quería ser en el Lista de
matrices después cada operación, utilizando el formato estándar “ toString ” de un objeto ArrayList.
12.4 A Concrete Collection Class: The 307
ArrayList
[Link]("Abril"); // ["Enero", "Febrero", "abril"] [Link](2, "marzo");
// ["enero", "febrero", "marzo", "abril"] [Link](0); // ["Febrero",
"Marzo", "abril"] [Link]("marzo"); // ["febrero", "abril"]

12.4.2 Envase y Boxeo automático

Solo se pueden agregar objetos (es decir, cualquier cosa que descienda de la clase Object) a las colecciones. Para
agregar valores de tipos primitivos a una colección, deben estar envueltos en el adecuado envoltura objeto ([Link]
Entero, Doble, etc.) antes ser agregado a la colección, por ejemplo, utilizando [Link] para encapsular un int:

Lista de matrices<entero> MesDías = nuevo ArrayList<Integer>();


[Link]([Link](31);

Sin embargo, “ boxeo automático ” (y desempaquetado) medio nosotros hacer no necesidad a explícitamente
referirse a el envoltura clases. Primitivos poder ser agregado directamente a a recopilación (el El contenedor todavía
se usa pero es implícito).

Lista de matrices<entero> MesDías = nuevo ArrayList<Entero>();


// caja automática
[Link](28);
// No fundición a pareo envoltura requerido en recuperación int
eneroNumber = [Link](0);

El autoboxing hace que parezca que las colecciones pueden contener primitivos, pero es importante entender que
siempre están envueltos en objetos, incluso si eso no tiene que hacerse manualmente en nuestro propio código. La
colección siempre tendrá su tipo declarado usando la clase contenedora apropiada.

12.4.3 Iteradores

Iteradores proporcionar un fácil forma a secuencia a través de el objetos en cualquier recopilación. Todas las
colecciones tener un “ iterador ” fábrica método a devolver un implementación de Iterador capaz de trabajar con ese
tipo de colección. Es un método de fábrica porque la colección sabe qué tipo de iterador implementación a devolver a
a nosotros. Nosotros hacer no Necesitar saber acerca de el concreto clase ser usado, solo el métodos de el interfaz. La
interfaz Iterator solo tiene dos métodos garantizados:

booleano tieneSiguiente()
// Devoluciones verdadero si el iteración tiene más elementos. E
siguiente()
// Devoluciones el próximo elemento en el iteración
308 12 The Collections Framework and
Generics
Nosotros poder usar a " mientras " bucle a iterar encima el recopilación y devolver cada objeto A su vez, se
utilizan estos dos métodos. También existe la opción " eliminar ". Método que elimina el último elemento devuelto
por el iterador de la colección. Sin embargo, esta es una operación opcional, por lo que no todos los tipos de
iteradores la admiten. Si bien el marco intenta proporcionar operaciones encapsuladas consistentes para diferentes
tipos de colecciones, no todas las implementaciones pueden admitir todas las operaciones. En tales casos, los métodos
se consideran opcionales. Un método de colección puede generar una excepción [Link].
UnsupportedOperationException. si un sin soporte opcional operación es llamado. El “ eliminar ” método es uno eso
lanza este excepción (él es un desenfrenado excepción, por lo que el compilador no requiere que se capture).
Cuando usamos el “ iterador ” método, necesitamos usar genéricos para especificar el tipo de objeto que
devuelve el iterador, por ejemplo,

Iterador<Cadena> iter = [Link]();

Si el iterador es mecanografiado, entonces cuando nosotros devolver el " próximo " objeto de el iterador, No será
necesario fundirlo.

mientras([Link]())
{
Cadena nombre del mes = [Link](); [Link](nombreMes);
}

Una vez que un iterador ha llegado al último elemento de una colección, no se puede restablecer. iterar encima el
recopilación de nuevo, a nuevo iterador objeto debe ser recuperado de La colección.

[Link] Iterador de lista


Cualquier clase que implemente la interfaz List también puede devolver un ListIterator, utilizando el método de
fábrica “ listIterator ” . Un ListIterator aprovecha la función subyacente implementación de Lista colecciones a
proporcionar a pocos métodos en Además de el básico métodos en el Iterador interfaz. Entre otro cosas, nosotros
poder atravesar una lista en ambas direcciones, ya que ListIterator tiene un método “ anterior ” y un método “
siguiente ” . También hay métodos para devolver el valor del índice del elemento siguiente o anterior que devolverá
el iterador.

[Link] Mejorado "para" Bucle


Como un alternativa a directamente usando un Iterador objeto, Java proporciona un mejorado bucle “ for ” que hace
iteración a través de a recopilación más fácil, si La única cosa tú quiero hacer itera sobre la colección (en lugar de usar los
métodos opcionales de Iterator o ListIterator). Esto está disponible para cualquier clase que implemente la interfaz
Iterable (que incluye todo el colecciones en el estructura). En cambio de creando un Objeto iterador , Podemos recorrer
directamente la colección, con el siguiente elemento devuelto a un local referencia variable cada tiempo el bucle itera. En
este ejemplo, “ monthNames ” es el nombre de la colección y “ aString ” es el nombre de la variable local.
12.4 A Concrete Collection Class: The 309
ArrayList
para(Cadena una cadena : nombres de los meses)
{
[Link](unaCadena);
}

[Link] Lambda Expresiones


Existe otra forma de iterar a través de una colección, y es mediante una expresión lambda. La interfaz Iterable tiene
un método “ forEach ” predeterminado que realiza a dado acción en cada objeto en el recopilación. Tú puede
recordar eso a La expresión lambda de Java debe implementar el único método abstracto de una interfaz. En este caso,
la interfaz es [Link], que tiene un “ accept ” abstracto. método. El “ para cada uno ” método
acepta a Consumidor como un argumento, entonces él es el “ aceptar ” método que la expresión lambda está
implementando (de forma anónima). El código es bastante simple:

[Link](nombreDeMeses -> { [Link](nombreMes);


});

Si cree que esto se ve ligeramente diferente de la expresión lambda que presentamos en el Capítulo 8 , tiene
razón. Primero, no estamos creando una referencia a la expresión lambda para su posterior ejecución, por lo que no
hay una referencia específica a la interfaz que se está implementando. simplemente están incorporando la expresión
lambda como el argumento del método “ forEach ” . La otra es que, dado que solo hay un argumento ( “
nombre_del_mes ” ) él hace no necesidad a aparecer en paréntesis (aunque (Agregar paréntesis también estaría bien).

12.4.4 Un Lista de matrices de Módulo Objetos

En el siguiente ejemplo, refactorizaremos las clases Curso y Módulo del Capítulo 9 . De esta forma, la asociación
entre un curso y sus módulos se implementa utilizando un ArrayList en lugar de un array. Esto hará que el código sea
más robusto (no habrá necesidad de preocuparse por ir más allá de los límites de un array) y nos permitirá utilizar
métodos e iteradores en la colección que no están disponibles con los arrays. El campo array del curso se reemplazará
por un ArrayList.

privado Lista de matrices<módulo> módulos = nuevo ArrayList<Módulo>();

Esto lleva a otros cambios en varios métodos de la clase. El “ addModule ” método No más extenso necesidades
a ser preocupado con lanzamiento un Excepción, ya no necesitamos un contador manual. Solo agregamos un módulo
a la lista de matrices y se redimensionará automáticamente si es necesario.
310 12 The Collections Framework and
Generics
público vacío agregarModulo(Módulo nuevoMódulo)
{
mó[Link](nuevoMódulo);
}

El Método “ getTotalCredits ” simplemente itera a través de el recopilación, en Este ejemplo utiliza el bucle
especial “ for ” .

público entero obtenerCréditosTotales()


{
entero total = 0;
para (Módulo metro : módulos)
{
total += [Link]édito();
}
devolver total;
}

El “ obtenerMódulos ” método No más extenso devoluciones un formación pero un Lista de matrices de Módulos.

público Lista de matrices<módulo> obtenerMódulos()


{
devolver módulos;
}

Finalmente, el método “ getModuleCount ” ya no necesita depender del contador manual, sino que simplemente
devuelve el tamaño actual de ArrayList.

público entero obtenerConteoDeMódulos()


{
devolver mó[Link]();
}

En general, el código que utiliza ArrayList es más simple y más sólido que el código equivalente que utiliza una
matriz.
Torneado nuestro atención a el unidad pruebas de Cap. 10 , el prueba para yendo más allá de Los límites de el
formación es No más extenso requerido. Allá es uno otro cambiar a el pruebas. El “ testAddedModule ” método
necesidades a ser modificado entonces eso él usos el " conseguir " método del ArrayList en lugar de utilizar un valor
de índice (entre corchetes) en la matriz.

público vacío pruebaMóduloAñadido()


{
Módulo módulo = nuevo Módulo ("Colecciones",
10, "Asignación");
[Link](módulo);
Módulo módulo 5 = [Link]().get(4); assertEquals(módulo, módulo5);
}
12.4 A Concrete Collection Class: The 311
ArrayList
Este prueba contiene un ejemplo de un “ antipatrón ” (es decir a común patrón eso No necesariamente debes
seguirlo). Este antipatrón tiene varios nombres, entre ellos “ Ley de Deméter ” , “ no hables con extraños ” y “
desastre ferroviario ” . La siguiente línea es la que muestra este comportamiento:

Módulo módulo 5 = [Link]().get(4);

Qué nosotros son haciendo es Accediendo el Lista de matrices a través de el Curso y entonces Accediendo Un
método de el Lista de matrices directamente. Este amable de código poder ser considerado como a malo práctica, como
él descansos encapsulación. Un alternativa diseño estrategia es a encapsular acceso al ArrayList agregando, por
ejemplo, un “ getModule ” método para la clase Curso.

público Módulo obtenerMódulo(int índice)


{
devolver mó[Link](índice);
}

Ahora el prueba poder ser escrito sin rotura encapsulación:

@Prueba
público vacío pruebaMóduloAñadido()
{
Módulo módulo = nuevo Módulo ("Colecciones", 10,
"Asignación");
[Link](módulo);
Módulo módulo 5 = [Link](4);
assertEquals(módulo, módulo5);
}

Nota
La idea de que encadenar una serie de llamadas a métodos es una mala práctica de diseño es solo... verdadero si él
descansos el encapsulamiento de estado datos dentro objetos. Si codificación usando Un funcional programación
estilo, el encadenamiento juntos de método llamadas es un patrón esperado. En programación funcional, los métodos
no mantienen el estado y cualquier representación del estado es inmutable, por lo que no hay ruptura de la
encapsulación .

Ejercicio 12.1
Cree una clase Bank que contenga una colección de objetos BankAccount, utilizando un LinkedHashSet. Agregue
métodos a la clase Bank para agregar BankAccounts al banco y mostrar los saldos de todas las cuentas que se
encuentran actualmente en el banco.

12.4.5 Inmodificable Colecciones

Una de las características de la programación funcional es que trabaja con variables inmutables (no se pueden ser
cambió) datos. Bastante que laboral con a datos colocar eso podría cambiar en el medio de a proceso, él voluntad
crear un inmutable Copiar de eso datos colocar. Java
312 12 The Collections Framework and
Generics
La sintaxis utiliza el término “ inmodificable ”. en lugar de “ inmutable ” Porque aunque sea es posible a crear un
inmodificable recopilación, él es no posible a garantizar que ninguno de los elementos dentro de esa colección puede
ser modificado en otra parte del código. Sin embargo, como indica el Javadoc, “ si una colección no modificable
contiene todos los elementos inmutables, puede considerarse efectivamente inmutable ” .
Este poder ser muy útil en complejo programación entornos dónde diferentes partes de el sistema podría ser
Accediendo el mismo datos. A adoptar este tipo de codificación, Java 9 y 10 ambos introducido alguno nuevo
maneras a crear inmodificable colecciones. Esto se podría hacer con versiones anteriores de Java, pero con una
codificación más compleja. Aquí, por ejemplo, se muestra el código para crear una copia no modificable de una lista,
utilizando el método estático “ [Link] ” . En este ejemplo, creamos y completamos una lista, y luego hacemos
una copia no modificable. Si intentamos agregar otro objeto a la copia no modificable, se generará una
UnsupportedOperationException.

Lista<Cadena> bandera = nuevo ArrayList<String>(); [Link]("Rojo");


[Link]("Azul"); [Link]("Verde");
Lista<Cadena> Colores inmutables = [Link](colores);
// añadiendo a la lista [Link](0,
"negro");
// intentando a agregar a el inmodificable Lista
// lanza un UnsupportedOperationException [Link](0, "Negro");

Hay varios métodos como este que respaldan la creación simple de archivos inmodificables. colecciones.
Nosotros voluntad no cubrir cualquier más de a ellos aquí como ellos son algo de a especialista requisito pero
controlar el Javadoc para Opciones si tú tener el necesidad Trabajar con colecciones no modificables.

12.5 Mapas

A Mapa permite a almacenado objeto a ser accedido por usando otro objeto como a clave. Por lo tanto, un
mapa consta de un conjunto de objetos “ clave ” , cada uno asociado con un único “ valor ”. objeto. Es necesario
especificar los tipos de las claves y los valores. En este ejemplo, un HashMap (una de las implementaciones de la
interfaz Map) utiliza cadenas tanto para las claves como para los valores para representar una guía telefónica simple.
Ambos tipos, separados por comas, deben especificarse entre corchetes angulares.

HashMap<Cadena, Cadena> directorio telefónico


= nuevo HashMap<Cadena, Cadena>();

A pesar de en este ejemplo el llaves y valores son ambos el mismo tipo, ellos También podrían ser de diferentes
tipos.
12.5 313
Maps
Al agregar elementos mediante el método “ put ” , debe proporcionar una clave y un valor de los tipos correctos.

agenda telefó[Link]("Fe", "555-123456");


[Link]("Esperanza", "555-232323");
[Link]("Caridad", "555-343456");

Inserción un objeto con a llave eso es igual a un existente llave reemplaza el objeto existente.

[Link]("Esperanza", "555-999999");

Valores son accedido por su llaves.

[Link]([Link]("Esperanza")); // " 555-999999"

Ellos poder también ser remoto usando su llaves.

agenda [Link]("Fe");

Hay varios otros métodos de Mapa, incluidos los siguientes ejemplos, que le permiten comprobar el contenido y
el estado actuales del Mapa.

[Link]([Link]()); // falso
[Link]([Link]()); // 3
[Link]([Link]("Fe")); // falso
[Link]([Link]("555-343456"));
// verdadero

El HashMap también incluye un “ toString ” sobrecargado método que muestra el contenido actual del Mapa

[Link](agenda telefónica); // usos “aCadena”

Nota
El orden en el que aparecen los elementos en un mapa se basa en el código hash, por lo que parece arbitrario. Los
códigos hash no son claves de datos y no se pueden utilizar como tales.

12.5.1 Mapa Vistas

Mapa Implementaciones proporcionar vistas de su contenido de tres Perspectivas. En la figura 12.4 , podemos ver que
un mapa está formado por colecciones. Las claves son un conjunto (porque deben ser únicas), mientras que los
valores son una colección (se permiten los duplicados). En suma, nosotros poder conseguir a vista de cada clave-valor
par en el Mapa, devuelto
314 12 The Collections Framework and
Generics
a Recopilación
a Colocar de llaves
of values
keySet<T>() valores<T>()

Keys Values

conjuntoDeEntradas<T,T>() Faith 555-123456


Hope 555-232323
Charity
a Colocar de [Link] objetos
555-343456

Higo. 12.4 Los tres vistas de Un mapa

como a colocar de [Link] objetos. Él es importante a recordar eso estos Colecciones son solo vistas del Mapa,
no colecciones separadas, y no deben usarse más allá de iteraciones a corto plazo. Cualquier otro acceso al Mapa debe
realizarse directamente a través de sus métodos.
En este ejemplo, nosotros usar un Iterador a escanear el llaves y recuperar su valores asociados usando el
conseguir método. El colocar de llaves es devuelto de el “ Conjunto de claves ” método:

Establecer<Cadena> nombres = libreta telefó[Link]();

Luego podemos iterar sobre este conjunto y usar cada clave para obtener su valor asociado del Mapa.

para (Cadena nombre : nombres)


{
[Link](nombre + "\'s número es " + agenda
telefó[Link](nombre));
}

Si nosotros solo buscado a recopilación de el valores nosotros podría en cambio usar el “ valores ”
método a devolver a Recopilación, para ejemplo,

Colección<Cadena> Números de teléfono = libreta telefó[Link]();


12.5 315
Maps
De nuevo, nosotros podría iterar encima este recopilación a conseguir acceso a el valores.
El siguiente código muestra cómo nosotros poder conseguir a Colocar de [Link] objetos de el
“ Conjunto de entradas ” método, Permitiendo a nosotros a iterar encima todo el clave-valor pares en el Mapa.

Conjunto<[Link]<Cadena, Cadena> Conjunto de entradas = libreta


telefó[Link]();
para ([Link]<Cadena, Cadena> fila : Conjunto de entradas)
{
[Link](fila);
}

12.5.2 Usando a Mapa de árboles

El siguiente ejemplo utiliza un TreeMap (que implementa la interfaz SortedMap) para implementar a simple cita
diario, usando fechas como el llaves y nombres (cadenas) como el valores. A diferencia de a Mapa Hash, a Mapa de
árboles proporciona a ordenado orden de llaves. En En el diario de citas, puede resultar útil tener las fechas de las
citas ordenadas. Las claves en este ejemplo serán objetos LocalDateTime.
A diferencia de Basado en matrices estructuras allá es No concepto de un inicial tamaño cuando usando una
implementación subyacente basada en árbol, que contrasta con la implementación de HashMap de el Mapa interfaz,
cual proporciona a por defecto inicial capacidad (de 16). En este ejemplo, a Mapa de árboles es incluido como a
privado atributo de el Diario clase (llamado “ appointmentSlots ” ) utilizando el constructor de cero argumentos. El
mapa está tipificado para tener objetos LocalDateTime como claves y cadenas como valores:

privado Mapa de árbol<Fecha y hora local, Cadena> Citas en línea = nuevo


TreeMap<LocalDateTime, String>();

Entradas se introducen en este mapa a través de el “ hacerCita ” método, que coloca la clave y su valor asociado
en el Mapa (donde “ clave ” en este caso es un objeto LocalDateTime y “ valor ” es una cadena). El “
showAppointments ” El método utiliza el “ keySet ” método del Mapa para obtener el conjunto de claves, luego itera
a través de estas llaves a acceso el valores. A formato el producción, individual campos son devuelto desde
LocalDateTime mediante el uso de métodos “ getter ” .
Este es el completo clase (incluido a " principal " método):
316 12 The Collections Framework and
Generics
paquete [Link].chapter12; importar
[Link];
importar [Link];
importar [Link];

público clase Diario


{
privado Mapa de árbol<Fecha y hora local, Cadena> Citas en línea = nuevo
TreeMap<LocalDateTime, String>();
público vacío hacerCita(Cadena nombre, entero año, int mes, int
día, int hora, int minuto)
{
Fecha y hora local llave = [Link]
(año, mes, día, hora, minuto);
[Link](clave, nombre);

}
público vacío mostrarCitas()
{
Cadena nombreActual;
Establecer<FechaHoraLocal> equipo =
[Link](); para(Fecha y hora local)
fecha y hora : equipo)
{
nombreActual = [Link](fechaHora);
[Link](nombreActual +
" tiene un cita en " + [Link]()
+ " " + [Link]()+ " "
+ [Link]()
+ " en " + [Link]() + : "
+ [Link]());
}
}
público estático vacío principal(Cadena[] argumentos)
{
// crear un objeto Diario Diario
diario = nuevo Diario();
// agrega tres citas al diario [Link]("Excelente Rey de
Terror",
1999, 7, 1, 10, 30);
[Link]("Papá Noel Claus", 2020, 12, 24,
23, 59);
[Link]("Neville Chambelán",
12.5 317
Maps
1938, 9, 28, 12, 0);
// mostrar el equipo en el diario [Link]();
}
}

La salida de Citas muestra que la secuencia de entradas en el Mapa está ordenada por fecha.

Neville Chamberlain tiene una cita el 28 DE SEPTIEMBRE DE 1938 a las 12:0 El


Gran Rey del Terror tiene una cita el 1 DE JULIO DE 1999 a las 10:30 Papá
Noel tiene una cita el 24 DE DICIEMBRE DE 2020 a las 23:59

Ejercicio 12.2
Agregue varios objetos String a un ArrayList. Repita el ArrayList y obtenga cada elemento en doblar, puesta él en a
Mapa Hash, indexado por un entero encimera. Escribir El HashMap a estándar producción a vista es contenido (él tiene
a “ aCadena ” método para este).

Ejercicio 12.3
Agregar a método a el Diario clase llamado “ eliminar cita ” eso, dado a fecha, eliminará cualquier cita en esa fecha.
Esto se puede implementar utilizando los métodos “ containsKey ” (que devuelve un valor booleano) y “ remove ”
(que elimina un elemento). de Mapa de árboles eso ambos llevar un objeto de el adecuado llave clase como un
argumento . Agregar a “ Buscar cita ” método a el clase. Este poder también usar “ ContieneClave ” .

Ejercicio 12.4
Escribir a JUnit prueba para el Diario clase. Incluir a prueba para su “ eliminar cita ”
método.

12.6 Utilidad Clases

El utilidad clases proporcionar varios métodos que guiarse por objetos de recopilación clases y matrices, generalmente
usando estático métodos. El Colecciones clase tiene estático métodos para manipular colecciones: búsqueda,
clasificación, giratorio, etc. De manera similar, la Matrices La clase tiene métodos estáticos para manipulando matrices.
Algunos de los métodos de estos utilidad clases, tales como aquellos para binario búsqueda, clasificación y hallazgo mínimo y
máximo valores, deben ser capaz a aplicar un orden relación a el objetos eso ellos son manipulando. Hay dos Formas de
aplicar el orden relaciones; ya sea implementando la interfaz Comparable en los objetos que se van a ordenar o Creando un
comparador externo objeto.
Aplicaciones a menudo necesidad a buscar o clasificar objetos. Para ejemplo, mayoría tarjeta Los juegos
requieren cierto concepto de orden de cartas (es decir, qué carta se puede jugar a continuación o tiene mayor
puntuación). El siguiente ejemplo se basa en algunos aspectos de un juego de cartas, que incluirá ambos
arrastramiento y clasificación jugando tarjetas. En este sección, nosotros voluntad ver cómo aplicar las interfaces
Comparable y Comparator al proceso de clasificación.
318 12 The Collections Framework and
Generics
"interfaz"
Comparable

compararCon(T) : entero

DeckOfCards PlayingCard

52 suit : String
dealNext() : PlayingCard value : int
sort()
shuffle() setSuit(String)
getSuit() : String
setValue(int)
getValue() : int
Higo. 12.5 El clases en el Ejemplo de DeckOfCards toString() : String

Figura 12.5 muestra las clases que vamos a utilizar en este ejemplo. Las clases representan objetos utilizados en
juegos de cartas; PlayingCard y DeckOfCards. La clase PlayingCard tiene dos campos, “ suit ” y “ value ” , y sus
métodos de obtención y establecimiento asociados. También implementa la interfaz “ Comparable ” y reemplaza “
toString ” . Baraja de cartas es un agregación de 52 Cartas de juego objetos. Él incluye métodos para repartir, ordenar
y barajar las cartas.

12.6.1 Comparando Objetos con el Comparable Interfaz

En la Fig. 12.5 , la clase PlayingCard implementa la interfaz Comparable, por lo que la declaración de clase incluye
esta implementación (Comparable está en el paquete [Link], por lo que no se requiere ninguna declaración de
importación). Dado que la interfaz utiliza genéricos, se debe especificar el tipo que se está comparando. En este caso,
estamos comparando PlayingCards:

La clase pública PlayingCard implementa Comparable<PlayingCard>


{…

Esta interfaz declara solo un método (con “ T ” siendo el tipo genérico del objeto):
12.6 Utility 319
Classes
público int compareTo( objeto T);

Él es arriba a el Implementando clase a proporcionar código para este método eso Compara el objeto receptor con
el objeto de parámetro para ordenarlos. Si “ this ” Si el objeto (al que se aplica el método “ compareTo ” ) es de un
orden inferior al del parámetro, el método debe devolver un entero negativo. Si son iguales, debe devolver cero. Si es
de un orden superior, debe devolver un entero positivo. nuestro ejemplo, nosotros voluntad orden jugando tarjetas por
su rostro valor, postergación el El palo de la carta . Todo lo que hace el método es restar el valor nominal del objeto de
parámetro del objeto “ this ” y devolver la diferencia, que puede ser positiva, negativa o cero.

público entero compararCon(Naipe tarjeta)


{
devolver [Link]() - [Link]();
}

Los objetos que implementan la interfaz Comparable (y, de hecho, los objetos que utilizan los Comparadores)
deben anular “ igual ” en a de manera que sea consistente con la implementación del método de comparación. Esto
evita comportamientos potencialmente inconsistentes si estos objetos se almacenan en SortedSets o SortedMaps. Por
lo tanto, deberíamos anular el método “ equals ” de PlayingCard para comparar los valores de las cartas.

@Anular
público booleano es igual a (Objeto objeto)
{
si(objeto == nulo
|| !([Link]().igual([Link]())))
{
devolver FALSO;
}
Cartas de juego otro = (Carta de Juego)objeto;
si(obtenerValor() == [Link]())
{
devolver verdadero;
}
demás
{
devolver FALSO;
}
}
320 12 The Collections Framework and
Generics
Aquí es el completo Cartas de juego clase (nota el “ aCadena ” método cual usos un “ interruptor ” declaración
para convertir el valor de la carta en una cadena, nombrando los ases y las cartas con figuras cuando sea necesario). El
constructor requiere que el palo y el valor de la carta se pasen como parámetros.

paquete [Link].capitulo12;

público clase Cartas de juego implementos Comparable<PlayingCard>


{
privado Cadena traje; valor
int privado;
público PlayingCard(Cadena traje, entero valor)
{
setSuit(traje); setValue(valor);
}
privado vacío setSuit(Cadena traje)
{
Este traje = traje;
}

privado vacío establecerValor(int valor)


{
[Link] = valor;
}
público Cadena obtenerSuit()
{
devolver traje;
}
público entero obtenerValor()
{
devolver valor;
}
@Anular
público Cadena encadenar()
{
Cadena nombreDeTarjeta;
cambiar (valor) {
Caso 1:
nombreDeTarjeta = "As";
romper;
caso 11:
nombreDeTarjeta = "Jacobo";
romper;
caso 12:
nombreDeTarjeta = "Reina";
romper;
caso 13:
nombreDeTarjeta = "Rey";
romper;
12.6 Utility 321
Classes
por defecto:
nombreDeTarjeta = [Link](getValue());
}
devolver nombreDeTarjeta + " de " + traje;
}
@Anular
público entero compararCon(Naipe tarjeta)
{
devolver [Link]() - [Link]();
}
@Anular
público booleano es igual a (Objeto objeto)
{
si(objeto == nulo ||
!([Link]().igual([Link]())))
{
devolver FALSO;
}
Cartas de juego otro = (Carta de Juego)objeto;

si(obtenerValor() == [Link]())
{
devolver verdadero;
}
demás
{
devolver FALSO;
}
}
}

El siguiente ejemplo demuestra algunos de los métodos de la clase PlayingCard, incluido el método “ toString ”
322 12 The Collections Framework and
Generics
paquete [Link].chapter12; clase
pública ComparingCards
{
público estático vacío principal(Cadena[] argumentos)
{
PlayingCard card1 = new PlayingCard("Corazones", 1); PlayingCard
tarjeta2 = nuevo PlayingCard("Diamantes", 13); int comparar =
[Link](tarjeta2);
si(comparar > 0)
{
[Link](tarjeta1 + " montones más que " + tarjeta2);
}
demás
{
si(comparar < 0)
{
[Link](tarjeta1 + " montones menos que " + tarjeta2);
}
demás
{
[Link](tarjeta1 + " montones el mismo como " +
tarjeta2);
}
}
}
}

El producción de este ejemplo quería ser

As de Copas montones menos que Rey de Diamantes

Cambiar los valores de las tarjetas proporcionadas a los constructores daría resultados diferentes.
Este caso de prueba JUnit proporciona pruebas para los tres resultados posibles de " compareTo " método cuando
usado con Naipes. Nota cómo el método (y La prueba) solo se ocupa del valor nominal de la carta, no del palo. La
jota de corazones y la jota de diamantes son iguales cuando se comparan.
12.6 Utility 323
Classes
paquete [Link].chapter12; importación
estático [Link].*; importar
[Link];
público clase Caso de prueba de naipes
{
@Prueba
público vacío pruebaMenosQue()
{
PlayingCard card1 = new PlayingCard("Corazones", 1); PlayingCard
tarjeta2 = nuevo PlayingCard("Diamantes", 13); int comparar =
[Link](tarjeta2); assertTrue(comparar < 0);
}
@Prueba
público vacío pruebaMayorQue()
{
PlayingCard card1 = new PlayingCard("Corazones", 12); PlayingCard
tarjeta2 = nuevo PlayingCard("Diamantes", 4); int comparar =
[Link](tarjeta2);
afirmarVerdadero(comparar > 0);
}

@Prueba
público vacío pruebaMismo()
{
PlayingCard card1 = new PlayingCard("Corazones", 11); PlayingCard
tarjeta2 = nuevo PlayingCard("Diamantes", 11);
entero comparar = [Link](card2); assertTrue(comparar == 0);
}
}

Ahora eso nosotros poder crear Cartas de juego objetos, nosotros necesidad a ser capaz a poner a ellos En un
cubierta. En este ejemplo, nosotros voluntad usar a Lista enlazada como el recopilación eso implementa la agregación
en DeckOfCards. El valor de usar una LinkedList aquí es que poder " trato " de él (es decir nosotros poder eliminar
el objeto en el comienzo de el lista).

privado ListaEnlazada<CartaDeJugando> cubierta =


nueva LinkedList<PlayingCard>();

Será útil tener un método getter privado para esta colección que podamos usar dentro de la clase:

privado ListaEnlazada<CartaDeJugando> obtenerDeck()


{
devolver cubierta;
}
324 12 The Collections Framework and
Generics
El Método “ dealNext ” devoluciones la tarjeta en la parte superior del paquete, usando el método “ re-
moveFirst ” de LinkedList.

público Cartas de juego Trato siguiente()


{
devolver [Link]();
}

En el constructor, 52 tarjetas son agregado a el cubierta, usando el " agregar " método de la interfaz Collection.
Necesitamos proporcionar el nombre del palo a los constructores de las cartas, por lo que en este ejemplo, usamos un
campo de matriz final estático de la clase con los nombres de los palos codificados en él.

público estático final Cadena[] TRAJES =


{"Corazones", "Diamantes", "Picas", "Tréboles"};

A pareja de otro constantes son también útil aquí, a representar el número de cartas de un palo (13) y el número
de palos de la baraja (4). El uso de estas constantes evitará que aparezcan números mágicos (literales numéricos) en el
código.

público estático final int TAMAÑO_TRAJE = 13; público


estático final entero Número de trajes = 4;

Allá es a anidado bucle en el constructor a crear el Naipes y agregar ellos a la baraja; el bucle exterior cuenta a
través de los 4 palos, y el bucle interior cuenta a través de el 13 tarjetas en cada traje. Cuando nosotros agregar a
nuevo Cartas de juego a el cubierta, el “ suitIndex ” valor, cual es cálculo de 0 a 12, necesidades a tener 1 agregado a
él a Obtenga números de tarjetas en el rango 1 – 13.

público Baraja de cartas()


{
para(int Conde de traje = 0; Conde de traje < NUMERO_DE_PALOS;
cantidad_de_palos++)
{
para(int índice de traje = 0; índice de traje < TALLA_DE_TRAJE;
índice_de_traje++)
{
[Link](nuevo PlayingCard(PALOS[cuentaPalos], índice de traje
+ 1));
}
}
}
12.6 Utility 325
Classes
12.6.2 El Colecciones Clase

El Colecciones clase es a colocar de estático métodos eso llevar a cabo operaciones en colecciones. En nuestro Baraja de
cartas nosotros voluntad usar métodos de el Colecciones clase a clasificar y baraja las cartas. La clase Collections
tiene muchos métodos útiles, entre ellos, búsqueda, reversión y siempre que Sólo lectura copias de colecciones.
Mayoría de estos métodos trabajar a nivel de interfaz. La firma del “ shuffle ” El método por ejemplo es

estático vacío barajar(Lista lista);

lo que significa que puede manejar cualquier cosa que implemente la interfaz List (es decir, cualquier colección
ordenada). El método “ shuffle ” reordena aleatoriamente los objetos de la colección, por lo que podemos usarlo
dentro de nuestra clase DeckOfCards para barajar las cartas.

público vacío barajar()


{
[Link](getDeck());
}

Aquí es el completo Baraja de cartas clase, cual nosotros poder trato de y barajar.

público clase Baraja de cartas


{
público estático final int TAMAÑO_TRAJE = 13; público
estático final entero Número de trajes = 4; público
estático final String[] SUITS =
{ "Copas", "Diamantes", "Espadas", "Clubs" }; lista privada
de enlaces <PlayingCard> baraja =
nuevo ListaEnlazada<CartaDeJuego>();
privado ListaEnlazada<CartaDeJugando> obtenerDeck()
{
devolver cubierta;
}
público Baraja de cartas()
{
para(int Conde de traje = 0;
Conde de traje < NUMERO_DE_PALOS; trajeCount++)
{
para(int índice de traje = 0;
índice de traje < TALLA_DEL_TRAJE; índice de traje++)
{
[Link](nuevo PlayingCard(PALOS[cuentaPalos],
índice de traje + 1));
}
}
}
público Cartas de juego Trato siguiente()
{
devolver obtenerDeck().removeFirst();
}
público vacío barajar()
{
[Link](getDeck());
}
}
326 12 The Collections Framework and
Generics
En este programa muy simple, simulamos un juego de cartas en el que se reparten tres cartas a dos jugadores cada
uno. El ganador es el jugador con la puntuación total más alta. Como el constructor crea la baraja de cartas en orden
de palo y número, debemos barajar la baraja antes de repartir las cartas.

paquete [Link].chapter12; importar


[Link];
público clase Juego de cartas simple
{
público estático vacío principal(Cadena[] argumentos)
{
Baraja de cartas cubierta = nuevo BarajaDeCartas();
[Link]();
PlayingCard carta = null; ArrayList<PlayingCard>
jugador1Mano =
nueva ArrayList<CartaDeJuego>(); ArrayList<CartaDeJuego>
jugador2mano =
nuevo ArrayList<PlayingCard>(); int
jugador1Puntaje = 0;
entero jugador2Puntuación = 0;
para(int i = 0; i < 3; yo++)
{
carta = [Link]();
[Link](carta);
puntuación1jugador += [Link]();
carta = [Link]();
[Link](tarjeta);
jugador2Puntuación += [Link]();
}
[Link]("Jugador 1 mano " + jugador1Mano); [Link]("Jugador 2
mano " + jugador2Mano); [Link]("Jugador 1 puntuado " +
jugador1Puntuación +
" Jugador 2 puntuado " + jugador2Puntuación);
}
}

Aquí es alguno muestra producción de correr el juego.

Mano del jugador 1 [Rey de tréboles, 2 de corazones, 10 de corazones] Jugador 2


mano [9 de Diamantes, Rey de Copas, 10 de Diamantes] El jugador 1 anotó 25 El
jugador 2 anotó 32

El “ tipo ” método de las Colecciones La clase puede ser se utiliza para ordenar el DeckOfCards.

[Link]( Lista );

El problema aquí es eso este versión de el " clasificar " método voluntad usar el Implementación de PlayingCard de
el “ comparar con ” método a clasificar el objetos en orden. Desde Nuestra implementación de “ compararCon ” no
toma Si se tienen en cuenta los trajes, la baraja no se clasificará en el tradicional orden, dónde tarjetas son ordenado
primero por traje y entonces por número.
12.6 Utility 327
Classes
A proporcionar un alternativa clasificación implementación, tú poder aprobar a Comparador como segundo
parámetro y lo usará para manejar el orden de clasificación.

[Link]( Lista , Comparador );

En la siguiente sección, crearemos un objeto Comparador adecuado para ordenar la baraja.

12.6.3 Creando a Comparador

La interfaz Comparator representa una relación de orden que se aplica a dos parámetros. objetos. Este interfaz poder
ser implementado a orden elementos independientemente de si implementan o no Comparable. Esto es útil cuando
queremos ordenar objetos de clases que no hemos escrito nosotros mismos y, por lo tanto, no podemos agregar
interfaces adicionales. También puede ser útil proporcionar formas alternativas de ordenar los mismo tipos de objetos.
Tú poder solo implementar el Comparable interfaz en Un camino para a dado clase pero poder crear como muchos
diferente Comparadores como tú como. El comparador interfaz requiere eso tú proporcionar un implementación de el
método de “ comparar ” .

entero comparar(T o1, T o2)

En suma, él declara el “ es igual a ” método.

booleano es igual a (Objeto objeto)

Dado que todos los objetos tienen un método “ equals ” heredado de Object, el compilador no requerirá que se lo
anule. El Javadoc establece que:

Siempre es seguro no anular [Link](Object). Sin embargo, anular este método puede, en algunos
casos, mejorar el rendimiento al permitir que los programas determinen que dos comparadores distintos
imponen el mismo orden.

En el siguiente Comparador implementación, Naipes son ordenado por Tanto el número como el palo (en orden
alfabético). Como en este caso el palo se almacena como una cadena, podemos utilizar el “ compareTo ” existente
Método de la clase String para ordenar los palos. La comparación del valor de las cartas, si son del mismo palo, se
realiza utilizando la implementación de la interfaz Comparable existente. Si PlayingCard no implementara
Comparable, podríamos aplicar manualmente una relación de orden.
328 12 The Collections Framework and
Generics
paquete [Link].chapter12; importar
[Link]; clase pública
CardComparator
implementos Comparador<PlayingCard>
{
público entero comparar(Naipe tarjeta1, Cartas de juego tarjeta2)
{
entero Comparación de trajes =
[Link]().compareTo([Link]()); si(comparaciónDePatrones !=
0)
{
devolver Comparación de trajes;
}
devolver [Link](tarjeta2);
}
}

Aquí es a clasificar método agregado a el Baraja de cartas clase eso usos el " clasificar "
método de el Colecciones clase y el Comparador de tarjetas.

público vacío clasificar()


{
[Link](deck, nuevo Comparador de tarjetas());
}

Este " principal " método muestra el efecto de primero arrastramiento el cubierta y entonces clasificación él.

público estático vacío principal(Cadena[] argumentos)


{
Baraja de cartas Baraja de cartas = nuevo BarajaDeCartas();
baraja de [Link]();
Iterador<PlayingCard> iter = [Link]().iterador(); mientras
([Link]())
{
[Link]([Link]());
}
baraja de [Link]();
iter = [Link]().iterador(); mientras
([Link]())
{
[Link]([Link]());
}
}

La salida de este programa de prueba es bastante larga, por lo que esta muestra se ha truncado :
12.6 Utility 329
Classes
5 de diamantes rey de
Diamantes
4 de espadas rey
de Espadas
10 de espadas
9 de espadas
//etc..

As de Clubs
2 de Clubs
3 de Clubs
4 de Clubs
5 de Clubs
6 de Clubs
7 de Clubs
//etc..

De A partir de este punto, nosotros tener a cubierta de tarjetas que nosotros Podría utilizar en cualquier numero de
juegos de cartas, aunque es posible que necesitemos tener comparadores más especializados para diferentes juegos
dónde el semántica de tarjeta orden son diferente ([Link] “ ases alto " ).

Ejercicio 12.5
No todas las barajas utilizan el “ palo francés ” de diamantes, tréboles, picas y corazones. Otros palos posibles son:

• latín traje: espadas, cálices, Monedas y clubs


• Brisca (Español) traje: oro, espadas, tazas y clubs
• germánico traje: campanas, bellotas, hojas y copas.

Agregue un constructor parametrizado a la clase DeckOfCards para que se pueda proporcionar un argumento
entero para seleccionar el tipo de mazo (usando campos finales estáticos). Escriba una prueba JUnit para su mazo para
confirmar que el palo está configurado correctamente.

Ejercicio 12.6
Tabla 12.2 muestra cómo una clase que implementa la interfaz Deque puede actuar como una pila, con métodos que
coinciden con las operaciones de pila habituales de " push " (agregar un elemento ). a el arriba de el pila), estallido
(eliminar el elemento de el arriba de el pila) y “ peek ” (ver el elemento en la parte superior de la pila sin eliminarlo).
Allá son alguno tarjeta juegos dónde allá son común quinielas de tarjetas. Jugadores puede dibujar a tarjeta de el
arriba de el principal piscina, cual es boca abajo, y desechar tarjetas mediante la adición a ellos atrás a el arriba de
otro piscina, cual es boca arriba. Sin embargo, jugadores poder

Mesa 12.2 Métodos de La


interfaz Deque y sus
Generic Stack Operations Equivalent Deque Method
Push addFirst(e)
equivalent generic stack
operaciones Pop removeFirst()
Peek peekFirst()
330 12 The Collections Framework and
Generics
también elegir a dibujar el arriba tarjeta de el cara arriba piscina, entonces este piscina hechos como a pila. Cree una
clase “ CardPool ” que use una Colección que implemente la interfaz Deque. Proporcionar adecuado
métodos para Naipes a ser ambos estirado de la parte superior del pozo y se devuelve a la parte superior del pozo.
Debido a que este pozo está boca arriba, los jugadores también deberían poder verificar la carta que está en la parte
superior del pozo antes de elegir si no robar la carta.
Para probar su clase, escriba métodos de prueba JUnit para empujar cartas al pozo, sacar cartas del pozo y mirar
la carta superior.

Ejercicio 12.7
Crear a " Mano " clase eso representa a colocar de tarjetas sostuvo en a del jugador mano. Usar Esta clase de mano
sirve para escribir el comienzo de un juego de 21 (también conocido como Pontoon). El juego tendrá un crupier y un
jugador. El crupier y el jugador reciben tres cartas. El que tenga la puntuación más alta (calculada sumando los
valores de las cartas) gana, a menos que el total sea superior a 21, en cuyo caso la mano se pasa . Todas las cartas
con figuras cuentan como 10. El crupier gana todos los sorteos.

12.7 Genéricos y Herencia

Las colecciones que hemos visto hasta ahora se han tipificado en una sola clase. Esto puede causar problemas cuando
queremos escribir métodos de utilidad genéricos que actúen sobre colecciones de objetos en jerarquías de herencia. La
siguiente clase contiene un método de utilidad estático que itera a través de una colección de objetos y los imprime en
la consola.

público clase Impresora genérica


{
public static void printElements
(Colección<Objeto> miColección)
{
para (Objeto miObjeto : miColección)
{
[Link](miObjeto);
}
}
}

El problema con un método como este es que no se puede utilizar para iterar sobre subclases del tipo declarado
de la colección . En este ejemplo, solo se puede pasar una colección de tipo Object al método “ printElements ” .
Si intentamos pasar una colección eso es mecanografiado a algo otro que Objeto, para ejemplo, a recopilación de
cadenas, esto provocará un error del compilador.
12.7 Generics and 331
Inheritance
Lista de matrices<Cadena> Nombres de los meses = nuevo ArrayList<String>();
[Link]("Enero");
[Link]("Febrero"); [Link](monthNames); //
compilador error

Aunque String es una subclase de Object, no podemos imprimir una colección de Strings utilizando este método.
El error de compilación resultante indica que:
El método printElements(Collection < Object > ) en el tipo GenericPrinter no es aplicable para los argumentos
(ArrayList < String > )
Para crear un método más genérico que pueda procesar objetos de subclases, podemos especificar el tipo de
colección usando el “ ? ” comodín. Esto hace que la colección pasada al método sea de un tipo desconocido, lo que
significa que el método puede procesar cualquier tipo de colección.

público estático vacío printAnyElements


(Colección<?> miColección)
{
para(Objeto miObjeto : miColección)
{
[Link](miObjeto);
}
}

Este método poder imprimir cualquier tipo de recopilación.

[Link](nombresDeMeses); // voluntad compilar

Nota
No se pueden agregar objetos a una colección creada con este comodín. Solo es apropiado para métodos de utilidad
que manejan colecciones existentes como la del ejemplo.

12.7.1 Especificando Límites

En el anterior ejemplo, nosotros comenzó con a método eso podría manejar clases de tipo objeto, entonces usado a
comodín a permitir el método a trabajar con cualquier tipo. A veces, sin embargo, nosotros desear métodos eso
manejar a específico clase y es subtipos, en orden llamar métodos específico a eso clase jerarquía. Para ejemplo,
nosotros podría desear a escribir Un método eso poder trabajar con cualquier Forma objeto (arrogante el Forma clase
nosotros creado en el Cap. 8 , que tiene un método “ getArea ” ). El siguiente código mostrará el área de cualquier
forma en una colección de formas.
332 12 The Collections Framework and
Generics
público estático vacío displayShapeProperties (formas de
Collection<Shape>)
{
para(Forma s : formas)
{
[Link]("El área de " + s +
" es " + [Link]());
}
}

Este obras bien en términos de usando a polimórfico referencia de tipo Forma a


referencia subclase objetos. Desafortunadamente, él quería no manejar a recopilación mecanografiado A un subclase,
como Cuadrado. El siguiente Lista de matrices, para ejemplo, podría no ser pasado al método “
displayShapeProperties ” .

ArrayList<Cuadrado> cuadrícula = nuevo ArrayList<Square>(); [Link](new


Square(null, 250)); [Link](cuadrados);
// voluntad no compilar

Podemos superar esta restricción utilizando un comodín acotado . Comodines acotados dejar a nosotros
especificar eso colecciones mecanografiado a a subclase son compatible con Este método. En este ejemplo, nosotros
poder especificar eso cualquier recopilación que contiene subclases de Forma se puede pasar al método.

público estático vacío displayAnyShapeProperties (Colección<?


extiende Shape> formas)
{
para (Forma s : formas) {
[Link]("El área de " + s + " es " +
[Link]());
}
}

Ahora, " Forma " es el superior atado de el comodín. Nosotros podría aprobar a recopilación de tipo Cuadrado a
este método, o Forma bidimensional, o en efecto cualquier otro subclase de Forma.

[Link] ( cuadrados);
// voluntad compilar
12.7 Generics and 333
Inheritance
Ejercicio 12.8
Crear a clase con a método eso voluntad llevar a recopilación de cualquier subtipo de Número como parámetro e
imprima su contenido en la consola. Pruebe sus métodos usando:

(a) A recopilación de Números enteros


(b) A recopilación de Dobles.

12.8 Recopilación Arroyos

La API de Stream de Java se agregó a Java 8 y admite un enfoque de programación funcional para manejar
colecciones (u otras secuencias de objetos) en Java mediante expresiones lambda. Las clases e interfaces de la API de
Stream se encuentran en el directorio “ [Link] ”. paquete. Cualquier colección puede devolver una
implementación de la interfaz Stream utilizando el “ stream ” método de la colección dada. Aquí hay un ejemplo de
cómo obtener un Stream de una ArrayList de objetos PlayingCard. Primero, asumimos que hay una lista de
PlayingCards llamada “ mano ” :

Lista<PlayingCard> mano = nuevo ArrayList<CartaDeJuego>();

De este nosotros poder crear a Arroyo de Cartas de juego referencias usando el " arroyo "
fábrica método.

Transmisión<PlayingCard> transmisión de tarjetas = [Link]();

El motivo de la creación de este Stream es que podamos aplicar una o más operaciones al contenido de ArrayList
para crear un valor o una colección resultante. Stream operaciones hacer no manipular el contenido de el original
Recopilación entonces poder se pueden encadenar entre sí en un estilo de programación funcional. Estas operaciones
juntas hacen arriba a arroyo tubería, consistente de el original datos fuente (a Recopilación en los siguientes
ejemplos), cero o más operaciones intermedias que transforman el flujo en otro arroyo y a Terminal operación
eso produce el Resultado. Se puede pensar que una secuencia de flujo actúa como una consulta en la fuente del
flujo. Aquí hay un ejemplo muy simple que simplemente aplica el método " count " para contar la cantidad de
elementos en el flujo.

largo Conteo de tarjetas = [Link]();

Tenga en cuenta que una vez realizada la operación de terminal, el flujo se cierra. medio eso en el ejemplo arriba,
el “ conteo de tarjetas ” referencia podría no ser se utiliza para cualquier otra operación de transmisión a menos que
se asigne a una nueva transmisión.
334 12 The Collections Framework and
Generics
Una forma de utilizar los flujos en una colección es crear otra colección que contenga un subconjunto de los
objetos originales. En la siguiente línea de código, a arroyo es creado de un Lista de matrices de Cartas de juego
objetos. Nota eso en Este ejemplo, a hacer el código más conciso y a asegurar eso nosotros conseguir a nuevo arroyo
que aún no se ha cerrado; llamamos al método “ stream ” como parte de la canalización en lugar de declarar una
variable separada. La operación terminal devolverá una Lista ( “ selectedList ” ). Sin embargo, antes de que eso
suceda, hay una operación intermedia ( “ filter ” ) que aplica un predicado a cada elemento (al que se hace referencia
mediante el nombre de la variable local). " tarjeta " en estos ejemplos) a determinar si él debería ser incluido. El El
predicado se implementa mediante una expresión lambda, que en este ejemplo selecciona solo aquellas cartas en la
lista “ Corazones ”. traje. entonces el “ recoger ” El método crea la lista que se devolverá utilizando el estático “ a la
lista ” método de el Recolectores de flujo de Java clase (puesta Cada operación en la tubería en una línea separada no
es necesaria pero mejora la legibilidad).

Lista<PlayingCard> Traje seleccionado = [Link]()


.filter(tarjeta -> [Link]().contentEquals("Corazones"))
.collect([Link]());

Aquí hay una clase de ejemplo completa que procesa una “ mano ” de 10 cartas al azar para producir una lista de
aquellas del palo " Corazones " :

paquete [Link].chapter12; importar


[Link]; importar
[Link];
importar [Link];
importar [Link];

público clase Transmisión de HandOfCards


{
público estático vacío principal(Cadena[] argumentos)
{
Baraja de cartas Baraja de cartas = nuevo BarajaDeCartas();
baraja de [Link]();
Lista<PlayingCard> mano = nuevo ArrayList<PlayingCard>(); para(int i = 0;
i < 10; i++)
{
[Link]([Link]());
}
[Link]("Mano de tarjetas Tratado \norte" + mano); Lista<CartaDeJuego>
paloseleccionado = [Link]()
.filter(tarjeta -> [Link]().contentEquals("Corazones"))
.collect([Link]()); [Link]("Filtrado mano (copas
solamente)\n" +
Traje seleccionado);
}
}
12.8 Collection 335
Streams
El producción de curso voluntad variar de correr a correr dependiente en el tarjetas Al azar
“ tratado ” , pero aquí es uno ejemplo.

Mano de tarjetas Tratado

[Reina de Tréboles, 6 de Corazones, 10 de Corazones, 9 de Picas,


As de Copas, 9 de Copas, As de Tréboles, Rey de diamantes, 2 de
picas, 4 de picas] Mano filtrada (solo corazones)
[6 de Copas, 10 de Copas, As de Copas, 9 de Copas]

En todos los ejemplos siguientes, asumimos que se ha utilizado el mismo código para crear la “ mano ” de diez
cartas, a la que se aplica cada uno de los ejemplos de Stream.
En el anterior ejemplo, a Arroyo era usado a crear a recopilación eso contenía un subconjunto de los elementos
originales utilizando el “ filtro ” método. El “ mapa ” El método, por el contrario, aplica una función a cada uno de
los elementos del flujo para crear una nueva colección. o Mapa que contiene el convertido datos. En Este ejemplo,
nosotros usar “ mapa ” convertir el nombres de cada tarjeta en el mano a superior caso, creando a Lista de
Instrumentos de cuerda.

Lista<Cadena> Trajes con mayúsculas = [Link]()


.map(tarjeta -> [Link]().toUpperCase()).
.collect([Link]());

Aquí es un ejemplo producción de este código (voluntad variar de correr a correr).

Superior caso trajes: [CLUBS, COPAS, ESPADAS, ESPADAS, PICAS, PICAS, CORAZONES,
PICAS, TRÉBOLES, DIAMANTES]

Como vimos con el método “ count ” anteriormente en esta sección, no todas las operaciones de Stream dan
como resultado una Colección. Por ejemplo, podemos usar los métodos “ max ” o “ min ” con Comparators para
devolver el objeto en el stream con el valor más alto o más bajo. En este ejemplo, usamos “ max ” para encontrar la
Carta de Juego con el valor máximo. El método “ get ” método devoluciones el Carta de juego resultante. Nota el uso
de el doble colon " método referencia " operador, cual poder ser usado como a taquigrafía en lambda expresiones. En
este ejemplo, “ PlayingCard::obtenerValor ” es usado en cambio del método más explícito pero menos conciso “
card -> [Link]() ” . En ambos casos, el método “ getValue ” se aplica a cada una de las cartas de juego de la
colección:

Cartas de juego más alto = Traje [Link]()


.max([Link](CartaDeJuego::obtenerValor))
.conseguir();
336 12 The Collections Framework and
Generics
En este levemente diferente ejemplo, nosotros usar el “ mínimo ” método después aplicando a Filtro que
selecciona solo aquellas cartas en la lista “ Picas ” palo, devolviendo el que tenga el valor más bajo (tenga en cuenta
que este código generará una excepción si no hay espadas en la mano de cartas generada aleatoriamente).

Cartas de juego alto = [Link]()


.filter(tarjeta -> [Link]().equals("Picas"))
.min([Link](PlayingCard::getValue))
.conseguir();

En este ejemplo, el " summingInt " El método de la clase Collectors se utiliza con el método “ collect ” para
sumar todos los valores de las tarjetas.

entero suma de tarjeta = [Link]()


.collect([Link](PlayingCard::getValue));

Para el ejemplo final de esta sección, nos referiremos a la Sección 12.4 , donde Pasamos por cuatro formas
diferentes de iterar a través de una colección: un Iterador, un ListIterator, un “ for ” mejorado bucle y una
expresión lambda. Existe otra opción, que es utilizar un flujo y el “ forEach ” método, que itera a través de los
elementos del flujo. Por supuesto, esto es muy similar a la expresión lambda de la sección 12.4 . pero aplicando “
forEach ” al flujo en lugar de a la colección.

[Link]()
.forEach([Link]::println);

Los ejemplos de esta sección han mostrado algunas de las posibilidades de utilizar Streams, pero hay muchos
otros aspectos a el API no cubierto aquí que Proporcionar diferentes formas de procesar datos de colecciones u otras
secuencias de objetos.

Ejercicio 12.9
Crear un Lista de matrices de Números enteros y aplicar el siguiente Arroyo métodos a él:

• Usar “ máximo ” a devolver el más alto valor.


• Usar “ min ” a devolver el más bajo valor.
• Aplicar el “ para cada uno ” método a imprimir afuera cada Entero en el arroyo.
• Aplicar a filtro a devolver a Lista que contiene solo aquellos Números enteros arriba a cierto valor
• Hacer seguro allá son alguno duplicado valores en su original Lista de matrices, entonces aplique el método “
distintos ” para crear una lista que contenga solo los valores distintos.
12.8 Collection 337
Streams
Ejercicio 12.10
Todo el procesamiento de objetos Integer en el Ejercicio 12.9 se puede realizar utilizando un Stream, pero hay otros
procesos numéricos que se pueden realizar en un IntStream, que proporciona un flujo de ints primitivos.

• Crear un Flujo interno usando el estático " de " método cual llevar a lista de números enteros separados por
comas como argumento.
• Aplicar el " suma " método a el Transmisión interna, cual devoluciones un en t.
• Crear otro Flujo interno y aplicar el m é t o d o “ promedio ” , cual devoluciones un objeto OptionDouble.

12.9 Resumen

En este capítulo, hemos analizado algunos aspectos del marco de colecciones y lo hemos utilizado para gestionar
colecciones de objetos. Comenzamos describiendo algunas de las interfaces principales del marco, incluidas Iterable,
Collection y Map, y vimos cómo estas poder ser usado a implementar objeto asociaciones. Nosotros miró en
el Clases de propósito general en el marco de Colecciones que vinculan interfaces de alto nivel y tipos específicos de
implementación, como ArrayList, que implementa la interfaz List con una implementación de matriz subyacente, y
TreeMap, que implementa la interfaz SortedMap utilizando una implementación basada en árboles. Se explicó el uso
de genéricos para crear colecciones de tipos seguros, junto con formas de aplicar tipos genéricos dentro de jerarquías
de herencia. El capítulo también describió cómo el marco utiliza las interfaces para proporcionar servicios comunes
en una variedad de clases implementadoras, y cómo algunas de ellas varían debido a las características de las
diferentes implementaciones utilizadas. Los ejemplos de código ilustraron las diferencias. entre Colecciones y Mapas,
el varios maneras en cual Iteradores poder Se demostró cómo se pueden utilizar para escanear el contenido de las
colecciones y cómo se pueden crear colecciones no modificables. Se demostraron utilidades como la clase Collections
y la interfaz Comparator. ilustrado con ejemplos de métodos semejante como " clasificar " y “ barajar ” que se
pueden aplicar a objetos de colección. Algunas de las interfaces, clases y métodos de el Arroyos API eran explorado,
con varios ejemplos aplicado a un ArrayList de objetos de dominio.
Aporte y Producción Corrientes

13

Un flujo es una secuencia ordenada de bytes que fluyen desde un origen a un destino. implementación de Arroyos en
Java objetivos a encapsular cualquier amable de de serie entrada o salida en una biblioteca de clases que proporcionan
un conjunto consistente de abstracciones (interfaces) y abstracto clases), a pesar de todo de el fuente o el hundir
(destino) del datos. Cuanto más bajo detalles de nivel específicos para esos tipos de fuente o destino son manejados
por el flujo y no tienen que ser manejados por el programador. Por ejemplo, el diferencias entre escribiendo a a
archivo y escribiendo a el pantalla Las consolas son manejadas por las implementaciones de las clases relevantes. Un
programa puede escribir y leer datos hacia y desde archivos, la consola, el teclado, redes u otros programas, todos
usando métodos similares, implementados por clases de biblioteca de flujo que encapsulan las diferencias de bajo
nivel entre los diversos tipos de transferencia de datos, proporcionando abstracciones de nivel superior para que las
use el programador (Fig. 13.1 ).

13.1 Java Arroyo Clases

El arroyo clases tener estado desarrollado en diferente Etapas encima el vida de Java, y hay clases de flujo en los
paquetes “ [Link] ” y “ [Link] ” . Los flujos originales en JDK 1.0 solo manejaban entrada y salida básicas de
bytes y primitivos de Java, por lo que JDK 1.1 agregó lectores y escritores para manejar E/S de caracteres. Estas
clases están en el paquete [Link]. Aunque estas clases son adecuadas para muchas aplicaciones, no son
particularmente escalables para aplicaciones de nivel empresarial, por lo que a partir de JDK 1.4, ha habido un
conjunto de clases en evolución en la biblioteca NIO (New Input/Output) (el paquete “ [Link] ” ) diseñada para
proporcionar implementaciones de flujo más escalables. Este es un proceso en curso y ha habido más clases NIO 2
(mejoras de NIO) en versiones posteriores. En este capítulo, cubriremos los conceptos básicos del manejo de flujos en
el paquete “ [Link] ” y brindaremos una breve introducción a “ [Link] ” .

© Saltador Naturaleza Suiza Estado 2020


339
D. Parsons, Foundational Java , Textos en Ciencias de la Computación,
[Link]
340 13 Input and Output
Streams
Programa

streams

Consola de archivos Teclado Red Programa

Higo. 13.1 Arroyos proporcionar de alto nivel abstracciones eso minimizar el diferencias entre Diferentes tipos de
transferencia de datos

13.1.1 Diferente Tipos de Arroyo

Existen muchos tipos diferentes de flujos en las bibliotecas, pero existe una categorización general que podemos hacer
en términos de los tipos de datos que ciertos flujos están diseñados para manejar. Los cuatro tipos de datos son bytes,
primitivos, caracteres y objetos, y existen familias separadas de clases de flujo que se utilizan para manejar estos tipos
(Tabla 13.1 ). Esto es una especie de simplificación excesiva de las bibliotecas de flujos, pero captura algunos
conceptos clave.
El nivel más bajo arroyos son byte arroyos que funcionar en bytes y Matrices de bytes. Estas se implementan
mediante las clases InputStream y OutputStream y sus subclases.
Filtrar arroyos usar más bajo nivel byte arroyos como parte de su implementación, entonces Para crear un flujo de
filtro, también necesitamos crear un flujo de entrada o salida asociado. Algunos flujos de filtro operan con tipos de
datos primitivos (ints, doubles, etc.). Estos se implementan mediante clases que extienden DataInput y DataOutput.
Los flujos de caracteres contienen caracteres Unicode de 16 bits y funcionan con caracteres, matrices de
caracteres y cadenas. Se implementan mediante las clases Reader y Writer y sus subclases.
Los flujos de objetos leen y escriben objetos. Estos están representados por ObjectInputStream. y Flujo de salida
de objetos clases. Estos son concreto clases eso ampliar InputStream y OutputStream y también implementar varias
interfaces.

Mesa 13.1 Tipos de corriente y el datos tipos eso ellos manejar

Arroyo tipo Datos tipos Relacionado clases


Byte arroyos Bytes (y matrices de bytes) Flujo de entrada/Flujo de salida
Filtrar arroyos Java primitivos Entrada de datos/Salida de datos
Flujos de personajes Personajes y Instrumentos de cuerda Lector/Escritor
Objeto arroyos Objetos Flujo de entrada de objeto/Flujo de salida de objeto
13.1 Java Arroyo Clases 341

Aunque los flujos se pueden utilizar en muchos tipos diferentes de conexiones seriales, la mayoría de los
ejemplos de este capítulo utilizan flujos de archivos, porque estos se pueden usar fácilmente para demostrar tanto la
entrada como la salida.

13.2 Byte Arroyos

Los flujos de bytes están representados por una jerarquía de herencia que tiene el InputStream abstracto y Flujo de
salida clases en el arriba. Estos abstracto clases tener algún comportamiento implementado por concreto subclases.
Figura 13.2 muestra alguno de el métodos principales de las clases InputStream y OutputStream.
Los OutputStreams escriben bytes sin procesar en su destino. El método “ write ” toma una matriz de bytes o un
int como parámetro. En el último caso, aunque el parámetro se escribe como un int, solo el byte de orden inferior del
int se escribe en el flujo de salida; los otros tres se ignoran. El método “ flush ” garantiza que cualquier byte
almacenado en búfer producción datos es escrito a es destino (cierre el arroyo voluntad también causa para
vaciarlo). Cuando se utiliza un InputStream, hay una " lectura " método que devuelve un int (nuevamente, solo se usa
realmente el byte de orden inferior) y otros métodos de " lectura " que devuelven los datos en matrices de bytes
pasadas como parámetros. Estos métodos que leen matrices también devuelven un int, que contiene la cantidad de
bytes leídos o − 1 si hay No más bytes en el aporte arroyo. El " disponible " método Estimaciones cómo Muchos
bytes estarán disponibles para la próxima operación de “ lectura ” en la secuencia.

Object

Flujo de entrada Flujo de salida

disponible() : int cerrar() cerrar() vaciar()


leer() : int leer(byte[]) : escribir(byte[])
entero escribir(byte[] b, entero
leer(byte[] b, entero compensar, entero desplazamiento, longitud int)
longitud) : entero escribir(int)

Higo. 13.2 El principal métodos del Resumen de InputStream y OutputStream clases


342 13 Input and Output
Streams
13.2.1 Transmisión Bytes a y de Archivos

FileOutputStream es una subclase concreta de OutputStream y se puede utilizar para escribir bytes a archivos. El
constructor mostrado aquí crea el archivo a pesar de todo de si a El archivo con ese nombre ya existe (pero no creará
carpetas).

Alternativamente, nosotros poder añadir un existente archivo por paso “ cierto ” como a segundo
argumento de parámetro.

Aunque la “ escritura ” Los métodos solo funcionan a nivel de byte, se pueden usar para escribir caracteres
ASCII en el flujo de salida ya que solo requieren un byte para representar el carácter, por ejemplo,

Sin embargo, normalmente no utilizaríamos FileOutputStreams para datos de caracteres. Solo se utilizan cuando
queremos escribir datos a nivel de bytes en un archivo, como datos de imágenes. Incluso en ese caso, existen
secuencias de nivel superior que probablemente serían mejores opciones. A medida que Ya veremos más tarde, La
razón principal de Necesitando a Conozca acerca de los arroyos de bajo nivel es eso ellos apoyo el funcionalidad de
más alto nivel arroyos. Dado este, El siguiente ejemplo debe tomarse como un esquema básico de sintaxis en lugar de
una buena práctica. para escribiendo personajes a archivos. Él hace, sin embargo, cubrir alguno centro aspectos para
manejar flujos de salida que se aplican a cualquier tipo de flujo:

1. Muchas operaciones en transmisiones generan una excepción [Link], por lo que esto debe
manejarse.
2. Las operaciones de archivo arrojan la excepción [Link], por lo que esto también debe
manejarse. Desde este es a subclase de Excepción IO, él debe ser manejado primero si Hay más de un bloque "
captura " .
3. Los streams siempre deben cerrarse cuando hayas terminado de usarlos. La mejor manera de hacerlo es usar el
comando “ try-with-resources ”. construcción, que garantiza que la recursos son cerrado si un excepción ocurre.
Este requiere el código eso abre la secuencia que se agregará al “ try ” .
4. Si un flujo de salida no se vacía ni se cierra, no hay garantía de que se escriban datos.

Aquí es el lleno clase eso escribe alguno individual personajes (como bytes) a a archivo:
13.2 Byte 343
Streams

Si ejecuta este ejemplo, que no incluye una ruta de archivo, se creará el archivo en el por defecto carpeta, cual en
Eclipse voluntad ser el proyecto carpeta. Si tú Haga clic derecho en el proyecto para obtener el menú emergente y
luego seleccione " Actualizar " . Debería ver el nombre del archivo de texto creado aparecer en la ventana del
344 13 Input and Output
Streams
Explorador de paquetes. Si hace doble clic en el archivo, Eclipse lo abrirá en una ventana del editor.
Teniendo creado el archivo usando a Flujo de salida de archivos nosotros poder leer el datos atrás en un programa
que utiliza un FileInputStream. FileInputStream es una subclase concreta de InputStream y poder ser usado a leer
bytes de archivos. Uno de el constructores toma el nombre de un archivo como parámetro.
13.2 Byte 345
Streams
Desde el “ disponible ” El método devuelve el número de bytes que quedan en el flujo, podemos usar este
método para controlar un bucle “ while ” que lee bytes (usando el método “ read ” que lee un byte a la vez)
del flujo de entrada.

Alternativamente, nosotros podría leer el arroyo datos directamente en a byte formación.

Aquí es a completo programa a leer de un aporte archivo arroyo. Este ejemplo Utiliza un bucle “ while ” , pero
también podría leer directamente en una matriz de bytes. Convierte cada int devuelto en un char para imprimirlo en la
consola.
346 13 Input and Output
Streams

13.3 Filtrar Arroyos

La idea básica de un flujo de filtro es que envuelve la funcionalidad básica de otro flujo de nivel inferior y luego
puede transformar los datos y/o proporcionar funcionalidad adicional (Fig. 13.3 ).
Un ejemplo útil de un flujo de filtrado es el que envuelve un flujo de bytes para trabajar con tipos de datos
primitivos de Java. Las clases concretas que hacen esto son DataInput-Stream y Flujo de salida de datos. Porque estos
clases requerir el servicios de flujos de bytes de nivel inferior, sus constructores requieren que estos otros flujos se
pasen como parámetros. En el siguiente ejemplo, a Flujo de salida de archivos objeto (a byte arroyo) se crea y
entonces aprobado a el constructor de a Flujo de salida de datos objeto. El El flujo de filtro utilizará los servicios del
flujo de bytes para ayudar a implementar sus métodos.

Nosotros poder hacer este bastante más conciso (y fácil a usar en a “ try-with-resources ” (construcción)
envolviendo el primer constructor dentro del otro y usando “ var ” en lugar de “ DataOutputStream ” :

filtrar arroyo
byte
stream

Higo. 13.3 Filtrar Los arroyos se envuelven nivel inferior flujos de bytes
13.2 Byte 347
Streams
Las clases concretas DataInputStream y DataOutputStream heredan de las clases FilterStream pero también
implementan las interfaces DataInput y Data Output respectivamente (Fig. 13.4 ). Estos Las interfaces definen la leer
o escribir métodos para primitivas Java que implementan las clases (Fig. 13.4 muestra un subconjunto de estos).
La clase DataOutputStream tiene métodos para escribir distintos tipos de primitivos de Java en el flujo. Por
ejemplo, podríamos querer escribir los campos de un Curso objeto a a archivo. Partida aparte el módulo datos, a curso
incluye es nombre (una cadena), el número de días de duración (un entero) y el precio (un doble). El siguiente
ejemplo muestra cómo escribiríamos estos tipos de datos en un DataOutputStream. El método “ writeUTF ” escribe
una cadena en el flujo, el método “ writeInt ” escribe un entero y “ writeDouble ” escribe un doble. Existen métodos
similares para escribir todos los tipos primitivos de Java.

InputStream OutputStream

FilterInputStream FilterOutputStream

readDouble() writeDouble(double)
readFloat() writeFloat(float)
DataInputStream DataOutputStream
readInt() writeInt(int)
readUTF() writeUTF(String)
etc.. etc..

«interface» «interface»
Higo. 13.4 Flujo de entrada de datos y Flujo de salida de datos heredar de filtroDataOutput
DataInput arroyos y Implementar
interfaces que declaren sus métodos de lectura y escritura para primitivas Java.
13.3 Filter 347
Streams

Si abre el archivo “ [Link] ” archivo en una ventana del editor después de ejecutar este código, debe ser capaz a
ver eso él es principalmente no legible para humanos bytes, con el excepción de la cadena, que aparecerá como
caracteres legibles.
En a vena similar, una DataInputStream sería necesidad a envoltura un Objeto InputStream y tiene la función “
read ” apropiada métodos para todos los tipos primitivos de Java. El siguiente fragmento de código podría leer
datos del archivo creado por el código en el anterior ejemplo. El importante cosa aquí es eso el datos debe ser leer
atrás exactamente en el orden correcto porque los diferentes tipos de datos utilizan diferentes representaciones a nivel
de byte. Por lo tanto, para leer desde un DataInputStream, debe conocer los tipos de datos y secuencias exactos que
está intentando leer desde el flujo.
348 13 Input and Output
Streams

Si el datos es exitosamente leer, el consola producción debería aparecer como este:

El arroyo biblioteca también incluye a Archivo de acceso aleatorio clase, cual combina la funcionalidad de
DataInputStreams y DataOutputStreams en un único objeto de manejo de archivos. Además de implementar los
métodos de DataInput y DataOutput interfaces, él proporciona métodos para gerente a archivo puntero cual poder se
puede configurar para leer o escribir en cualquier posición del archivo. Donde los tipos primitivos necesitan ser
configurados regularmente ambos escrito y leer, usando a soltero Archivo de acceso aleatorio quería ser a Un enfoque
mejor que separar los objetos de archivo de entrada y salida.
13.3 Filter 349
Streams
Mesa 13.2 Transacción Datos para el
ejercicio 13.1 Account Amount Transaction Date
number type
1009876 145.50 DR 2020-12-03
1876253 1267.00 CR 2020-11-30
1192873 45.30 CR 2021-02-15

Ejercicio 13.1
Mesa 13.2 muestra alguno datos acerca de financiero actas.
Crea una clase con un “ main ” método que escribe estos datos en un archivo. Supongamos que el número de
cuenta se debe escribir como un entero y el monto de la transacción como un doble. El transacción tipo podría ser
escrito como a Cadena o dos separado caracteres. Utilizar a Fecha local a representar el fecha en el programa. Desde
allá es No método en un DataOutputStream para escribir una LocalDate, escribe la fecha como una cadena en el
archivo.
Cuando tú tener exitosamente escrito el datos a a archivo, crear otro clase con un “ principal ” método eso poder
leer el datos de el archivo y mostrar él, adecuadamente formateado en la consola. Utilice un DateTimeFormatter para
analizar la cadena de fecha y convertirla en un objeto LocalDate.

13.4 Lectores y Escritores

Lectores y Escritores son en a separado jerarquía de el arroyo clases eso nosotros Hemos visto hasta ahora. Tienen un
conjunto similar de métodos pero manejan caracteres y cadenas, no bytes o primitivos (Fig. 13.5 ). Reader y Writer
son clases abstractas con algún comportamiento implementado por subclases. Estos son los flujos preferidos para usar
al leer y escribir datos de caracteres.

Object
Lector Escritor

listo() : booleano cerrar() flush()


close() : void leer() : escribir(char[])
int leer(char[]) : int escribir(int)
saltar() : largo escribir(String)

Higo. 13.5 El Lector y Escritor clases, y alguno de su métodos


350 Inde
x
13.4.1

Common questions

Con tecnología de IA

Una ArrayList en Java ofrece varias ventajas sobre una matriz simple. A diferencia de una matriz, que tiene un tamaño fijo, una ArrayList es redimensionable dinámicamente, lo que significa que se expandirá automáticamente cuando se necesite espacio adicional al agregar nuevos elementos . Además, proporciona métodos útiles como 'add' para añadir elementos, y 'get' para acceder a ellos mediante índices, lo que no está disponible en matrices simples . Otra ventaja es que una ArrayList se integra fácilmente en el Marco de Colecciones de Java, permitiendo la manipulación fácil de los datos mediante streams y operaciones de colección avanzadas . Sin embargo, es importante considerar que las ArrayLists pueden no ser tan eficientes en términos de tiempo o memoria como las matrices simples en algunas operaciones específicas debido a la necesidad de realocaciones y copias internas de matrices .

Una ArrayList y una LinkedList en Java manejan la eliminación de elementos de manera distinta debido a sus diferencias estructurales. En una ArrayList, la eliminación de un elemento se basa en el índice, y el proceso implica el desplazamiento de todos los elementos subsiguientes para llenar el vacío dejado por el elemento eliminado, lo cual puede ser costoso en términos de rendimiento . Por otro lado, una LinkedList permite la eliminación de elementos desde el comienzo o el final de la lista sin necesidad de reestructurar toda la colección, lo que puede ser más eficiente cuando se realizan frecuentemente estas operaciones . Además, debido a su estructura de nodos enlazados, una LinkedList puede eliminar elementos en ubicaciones arbitrarias más eficientemente que una ArrayList, siempre que el nodo en cuestión sea localizado primero .

Antes de la introducción de genéricos en las colecciones de Java, las colecciones podían almacenar cualquier tipo de objeto, ya que usaban referencias de tipo Object, lo que no proporcionaba seguridad de tipo. Esto generaba riesgos de excepciones de tiempo de ejecución cuando se recuperaban y se intentaba manipular objetos de un tipo no esperado, obligando a los desarrolladores a realizar conversiones explícitas de tipos . Después de la integración de genéricos, las colecciones ofrecen seguridad de tipo al permitir declarar el tipo de elementos que contendrán desde el momento de la creación, lo cual es verificado por el compilador. Esto previene la adición de elementos de tipos incorrectos y elimina la necesidad de conversiones de tipo, mejorando la seguridad de tipo y reduciendo la probabilidad de errores en tiempo de ejecución . Los genéricos permiten a los desarrolladores centrarse más en la lógica del negocio en lugar de la gestión de tipos, mejorando la robustez y mantenibilidad del código .

Los streams de filtro en Java están diseñados para agregar funcionalidad adicional a los byte streams subyacentes. Un stream de filtro envuelve un stream de byte y puede transformar los datos o proporcionar operaciones adicionales como la transformación de datos primitivos a través de DataInputStream y DataOutputStream, los cuales aceptan un byte stream como entrada . Los byte streams, por otro lado, son más básicos y operan directamente sobre bytes y matrices de bytes, satisfaciendo las necesidades básicas de transferencia de datos sin las funcionalidades adicionales que los streams de filtro pueden proporcionar. El diseño de los streams de filtro en torno a streams de bytes subyacentes les permite reutilizar la funcionalidad básica mientras agregan capas de procesamiento adicionales .

Los genéricos en las colecciones de Java proporcionan seguridad de tipo al permitir especificar el tipo de objetos que una colección puede contener al momento de su creación. Esto evita errores de tipo en tiempo de compilación, garantizando que solo el tipo especificado de objeto pueda ser almacenado en la colección . Antes de la introducción de genéricos, las colecciones podían contener cualquier tipo de referencia de objeto, lo que podía llevar a excepciones de tiempo de ejecución al intentar acceder a un objeto en una colección con un tipo no esperado. Con los genéricos, el compilador puede advertir sobre peligros potenciales, ya que las colecciones bien tipificadas aseguran que los elementos recuperados y añadidos coincidan con el tipo especificado . Además, el uso de genéricos elimina la necesidad de realizar conversiones explícitas de tipos al trabajar con los objetos de la colección, haciendo que el código sea más legible y menos propenso a errores .

Manejar las excepciones correctamente al trabajar con FileInputStream en Java es crucial para asegurar la robustez y fiabilidad de un programa. Los FileInputStream pueden lanzar excepciones de E/S, como IOException, si ocurren problemas al abrir, cerrar o leer de un archivo. Éstas deben ser manejadas adecuadamente para evitar que el programa falle abruptamente . Además, los recursos como FileInputStream deben cerrarse siempre después de su utilización para liberar recursos del sistema; utilizar try-with-resources garantiza esto incluso si se lanza una excepción durante la operación, mejorando la gestión de recursos y minimizando el riesgo de fugas . No manejar las excepciones apropiadamente podría llevar a corrupción de datos o pérdida de datos si el flujo se interrumpe inesperadamente .

El método 'filter' de la API de Streams en Java se utiliza para modificar colecciones al crear un nuevo stream que contiene solo aquellos elementos que cumplen con un predicado específico. Esta operación intermedia evalúa cada elemento de la colección original y aplica un predicado, que es una función que devuelve un booleano, para determinar si el elemento debe incluirse en el stream resultante . Este enfoque permite realizar operaciones de filtrado y transformación de manera declarativa y en paralelo, mejorando la legibilidad y potencialmente el rendimiento comparado con enfoques iterativos tradicionales . Al finalizar, se utiliza una operación terminal como 'collect' para recolectar los elementos filtrados en una nueva colección .

La construcción try-with-resources en Java se utiliza para gestionar automáticamente el cierre de recursos, como streams y conexiones de bases de datos, eliminando la necesidad de cerrar manualmente los recursos en un bloque finally. Un stream abierto dentro de este bloque se cerrará automáticamente al finalizar, incluso si ocurre una excepción . Esto asegura que los recursos se liberen apropiadamente, previniendo fugas de recursos y garantizando que el flujo de salida sea vaciado y cerrado, lo que es crucial para que los datos se escriban correctamente . Al poner un recurso dentro de un try-with-resources, se especifica el código responsable de abrir el recurso, y automáticamente se gestiona su ciclo de vida dentro de ese bloque .

La diferencia fundamental en el rendimiento entre una LinkedList y una ArrayList cuando se trata de modificaciones frecuentes en Java está relacionada con su estructura interna. Una LinkedList es más eficiente para modificaciones frecuentes debido a su implementación mediante nodos enlazados, lo que permite actualizaciones rápidas en el inicio o fin de la lista y al insertar o eliminar elementos, ya que no requiere el desplazamiento de otros elementos . Por otro lado, una ArrayList necesita reestructurar su contenido al insertar o eliminar elementos, especialmente cuando se realizan estas operaciones en el medio de la lista, lo cual puede resultar en un alto costo de rendimiento por el desplazamiento de múltiples elementos y la posible redimensión de la matriz .

Utilizar streams para manipular colecciones en Java representa un paradigma de programación más funcional, lo cual tiene varias implicaciones. Los streams permiten a los desarrolladores operar sobre colecciones de datos de manera declarativa, especificando qué se quiere hacer sin detallar el cómo implementarlo, lo que mejora la legibilidad y expresividad del código . Además, al separar las operaciones de datos de sus implementaciones, el enfoque de streams permite optimizaciones internas, como la ejecución en paralelo y el uso eficiente de múltiples procesadores, lo que puede mejorar el rendimiento de las aplicaciones . Esto también habilita a los desarrolladores para emplear técnicas funcionales como lambdas y referencias a métodos, promoviendo un estilo más funcional en Java. Sin embargo, este enfoque requiere un cambio conceptual hacia el uso de operaciones inmutables y evita cambios de estado durante las operaciones de flujo, lo que puede ser un desafío para los desarrolladores acostumbrados a paradigmas de programación más imperativos .

También podría gustarte