Jak wiesz, nasze nawyki są drugą naturą. A kiedy już przyzwyczaisz się do pisania
for (int i = 0; i <......)
, żadna część ciebie nie będzie chciała ponownie uczyć się tego konstruktu (zwłaszcza, że jest on dość prosty i zrozumiały). Jednak pętle są często wielokrotnie używane do wykonywania tych samych podstawowych operacji, a powtarzanie jest czymś, czego bardzo chcielibyśmy się pozbyć. Dzięki Javie 8 firma Oracle postanowiła nam w tym pomóc. Poniżej znajduje się 10 najlepszych metod zbierania, które pozwolą Ci zaoszczędzić mnóstwo czasu i kodu.
1. Iterable.forEach(akcja Consumer <? Super T>)
Nazwa mówi sama za siebie. Iteruje po kolekcji przekazanej jako argument i wykonuje wyrażenie lambda akcji dla każdego z jej elementów.
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(Predicate<? super E> filter)
Ponownie, nic trudnego tutaj. Metoda iteruje po kolekcji i usuwa wszystkie pasujące elementyfilter
.
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 + " "));
W jednym wierszu usuwamy z listy wszystkie liczby większe niż 5.
3. Map.forEach(Akcja BiConsumer <? super K, ? super V>)
MetodaforEach
działa nie tylko dla klas, które implementują Collection
interfejs, ale także dla 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 (klawisz K, BiFunction <? Super K, ? Super V, ? Extends V> remappingFunction)
Wygląda trochę bardziej onieśmielająco, ale w rzeczywistości jest prosty, jak wszystkie poprzednie. Ta metoda ustawiakey
wartość równą wynikowi wykonania mappingFunction
. Na przykład:
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
Autor „Thinking in Java” jest zdecydowanie spoko! :)
5. Map.computeIfAbsent(klawisz K, funkcja <? super K, ? rozszerza V> mappingFunction)
Ta metoda doda nowy element doMap
, ale tylko wtedy, gdy nie ma jeszcze elementu z tym kluczem. Przypisana wartość będzie wynikiem wykonania mappingFunction
. Jeśli element z kluczem już istnieje, nie zostanie nadpisany. Po prostu pozostanie tak, jak jest. Wróćmy do naszych książek i wypróbujmy nową metodę:
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));
Oto nasze mappingFunction
:
public static String getHarryPotterAuthor() {
return "Joanne Rowling";
}
A oto nowa książka:
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(klawisz K, BiFunction<?super K, ?super V,?extenss V>remappingFunction)
Tutaj mamy taką samą zasadę jakMap.compute()
, ale obliczenia są wykonywane tylko wtedy, gdy element z key
już istnieje.
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));
Pierwsze wywołanie funkcji nie przyniosło żadnych zmian, ponieważ w naszym Map
. Ale w drugim wezwaniu program zmienił autora książki „Bracia Karamazow” na Aleksandra Puszkina. Wyjście:
_________________
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 (klucz obiektu, V defaultValue)
Ta metoda zwraca wartość odpowiadającąkey
. Jeśli klucz nie istnieje, zwraca wartość domyślną.
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);
Jest to bardzo wygodne:
Unknown author
8. Map.merge (klawisz K, wartość V, BiFunction <? super V, ? super V, ? rozszerza V> remappingFunction)
Nawet nie zawracałem sobie głowy obliczeniem, ile linii kodu zaoszczędzi ci ta metoda.- Jeśli
key
nie istnieje w twoimMap
, lub jeślivalue
dla tego klucza jestnull
, to metoda dodaje przekazanąkey-value
parę doMap
. - Jeśli
key
istnieje i jegovalue != null
, to metoda zmienia swoją wartość na wynik wykonaniaremappingFunction
. - Jeśli
remappingFunction
zwracanull
, tokey
jest usuwany z kolekcji.
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));
Wyjście:
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
*przepraszam, Bruce*
9. Map.putIfAbsent(klawisz K, wartość V)
Wcześniej, aby dodać parę doMap
, jeśli jeszcze jej tam nie było, należało wykonać następujące czynności:
Map <String, String> map = new HashMap<>();
if (map.get("Lord of the Rings") == null)
map.put("Lord of the Rings", "John Tolkien");
Teraz wszystko stało się znacznie łatwiejsze:
Map<String, String> map = new HashMap<>();
map.putIfAbsent("Lord of the Rings", "John Tolkien");
10. Map.replace i Map.replaceAll()
Nie mniej ważny.Map.replace(K key, V newValue)
zastępujekey
wartość przeznewValue
, jeśli taki klucz istnieje. Jeśli nie, nic się nie dzieje.Map.replace(K key, V oldValue, V newValue)
robi to samo, ale tylko wtedy, gdy bieżąca wartość forkey
jest równaoldValue
.Map.replaceAll(BiFunction<? super K, ? super V, ? extends V> function)
zastępuje każdyvalue
wynikiem funkcji.
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
To nie zadziałało! Obecna wartość klucza „Bracia Karamazow” to „Fiodor Dostojewski”, a nie „Bruce Eckel”, więc nic się nie zmieniło.
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
Z łatwością zmieniliśmy wartości dla całości Map
bez żadnych skomplikowanych konstrukcji! PS Przyzwyczajenie się do nowego jest zawsze trudne, ale te zmiany są naprawdę dobre. W każdym razie niektóre części mojego kodu zdecydowanie mniej przypominają spaghetti niż wcześniej :) Powodzenia w nauce!
GO TO FULL VERSION