Java | Фишки и трюки
7.21K subscribers
182 photos
29 videos
6 files
40 links
Java: примеры кода, интересные фишки и полезные трюки

Купить рекламу: https://telega.in/c/java_tips_and_tricks

✍️По всем вопросам: @Pascal4eg
Download Telegram
⌨️ Полезные стримы. Группировка

Дан список людей с именем и городом проживания. Нужно сгруппировать их по городам.

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

record Person(String name, String city) {}

public class StreamExample {
public static void main(String[] args) {
List<Person> people = List.of(
new Person("Alice", "New York"),
new Person("Bob", "Los Angeles"),
new Person("Charlie", "New York"),
new Person("David", "Los Angeles"),
new Person("Edward", "San Francisco")
);

Map<String, List<Person>> peopleByCity = people.stream()
.collect(Collectors.groupingBy(Person::city));

peopleByCity.forEach((city, peopleInCity) -> {
System.out.println(city + ": " + peopleInCity.stream()
.map(Person::name)
.collect(Collectors.joining(", ")));
});
// Вывод:
// San Francisco: Edward
// New York: Alice, Charlie
// Los Angeles: Bob, David
}
}


#java #stream #grouping
Please open Telegram to view this post
VIEW IN TELEGRAM
👍23🔥4👏21
⌨️ Полезные стримы. Объединение стримов

Даны два списка фруктов. Нужно объединить их в одном стриме, обработать его и вывести результат.


var list1 = List.of("apple", "banana", "cherry");
var list2 = List.of("orange", "pineapple", "mango");

var result = Stream.concat(list1.stream(), list2.stream())
.filter(s -> s.length() > 5)
.toList();

System.out.println(result);
// [banana, cherry, orange, pineapple]


#java #stream #concat
Please open Telegram to view this post
VIEW IN TELEGRAM
👍23🔥21👏1
⌨️ Полезные стримы. Метод distinct()

Если у вас есть поток, который может содержать повторяющиеся элементы, используйте операцию distinct(), чтобы удалить их.


var list = Arrays.asList(1, 2, 3, 3, 4, 5, 5);
var distinctList = list.stream()
.distinct()
.collect(Collectors.toList());
// distinctList: [1, 2, 3, 4, 5]


#java #stream #distinct
Please open Telegram to view this post
VIEW IN TELEGRAM
👍23🔥21👏1
⌨️ Полезные стримы. Сортировка

Отсортировать список с помощью стрима можно используя метод sorted():

var list = List.of(10, 5, 7, 3);
var sortedList = list.stream()
.sorted()
.toList();
sortedList.forEach(System.out::println);
// 3 5 7 10


Можно передать Comparator:

var list = List.of(10, 5, 7, 3);
var sortedList = list.stream()
.sorted(Comparator.reverseOrder())
.toList();
sortedList.forEach(System.out::println);
// 10 7 5 3


#java #stream #sorted
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81🔥1
⌨️ Полезные стримы. Метод peek()

Метод peek() возвращает поток, состоящий из элементов этого потока, дополнительно выполняя предусмотренное действие над каждым элементом по мере потребления элементов из результирующего потока.

Это промежуточная операция.

Для конвейеров параллельных потоков действие может быть вызвано в любое время и в любом потоке, в котором элемент становится доступным в результате вышестоящей операции. Если действие изменяет общее состояние, оно отвечает за обеспечение необходимой синхронизации.

Этот метод существует в основном для отладки, когда вы хотите видеть элементы по мере их прохождения через определенную точку конвейера:

Stream.of("one", "two", "three", "four")
.filter(e -> e. length() > 3)
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.collect(Collectors.toList());
// Filtered value: three
// Mapped value: THREE
// Filtered value: four
// Mapped value: FOUR


В тех случаях, когда реализация потока может оптимизировать создание некоторых или всех элементов (например findFirst или count), действие не будет вызываться для этих элементов.

#java #stream #peek
Please open Telegram to view this post
VIEW IN TELEGRAM
👍121
⌨️ Срезы в стримах. Метод takeWhile

В Java 9 появилось два новых метода, полезных для выбора элементов потока с хорошей производительностью: takeWhile и dropWhile.

Допустим, у нас есть следующий список блюд:

List<Dish> specialMenu = Arrays.asList(
new Dish("seasonal fruit", 120),
new Dish("prawns", 300),
new Dish("rice", 350),
new Dish("chicken", 400),
new Dish("french fries", 530));


