![Спрете да пишете цикли! 10 най-добри практики за работа с колекции в Java 8 - 1]()
Както знаете, нашите навици са втора природа. И след като свикнете да пишете
for (int i = 0; i <......)
, никоя част от вас не иска да учи отново тази конструкция (особено след като е доста проста и разбираема). Въпреки това, циклите често се използват многократно за извършване на едни и същи основни операции и повторението е нещо, от което много бихме искали да се отървем. С Java 8 Oracle реши да ни помогне да направим това. По-долу са 10-те най-добри метода за събиране, които ще ви спестят много време и code.
1. Iterable.forEach(Consumer <? Super T> действие)
Името говори само за себе си. Той итерира колекцията, предадена като аргумент, и изпълнява действието ламбда израз за всеки от нейните елементи.
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(предикат<? супер E> филтър)
Отново няма нищо трудно тук. Методът итерира колекцията и премахва всички елементи, които съвпадат
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 + " "));
В един ред премахваме от списъка всички числа, по-големи от 5.
3. Map.forEach(BiConsumer <? super K, ? super V> действие)
Методът
forEach
работи не само за класове, които имплементират интерфейса
Collection
, но и за
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 (клавиш K, BiFunction<? Super K,? Super V,? Extends V> remappingFunction)
Изглежда малко по-страшно, но всъщност просто, като всички предишни. Този метод задава
key
стойност равна на резултата от изпълнението
mappingFunction
. Например:
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
Authorът на "Thinking in Java" определено е готин! :)
5. Map.computeIfAbsent(клавиш K, функция <? super K, ? разширява V> mappingFunction)
Този метод ще добави нов елемент към
Map
, но само ако вече няма елемент с този ключ. Присвоената стойност ще бъде резултатът от изпълнението на
mappingFunction
. Ако елемент с ключ вече съществува, той няма да бъде презаписан. Просто ще си остане Howто е. Нека се върнем към нашите книги и да опитаме нов метод:
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));
Ето го нашия
mappingFunction
:
public static String getHarryPotterAuthor() {
return "Joanne Rowling";
}
А ето и новата книга:
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(ключ K, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
Тук имаме същия принцип като
Map.compute()
, но изчисленията се извършват само ако елемент с
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));
Първото извикване на функцията не направи промени, защото в нашия няма книга със заглавие "Евгений Онегин"
Map
. Но във второто обаждане програмата промени автора на книгата "Братя Карамазови" на Александър Пушкин. Изход:
_________________
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(обектен ключ, V defaultValue)
Този метод връща стойността, съответстваща на
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");
String igor = books.getOrDefault("The Tale of Igor's Campaign", "Unknown author");
System.out.println(igor);
Това е много удобно:
Unknown author
8. Map.merge(ключ K, V стойност, BiFunction<? super V, ? super V, ? extends V> remappingFunction)
Дори не си направих труда да изчисля колко реда code ще ви спести този метод.
- Ако
key
не съществува във вашия Map
or ако value
за този ключ е null
, тогава методът добавя предадената key-value
двойка към Map
.
- Ако
key
съществува и е value != null
, тогава методът променя стойността си на резултата от изпълнението remappingFunction
.
- Ако
remappingFunction
се върне null
, тогава 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.merge("Thinking in Java", "Bruce Eckel", (a, b) -> b + " and some coauthor");
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 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
*съжалявам, Брус*
9. Map.putIfAbsent(ключ K, V стойност)
Преди, за да добавите чифт към
Map
, ако все още не е бил там, трябваше да направите следното:
Map <String, String> map = new HashMap<>();
if (map.get("Lord of the Rings") == null)
map.put("Lord of the Rings", "John Tolkien");
Сега всичко стана много по-лесно:
Map<String, String> map = new HashMap<>();
map.putIfAbsent("Lord of the Rings", "John Tolkien");
10. Map.replace и Map.replaceAll()
Не на последно място.
Map.replace(K key, V newValue)
заменя key
стойността на с newValue
, ако съществува такъв ключ. Ако не, нищо не се случва.
Map.replace(K key, V oldValue, V newValue)
прави същото, но само ако текущата стойност за key
е равна на oldValue
.
Map.replaceAll(BiFunction<? super K, ? super V, ? extends V> function)
замества всеки value
с резултат от функция.
Например:
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
Не се получи! Текущата стойност за ключа "Братя Карамазови" е "Фьодор Достоевски", а не "Брус Екел", така че нищо не се е променило.
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
Лесно променихме стойностите за цялото
Map
без ниHowви сложни конструкции! PS Свикването с новото винаги е трудно, но тези промени са наистина добри. Във всеки случай, някои части от codeа ми определено не прorчат на спагети от преди :) Успех в ученето!
GO TO FULL VERSION