![¡Deja de escribir bucles! Las 10 mejores prácticas para trabajar con colecciones en Java 8 - 1]()
Como saben, nuestros hábitos son una segunda naturaleza. Y una vez que te acostumbras a escribir
for (int i = 0; i <......)
, ninguna parte de ti quiere tener que volver a aprender esta construcción (especialmente porque es bastante simple y comprensible). Sin embargo, los bucles a menudo se usan repetidamente para realizar las mismas operaciones básicas, y la repetición es algo de lo que nos gustaría deshacernos. Con Java 8, Oracle ha decidido ayudarnos a hacer esto. A continuación se encuentran los 10 mejores métodos de recopilación que le ahorrarán una tonelada de tiempo y código.
1. Iterable.forEach (Consumidor <? Super T> acción)
El nombre habla por sí mismo. Itera sobre la colección pasada como argumento y ejecuta la expresión action lambda para cada uno de sus elementos.
List <Integer> numbers = new ArrayList<>(Arrays.asList(1,2,3,4,5,6,7));
numbers.forEach(s -> System.out.print(s + " "));
1 2 3 4 5 6 7
2. Collection.removeIf(predicado<? filtro super E>)
Una vez más, nada difícil aquí. El método itera sobre la colección y elimina cualquier elemento que coincida
filter
.
List <Integer> numbers = new ArrayList<>(Arrays.asList(1,2,3,4,5,6,7));
numbers.removeIf(s -> s > 5);
numbers.forEach(s -> System.out.print(s + " "));
En una sola línea, estamos eliminando de la lista todos los números mayores de 5.
3. Map.forEach(BiConsumer <? super K, ? super V> acción)
El
forEach
método funciona no solo para clases que implementan la
Collection
interfaz, sino también para
Map
.
Map <String, String> books = new HashMap<>();
books.put("War and Peace", "Leo Tolstoy");
books.put("Crime and Punishment", "Fyodor Dostoevsky");
books.put("Thinking in Java", "Bruce Eckel");
books.put("The Brothers Karamazov", "Fyodor Dostoevsky");
books.put("The Lord of the Rings", "John Tolkien");
books.forEach((a,b) -> System.out.println("Book title: " + a + ". Author: "+ b));
Book title: The Brothers Karamazov. Author: Fyodor Dostoevsky
Book title: Thinking in Java. Author: Bruce Eckel
Book title: Crime and Punishment. Author: Fyodor Dostoevsky
Book title: War and Peace. Author: Leo Tolstoy
Book title: Lord of the Rings. Author: John Tolkien
4. Map.compute (tecla K, BiFunction<? Super K,? Super V,? Extends V> función de reasignación)
Parece un poco más intimidante, pero en realidad simple, como todos los anteriores. Este método establece
key
el valor de igual al resultado de la ejecución
mappingFunction
. Por ejemplo:
Map <String, String> books = new HashMap<>();
books.put("War and Peace", "Leo Tolstoy");
books.put("Crime and Punishment", "Fyodor Dostoevsky");
books.put("Thinking in Java", "Bruce Eckel");
books.put("The Brothers Karamazov", "Fyodor Dostoevsky");
books.put("The Lord of the Rings", "John Tolkien");
books.forEach((a,b) -> System.out.println("Book title: " + a + ". Author: "+ b));
books.compute("Thinking in Java", (a,b) -> b + ", cool dude");
System.out.println("_______________________");
books.forEach((a,b) -> System.out.println("Book title: " + a + ". Author: "+ b));
Book title: The Brothers Karamazov. Author: Fyodor Dostoevsky
Book title: Thinking in Java. Author: Bruce Eckel
Book title: Crime and Punishment. Author: Fyodor Dostoevsky
Book title: War and Peace. Author: Leo Tolstoy
Book title: Lord of the Rings. Author: John Tolkien
_______________________
Book title: The Brothers Karamazov. Author: Fyodor Dostoevsky
Book title: Thinking in Java. Author: Bruce Eckel, cool dude
Book title: Crime and Punishment. Author: Fyodor Dostoevsky
Book title: War and Peace. Author: Leo Tolstoy
Book title: Lord of the Rings. Author: John Tolkien
¡El autor de "Pensar en Java" es definitivamente genial! :)
5. Map.computeIfAbsent (tecla K, función <? super K, ? extiende V> función de mapeo)
Este método agregará un nuevo elemento al
Map
, pero solo si aún no tiene un elemento con esa clave. El valor asignado será el resultado de ejecutar el
mappingFunction
. Si ya existe un elemento con la clave, no se sobrescribirá. Simplemente permanecerá como está. Volvamos a nuestros libros y probemos un nuevo método:
Map <String, String> books = new HashMap<>();
books.put("War and Peace", "Leo Tolstoy");
books.put("Crime and Punishment", "Fyodor Dostoevsky");
books.put("Thinking in Java", "Bruce Eckel");
books.put("The Brothers Karamazov", "Fyodor Dostoevsky");
books.put("The Lord of the Rings", "John Tolkien");
books.computeIfAbsent("Harry Potter and the Prisoner of Azkaban", b -> getHarryPotterAuthor());
books.forEach((a,b) -> System.out.println("Book title: " + a + ". Author: "+ b));
Aquí está nuestro
mappingFunction
:
public static String getHarryPotterAuthor() {
return "Joanne Rowling";
}
Y aquí está el nuevo libro:
Book title: The Brothers Karamazov. Author: Fyodor Dostoevsky
Book title: Thinking in Java. Author: Bruce Eckel
Book title: Crime and Punishment. Author: Fyodor Dostoevsky
Book title: War and Peace. Author: Leo Tolstoy
Book title: Harry Potter and the Prisoner of Azkaban. Author: Joanne Rowling
Book title: Lord of the Rings. Author: John Tolkien
6. Map.computeIfPresent(tecla K, BiFunction<? super K, ? super V, ? extiende V> función de reasignación)
Aquí tenemos el mismo principio que
Map.compute()
, pero los cálculos se realizan solo si ya existe un elemento
key
.
Map <String, String> books = new HashMap<>();
books.put("War and Peace", "Leo Tolstoy");
books.put("Crime and Punishment", "Fyodor Dostoevsky");
books.put("Thinking in Java", "Bruce Eckel");
books.put("The Brothers Karamazov", "Fyodor Dostoevsky");
books.put("The Lord of the Rings", "John Tolkien");
books.computeIfPresent("Eugene Onegin", (a,b) -> b = "Alexander Pushkin");
System.out.println("_________________");
books.forEach((a,b) -> System.out.println("Book title: " + a + ". Author: "+ b));
books.computeIfPresent("The Brothers Karamazov", (a,b) -> b = "Alexander Pushkin");
System.out.println("_________________");
books.forEach((a,b) -> System.out.println("Book title: " + a + ". Author: "+ b));
La primera llamada a la función no hizo cambios, porque no hay ningún libro titulado "Eugene Onegin" en nuestro archivo
Map
. Pero en la segunda convocatoria, el programa cambió al autor del libro "Los hermanos Karamazov" a Alexander Pushkin. Producción:
_________________
Book title: The Brothers Karamazov. Author: Fyodor Dostoevsky
Book title: Thinking in Java. Author: Bruce Eckel
Book title: Crime and Punishment. Author: Fyodor Dostoevsky
Book title: War and Peace. Author: Leo Tolstoy
Book title: Lord of the Rings. Author: John Tolkien
_________________
Book title: The Brothers Karamazov. Author: Alexander Pushkin
Book title: Thinking in Java. Author: Bruce Eckel
Book title: Crime and Punishment. Author: Fyodor Dostoevsky
Book title: War and Peace. Author: Leo Tolstoy
Book title: Lord of the Rings. Author: John Tolkien
7. Map.getOrDefault (clave de objeto, valor predeterminado de V)
Este método devuelve el valor correspondiente a
key
. Si la clave no existe, devuelve el valor predeterminado.
Map <String, String> books = new HashMap<>();
books.put("War and Peace", "Leo Tolstoy");
books.put("Crime and Punishment", "Fyodor Dostoevsky");
books.put("Thinking in Java", "Bruce Eckel");
books.put("The Brothers Karamazov", "Fyodor Dostoevsky");
books.put("The Lord of the Rings", "John Tolkien");
String igor = books.getOrDefault("The Tale of Igor's Campaign", "Unknown author");
System.out.println(igor);
Esto es muy conveniente:
Unknown author
8. Map.merge (tecla K, valor V, BiFunction<? super V, ? super V, ? extiende V> función de reasignación)
Ni siquiera me molesté en intentar calcular cuántas líneas de código te ahorrará este método.
- Si
key
no existe en su Map
, o si value
para esta clave es null
, entonces el método agrega el key-value
par pasado al Map
.
- Si
key
existe y es value != null
, entonces el método cambia su valor al resultado de la ejecución remappingFunction
.
- Si
remappingFunction
devuelve null
, key
se elimina de la colección.
Map <String, String> books = new HashMap<>();
books.put("War and Peace", "Leo Tolstoy");
books.put("Crime and Punishment", "Fyodor Dostoevsky");
books.put("Thinking in Java", "Bruce Eckel");
books.put("The Brothers Karamazov", "Fyodor Dostoevsky");
books.put("The Lord of the Rings", "John Tolkien");
books.merge("Thinking in Java", "Bruce Eckel", (a, b) -> b + " and some coauthor");
books.forEach((a, b) -> System.out.println("Title: " + a + ". Author: "+ b));
Producción:
Title: The Brothers Karamazov. Author: Fyodor Dostoevsky
Title: Thinking in Java. Author: Bruce Eckel and some coauthor
Title: Crime and Punishment. Author: Fyodor Dostoevsky
Title: War and Peace. Author: Leo Tolstoy
Title: Lord of the Rings. Author: John Tolkien
*lo siento Bruce*
9. Map.putIfAbsent (clave K, valor V)
Anteriormente, para agregar un par a un
Map
, si aún no estaba allí, tenía que hacer lo siguiente:
Map <String, String> map = new HashMap<>();
if (map.get("Lord of the Rings") == null)
map.put("Lord of the Rings", "John Tolkien");
Ahora todo se ha vuelto mucho más fácil:
Map<String, String> map = new HashMap<>();
map.putIfAbsent("Lord of the Rings", "John Tolkien");
10. Map.replace y Map.replaceAll()
Por último, pero no menos importante.
Map.replace(K key, V newValue)
reemplaza key
el valor de con newValue
, si existe tal clave. Si no, no pasa nada.
Map.replace(K key, V oldValue, V newValue)
hace lo mismo, pero solo si el valor actual de key
es igual a oldValue
.
Map.replaceAll(BiFunction<? super K, ? super V, ? extends V> function)
reemplaza cada uno value
con el resultado de la función.
Por ejemplo:
Map <String, String> books = new HashMap<>();
books.put("War and Peace", "Leo Tolstoy");
books.put("Crime and Punishment", "Fyodor Dostoevsky");
books.put("Thinking in Java", "Bruce Eckel");
books.put("The Brothers Karamazov", "Fyodor Dostoevsky");
books.put("The Lord of the Rings", "John Tolkien");
books.replace("The Brothers Karamazov", "Bruce Eckel", "John Tolkien");
books.forEach((a, b) -> System.out.println("Title: " + a + ". Author: "+ b));
Title: The Brothers Karamazov. Author: Fyodor Dostoevsky
Title: Thinking in Java. Author: Bruce Eckel
Title: Crime and Punishment. Author: Fyodor Dostoevsky
Title: War and Peace. Author: Leo Tolstoy
Title: Lord of the Rings. Author: John Tolkien
¡No funcionó! El valor actual de la clave "Los hermanos Karamazov" es "Fiodor Dostoievski", no "Bruce Eckel", por lo que nada ha cambiado.
Map books = new HashMap<>();
books.put("War and Peace", "Leo Tolstoy");
books.put("Crime and Punishment", "Fyodor Dostoevsky");
books.put("Thinking in Java", "Bruce Eckel");
books.put("The Brothers Karamazov", "Fyodor Dostoevsky");
books.put("The Lord of the Rings", "John Tolkien");
books.replaceAll((a,b) -> getCoolAuthor());
books.forEach((a, b) -> System.out.println("Title: " + a + ". Author: "+ b));
public static String getCoolAuthor() {
return "Cool author";
}
Title: The Brothers Karamazov. Author: Cool author
Title: Thinking in Java. Author: Cool author
Title: Crime and Punishment. Author: Cool author
Title: War and Peace. Author: Cool author
Title: Lord of the Rings. Author: Cool author
¡Cambiamos fácilmente los valores para el conjunto
Map
sin construcciones complicadas! PD: Siempre es difícil acostumbrarse a lo nuevo, pero estos cambios son realmente buenos. En cualquier caso, algunas partes de mi código son definitivamente menos espaguetis que antes :) ¡Buena suerte en el aprendizaje!
GO TO FULL VERSION