Для получения блюд с калорийностью меньше 320, можно воспользоваться операцией filter. Недостаток операции filter в том, что она требует прохода в цикле по всему потоку данных с применением предиката ко всем элементам.

В нашем примере список уже отсортирован по числу калорий. Вместо того, чтобы пройтись по каждому элементу, можно прекратить работу сразу же после обнаружения блюда, содержащего 320 калорий или более. В случае небольшого списка это может показаться не таким уж громадным преимуществом, но при работе с потенциально большим потоком элементов окажется весьма полезным.

Поможет нам в этом операция takeWhile! Она позволяет выполнить срез любого потока данных (даже бесконечного) с помощью предиката. И, к счастью, она прекращает работу сразу же по обнаружении неподходящего элемента. Вот как ее следует использовать:

List<Dish> sliceMenu1
= specialMenu.stream()
.takeWhile(dish -> dish.getCalories() < 320)
.collect(toList());


#java #stream #takeWhile
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍23🤝21🔥1🤔1
⌨️ Срезы в стримах. Метод dropWhile

Операция dropWhile служит дополнением к операции takeWhile. Она отбрасывает первые элементы, для которых предикат возвращает true. Как только результат вычисления предиката становится ложным, она прекращает работу и возвращает все оставшиеся элементы, причем работает даже в том случае, если число оставшихся элементов бесконечно!


List<Integer> ints = List.of(1,2,3,4,5,6,7,8,9);
ints.stream()
.dropWhile(i -> i < 5)
.forEach(System.out::println);
// 5 6 7 8 9


#java #stream #dropWhile
Please open Telegram to view this post
VIEW IN TELEGRAM
👍183
⌨️ Усечение потока данных. Метод limit

Потоки данных поддерживают метод limit(n). Он возвращает еще один поток, не превышающий заданную длину, переданную в limit в виде аргумента. Если поток данных упорядоченный, возвращаются первые элементы, но не более чем n.

Например, с помощью следующего кода можно создать List, выбрав первые три блюда, содержащие более 300 калорий:

List<Dish> dishes = specialMenu
.stream()
.filter(dish -> dish.getCalories() > 300)
.limit(3)
.collect(toList());


Метод limit работает и для неупорядоченных потоков данных (например, когда источник представляет собой объект типа Set). В этом случае не следует исходить из допущения о какой-либо упорядоченности результата, возвращенного методом limit.

#java #stream #limit
Please open Telegram to view this post
VIEW IN TELEGRAM
🤝3👍2
⌨️ "Распрямление" потока. Метод flatMap

Метод Stream.flatMap используется для преобразования элементов одного потока (stream) в несколько элементов другого потока, а затем объединения этих элементов в один поток. Это особенно полезно, когда у вас есть коллекция коллекций, и вы хотите "распрямить" её, т.е. получить плоскую структуру, содержащую все элементы.

Допустим, у вас есть список строк, каждая из которых содержит несколько слов, и вы хотите получить поток всех слов:

List<String> sentences = Arrays.asList("Java is fun", "I love programming");

Stream<String> wordsStream = sentences.stream()
.flatMap(sentence -> Arrays.stream(sentence.split(" "))); // Преобразуем в поток слов

wordsStream.forEach(System.out::println);


Результат:

Java
is
fun
I
love
programming


Здесь каждый массив слов был преобразован в поток, а затем flatMap "распрямил" эти потоки в один.

#java #stream #flatMap
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81
⌨️ Чем отличаются методы Stream.toList() и Stream.collect(Collectors.toList())?

Методы Stream.toList() и Stream.collect(Collectors.toList()) кажутся схожими, так как оба возвращают список, но есть ключевое отличие: Stream.toList() возвращает неизменяемый список, а Stream.collect(Collectors.toList()) возвращает изменяемый список на базе ArrayList.

#java #stream #toList
Please open Telegram to view this post
VIEW IN TELEGRAM
👍203
⌨️ Пропуск элементов потока. Метод skip

Потоки данных поддерживают метод skip(n), возвращающий поток данных с отброшенными первыми n элементами источника. Если в потоке-источнике было меньше n элементов, возвращается пустой поток.

Например, следующий код пропускает первые два блюда, содержащие более 300 калорий, и возвращает остальные:

