12 найпоширеніших способів використання Java Streams
Джерело: Dev.to Java Streams API вперше з'явився в Java 8. Його мета - надати компактніший спосіб виконання спільних операцій з колекціями об'єктів. Також Java Streams API може використовуватись для реалізації складних алгоритмів. У цій статті ми поговоримо про поширені випадки використання Java Streams. Для початку прояснимо деякі основи:-
stream() – створює потік (Stream) з колекції.
-
collect() - Збирає потік в об'єкт. Об'єкт може бути колекцією, примітивом або класом користувача.
-
Collectors - клас, який надає (безліч) статичних методів для збору потоків.
1. Фільтрування (Filtering)
-
Використовується для видалення значень із колекції (Collection) на основі умови.
-
Для фільтрації елементів колекції з урахуванням умови використовується метод filter() . Зберігаються лише елементи, що збігаються.
List<Integer> evenNumbers = originalList.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
2. Попередня обробка (Preprocessing)
-
Корисна, коли кожне значення в колекції потрібно змінити на місці.
-
Метод map() використовується для застосування функції кожного елемента колекції та повернення нової колекції обчислених значень.
List<Integer> squares = originalList.stream()
.map(n -> n * n)
.collect(Collectors.toList());
3. Перетворення (Conversion)
-
Корисно, коли ми хочемо перетворити колекцію на іншу колекцію.
-
Є кілька способів досягти цього.
Приклад 1. Створити Map із Lists.
Перетворення списку рядків на карту рядків та довжини.Map<String, Integer> wordLengths = words.stream()
.collect(Collectors.toMap(
word -> word,
word -> word.length()));
Приклад 2. Перетворення списку (list) на набори (sets).
Це найпоширеніший варіант використання для видалення дублікатів. Крім того, якщо ми хочемо помістити елементи назад до списку, ми можемо двічі використовувати методи stream() та collect() . Наприклад, давайте перетворимо список рядків на список унікальних рядків:// if we want to collect to a set
Set<String> uniqueWords = words.stream()
.collect(Collectors.toSet());
// OR
// if we want to start and end as a list
List<String> uniqueWords = words.stream()
.collect(Collectors.toSet()).stream().collect(Collectors.toList());
Приклад 3. Перетворення списку товарів на список їх назв. (Flattening - Вирівнювання)
List<String> productNames = products.stream()
.map(product -> product.getName())
.collect(Collectors.toList());
4. Скорочення (Reduction)
-
Скорочує Collection до значення.
-
Метод reduce() використовується для застосування функції до кожного елемента колекції та повернення одного значення.
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b);
5. Угруповання (Grouping)
-
Групує елементи Collection за заданою умовою.
-
Для групи елементів Collection за умовою використовується метод Collectors.groupingBy() .
Map<String, List<Product>> productsByCategory = products.stream()
.collect(Collectors.groupingBy(product -> product.getCategory()));
6. Пошук (Finding)
-
Шукає перший або будь-який елемент Collection, який відповідає умові.
-
Для пошуку використовуються методи findFirst() та findAny() .
Optional<String> firstLongWord = words.stream()
.filter(word -> word.length() > 5)
.findFirst();
// Note that findFirst() and findAny() methods return Optional<T> objects.
7. Сортування (Sorting)
-
Сортує елементи колекції.
-
Для сортування використовується метод sorted() .
List<Integer> topK = numbers.stream()
.sorted()
.limit(k)
.collect(Collectors.toList());
8. Поділ (Partitioning)
-
Розділяє елементи Collection за заданою умовою.
-
Для розділення елементів використовується метод Collectors.partitioningBy() .
Map<Boolean, List<Student>> passingFailing = students
.stream()
.collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
9. Підрахунок (Counting)
-
Підраховує кількість елементів, що відповідають умові.
-
Для підрахунку кількості елементів, що відповідають умові, використовується метод count() .
long count = words.stream()
.filter(word -> word.length() > 5)
.count();
10. Діапазон (Range)
-
Створює діапазон значень.
-
Для створення діапазону значень використовують метод range() .
int[] numbers = IntStream.range(0, 10).toArray();
11. Відповідність (Matching)
-
Зіставляє елементи колекції з предикатом (умовою).
-
Для зіставлення елементів колекції з предикатом і повернення логічного значення використовуються такі методи, як anyMatch() , allMatch() і noneMatch() .
// true when all elements match the predicate
boolean allMatch = products.stream()
.allMatch(product -> product.getPrice() > 10);
// true when any element matches the predicate
boolean anyMatch = products.stream()
.anyMatch(product -> product.getPrice() > 10);
// true when no elements match the predicate
boolean noneMatch = products.stream()
.noneMatch(product -> product.getPrice() > 10);
12. Приєднання (Joining)
-
Об'єднує елементи колекції в рядок.
-
Для об'єднання елементів колекції в рядок використовується метод Collectors.joining() .
String joinedWords = words.stream()
.collect(Collectors.joining(" "));
Ось і все для спільних сценаріїв. Є й інші менш поширені сценарії, які можна вивчити самостійно:
- Паралельні потоки (Parallel Streams);
- Статистика;
- Користувальницькі колектори (Custom Collectors).
Переваги потоків
-
Більш компактний код — зменшує обсяг коду, який буде необхідний обробки колекції.
-
Менше проміжних змінних. Проміжні змінні можуть бути причиною помилок. Чим їх менше, тим простіше уникнути несподіваних помилок.
-
Інтуїтивно зрозумілий код. Деякі розробники не погодяться, що потоки більш інтуїтивно зрозумілі, ніж інші методи. Однак, як тільки ми звикнемо до них, вони стануть набагато інтуїтивнішими, ніж інші методи.
Як оцінити виділення пам'яті об'єкта в Java
Джерело: DZone У цій статті показано три найбільш відомі способи оцінки виділення пам'яті об'єкта в Java.Оцінка пам'яті за допомогою Profiler
Найпростіший спосіб оцінити пам'ять деяких об'єктів - заглянути прямо в пам'ять JVM за допомогою профілювача, такого як Visual VM . Проблема з цим підходом полягає в тому, що вам потрібно підключитися до працюючої JVM, що може бути неможливо для виробничих середовищ з міркувань безпеки.Оцінка пам'яті за допомогою інструментів
Інший спосіб оцінити виділену пам'ять для цього об'єкта - використовувати Instruments. Простіше кажучи, нам потрібно створити клас та скомпілювати його в JAR. Після створення JAR ми маємо виконати нашу JVM разом із цим JAR. Детально про цей спосіб можна дізнатися тут . Недоліком тут є необхідність додавання певного jar-файлу в JVM, що може бути неприйнятним для виробництва через проблеми з безпекою або пов'язані з цим проблеми.Оцінка пам'яті за допомогою JOL Library
Як ще один варіант, ми можемо використовувати JOL Library . Це дуже потужна бібліотека, яка може надати детальну оцінку ваги об'єкта та пам'яті, виділеної екземпляром об'єкта. Щоб використати бібліотеку, нам потрібно додати залежність:<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
Після цього ми можемо використовувати її так:
out.println(GraphLayout.parseInstance(myObject).totalSize() / 1024000d + " MB")
ObjectSizeCalculator з архіву Twitter
У відкритому репозиторії Twitter GitHub є клас інструменту ObjectSizeCalculator , який може оцінити виділену пам'ять для екземпляра об'єкта. Його використання не займає багато пам'яті чи часу. Процес оцінки займає секунди, навіть великих об'єктів. Використання цього класу досить просто:ObjectSizeCalculator.getObjectSize(address)
Я рекомендую цей спосіб, але майте на увазі, що він підтримується лише Java Hotspot, OpenJDK та TwitterJDK.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