List<Dish> dishes = menu
.stream()
.filter(d -> d.getCalories() > 300)
.skip(2)
.collect(toList());


#java #stream #skip
Please open Telegram to view this post
VIEW IN TELEGRAM
👏73
⌨️ Метод Stream.anyMatch

Метод anyMatch служит для ответа на вопрос: «Удовлетворяет ли заданному предикату хотя бы один элемент из потока данных?»

Метод anyMatch возвращает boolean, а значит, является завершающей (терминальной) операцией.


int[] digits = {1, 3, 5, 7, 2, 9};
boolean result = Arrays.stream(digits).anyMatch(d -> d % 2 == 0);
System.out.println(result); // true


#java #Stream #anyMatch
Please open Telegram to view this post
VIEW IN TELEGRAM
14
⌨️ Методы allMatch и noneMatch интерфейса Stream

Метод allMatch проверяет, удовлетворяют ли заданному предикату все элементы потока данных.


// Все не чётные?
int[] digits = {1, 3, 5, 7, 9};
boolean result = Arrays.stream(digits).allMatch(d -> d % 2 != 0);
System.out.println(result); // true


Противоположностью allMatch является метод noneMatch. Он проверяет, точно ли ни один элемент списка не соответствует заданному предикату.

// Нет чётных?
int[] digits = {1, 3, 5, 7, 9};
boolean result = Arrays.stream(digits).noneMatch(d -> d % 2 == 0);
System.out.println(result); // true


#java #Stream #allMatch #noneMatch
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥1
⌨️ Метод reduce интерфейса Stream

Метод reduce в интерфейсе Stream используется для сведения набора элементов потока к одному результату, применяя заданную бинарную операцию (например, сложение, умножение). Этот метод часто используется для агрегации данных.

Допустим, у нас есть список чисел, и мы хотим найти их сумму:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

int sum = numbers.stream()
.reduce(0, (a, b) -> a + b);

System.out.println(sum); // 15

В этом примере:
0 — начальное значение (identity),
(a, b) -> a + b — бинарная операция, которая складывает два значения.

reduce полезен для таких операций, как сумма, произведение, объединение строк и т.д.

#java #Stream #reduce
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81🔥1
⌨️ Параллельные и последовательные потоки (Stream)

Последовательные потоки (Sequential Streams)

✔️ Обрабатывают элементы последовательно, один за другим, на одном потоке, следовательно производительность ограничена возможностями одного ядра процессора.

✔️ Используют основной поток программы (main thread) для выполнения операций.

✔️ Метод stream() создаёт последовательный поток.

Пример последовательного потока:

List<String> list = List.of("Hello ", "w", "o", "r", "l", "d!");
list.stream().forEach(System.out::print);
// Hello world!


Параллельные потоки (Parallel Streams)

✔️ Обрабатывают элементы параллельно, распределяя их между несколькими потоками (threads), что позволяет использовать многопоточность.

✔️ Используют ForkJoinPool для распределения задач между потоками.

✔️ Эффективны для больших наборов данных, поскольку могут улучшить производительность на многоядерных процессорах.

✔️ Параллельный поток можно создать, вызвав метод parallelStream() или применив метод parallel() к уже существующему потоку.

Пример параллельного потока:

List<String> list = List.of("Hello ", "w", "o", "r", "l", "d!");
list.parallelStream().forEach(System.out::print);
// rlHello d!wo


#java #Stream #parallelStream
Please open Telegram to view this post
VIEW IN TELEGRAM
👍112🔥1😁1
⌨️ Метод forEachOrdered интерфейса Stream

Метод forEachOrdered в интерфейсе Stream используется для обработки каждого элемента потока с сохранением порядка обработки, даже если поток является параллельным.

В отличие от метода forEach(), который не гарантирует порядок выполнения в параллельных потоках, метод forEachOrdered() всегда сохраняет порядок элементов, как если бы поток был последовательным.

Этот метод полезен, если вам нужно выполнить действия для каждого элемента в параллельном потоке, но при этом важен порядок обработки (например, вывод или запись данных в определенной последовательности).

Параллельный поток с forEach:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.parallelStream().forEach(n -> System.out.println(n));
// Порядок не определён, например 3 1 4 2 5


Параллельный поток с forEachOrdered:

numbers.parallelStream()
.forEachOrdered(n -> System.out.println(n));
// 1 2 3 4 5


#java #Stream #forEachOrdered
Please open Telegram to view this post
VIEW IN TELEGRAM
👍122
⌨️ Stream.reduce() vs Collectors.joining()

Когда требуется конкатенировать строки с использованием Stream, можно выбрать один из двух методов: Stream.reduce() или Stream.collect(Collectors.joining()).

Пример с Stream.reduce():
List<String> list = List.of("Str1", "Str2", "Str3");
String result = list.stream().reduce("", (a, b) -> a + b);
System.out.println(result); // Str1Str2Str3


Пример с Collectors.joining():
List<String> list = List.of("Str1", "Str2", "Str3");
String result = list.stream().collect(Collectors.joining());
System.out.println(result); // Str1Str2Str3


Использование reduce() для конкатенации строк не является оптимальным с точки зрения производительности. При каждом вызове операции +, создается новая строка, так как строки в Java неизменяемы. Это приводит к увеличению нагрузки на память из-за создания множества промежуточных объектов.

В свою очередь, метод Collectors.joining() использует StringBuilder для сборки строк, что значительно эффективнее. Он избегает создания лишних объектов и снижает потребление памяти.

#java #Stream #reduce #joining
Please open Telegram to view this post
VIEW IN TELEGRAM
👍163🍾2🔥1
⌨️ Вычислить максимальное значение в одну строку

В этом нам помогут наши любимые стримы.

Так:
List<Integer> iList = List.of(1,2,3,4,5);
Integer max = iList.stream().reduce(Integer::max).orElse(null);
System.out.println(max);


А еще лучше вот так:
List<Integer> iList = List.of(1,2,3,4,5);
iList.stream().reduce(Integer::max).ifPresent(System.out::println);


#java #Stream #max
Please open Telegram to view this post
VIEW IN TELEGRAM
👍91
⌨️ Срезы в стримах. Метод takeWhile

В Java 9 появилось два новых метода, полезных для выбора элементов потока с хорошей производительностью: takeWhile и dropWhile.

Допустим, у нас есть следующий список блюд:

List<Dish> specialMenu = Arrays.asList(
new Dish("seasonal fruit", 120),
new Dish("prawns", 300),
new Dish("rice", 350),
new Dish("chicken", 400),
new Dish("french fries", 530));


Для получения блюд с калорийностью меньше 320, можно воспользоваться операцией filter. Недостаток операции filter в том, что она требует прохода в цикле по всему потоку данных с применением предиката ко всем элементам.

В нашем примере список уже отсортирован по числу калорий. Вместо того, чтобы пройтись по каждому элементу, можно прекратить работу сразу же после обнаружения блюда, содержащего 320 калорий или более. В случае небольшого списка это может показаться не таким уж громадным преимуществом, но при работе с потенциально большим потоком элементов окажется весьма полезным.

Поможет нам в этом операция takeWhile! Она позволяет выполнить срез любого потока данных (даже бесконечного) с помощью предиката. И, к счастью, она прекращает работу сразу же по обнаружении неподходящего элемента. Вот как ее следует использовать:

List<Dish> sliceMenu1
= specialMenu.stream()
.takeWhile(dish -> dish.getCalories() < 320)
.collect(toList());


#java #stream #takeWhile
Please open Telegram to view this post
VIEW IN TELEGRAM
👍202
⌨️ Stream.reduce() vs Collectors.joining()

Когда требуется конкатенировать строки с использованием Stream, можно выбрать один из двух методов: Stream.reduce() или Stream.collect(Collectors.joining()).

Пример с Stream.reduce():
List<String> list = List.of("Str1", "Str2", "Str3");
String result = list.stream().reduce("", (a, b) -> a + b);
System.out.println(result); // Str1Str2Str3


Пример с Collectors.joining():
List<String> list = List.of("Str1", "Str2", "Str3");
String result = list.stream().collect(Collectors.joining());
System.out.println(result); // Str1Str2Str3


Использование reduce() для конкатенации строк не является оптимальным с точки зрения производительности. При каждом вызове операции +, создается новая строка, так как строки в Java неизменяемы. Это приводит к увеличению нагрузки на память из-за создания множества промежуточных объектов.

В свою очередь, метод Collectors.joining() использует StringBuilder для сборки строк, что значительно эффективнее. Он избегает создания лишних объектов и снижает потребление памяти.

#java #Stream #reduce #joining
Please open Telegram to view this post
VIEW IN TELEGRAM
👍141