JavaRush /Курсы /Java Syntax Pro /Работа с потоками, часть 2

Работа с потоками, часть 2

Java Syntax Pro
18 уровень , 4 лекция
Открыта

1. Преобразование данных

Также у класса Stream<T> есть метод, который позволяет преобразовать данные из одного типа в другой. Этот метод называется map().

Он тоже возвращает поток Stream<R>, но уже с элементами нового типа. В качестве параметра в метод map() нужно передать функцию, которая преобразовывает один тип данных в другой.

Примеры:

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<String> stream2 = stream.map((x) -> String.valueOf(x));
Преобразовываем поток Integer в поток String

Функция, которую передали в метод map() в качестве параметра, принимает число x, а в качестве результата возвращает строку. Можно, кстати, записать этот код короче:

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<String> stream2 = stream.map(String::valueOf);
Преобразовываем поток Integer в поток String

Преобразование строки в число

Аналогично можно написать код и для преобразования строки в число — тоже ничего сложного:

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
Stream<String> stream2 = stream.map(String::valueOf);
Stream<Integer> stream3 = stream2.map(Integer::parseInt);
Преобразовываем поток String в поток Integer

Преобразование строки в URI

Операции по преобразованию данных могут быть большими и тяжелыми. Допустим, мы хотим преобразовать коллекцию строк в объекты URI. Это очень легко сделать, ведь URI принимает строку в качестве параметра конструктора

ArrayList<String> list = new ArrayList<String>();
list.add("https://google.com");
list.add("https://linkedin.com");
list.add("https://yandex.com");

Stream<URI> stream = list.stream().map( URI::new );
Преобразовываем поток String в поток URI

Мы создали коллекцию, записали в нее 3 ссылки на сайты в интернете. Затем получили у коллекции объект Stream<String> и у него — объект Stream<URI>. А в метод map передали ссылку на метод, который будет использоваться для преобразования из String в URI.

Этот метод (конструктор) должен принимать в качестве параметра тип String. Все вроде бы идеально...


2. Исключения

Код выше должен работать, но он работать не будет — программа не скомпилируется. И не потому, что мы где-то сделали ошибку, а потому, что ее сделали разработчики Java.

Когда-то давно им пришла в голову замечательная идея — добавить в конструктор(!) класса URI checked-исключение URISyntaxException. А такие исключения нужно обязательно заворачивать в try-catch.

Поэтому последняя строка нашего кода будет выглядеть вот так:

Stream<URI> stream = list.stream().map(str ->
{
  try
  {
     return new URI(str);
  }
  catch (URISyntaxException e)
  {
     e.printStackTrace();
     return null;
  }
});

Что вам сказать? Нужно дважды подумать, прежде чем использовать checked-исключения. И трижды, прежде чем использовать их в конструкторе.


Комментарии (119)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Виктор Уровень 21
4 октября 2025
Начинаю немного понимать что к чему) или нет.
Anonymous #3585174 Уровень 33
23 июля 2025
like
ShadyLine Уровень 30
8 апреля 2025
сложно
Cryptosin Уровень 24
23 февраля 2025
Отличие между map() и flatMap() Представим, что у нас есть список людей и их списки хобби:

List<Person> people = List.of(
    new Person("Аня", List.of("Плавание", "Чтение")),
    new Person("Борис", List.of("Шахматы", "Рисование")),
    new Person("Вика", List.of("Танцы"))
);
Где Person — это просто класс:

class Person {
    String name;
    List<String> hobbies;

    Person(String name, List<String> hobbies) {
        this.name = name;
        this.hobbies = hobbies;
    }
}
1️⃣ map(): Получаем список списков хобби

List<List<String>> hobbiesList = people.stream()
    .map(person -> person.hobbies)
    .toList();

System.out.println(hobbiesList);
💡 Вывод:

[
    [Плавание, Чтение],
    [Шахматы, Рисование],
    [Танцы]
]
👉 Мы получили список списков, то есть список, где у каждого человека свой отдельный список хобби. 2️⃣ flatMap(): Получаем просто список всех хобби

List<String> allHobbies = people.stream()
    .flatMap(person -> person.hobbies.stream())
    .toList();

System.out.println(allHobbies);
💡 Вывод:

[Плавание, Чтение, Шахматы, Рисование, Танцы]
👉 Мы получили простой список всех хобби, потому что flatMap() "разгладил" список списков. 🚀 Разница в одном предложении: - map() оставляет список списков (List<List<String>>). - flatMap() делает один общий список (List<String>).
Rustam Уровень 3 Student
19 октября 2024
После стремного кода с try - catch, я ожидал ещё одно включение, где нам расскажут про легкий способ, сделать это всё в 1 строку. Избаловали...
Даниил Уровень 35
7 февраля 2025
URI.create(String);
Anton Уровень 2
30 сентября 2024
return strings.map(String::toUpperCase) Что обозначает символ :: ?
Viktoryia Ka Уровень 106
6 октября 2024
Ссылка на метод. В конкретном примере говорит, что к объекту типа String будет применен метод toUpperCase(). А-ля тернарный оператор, но т к ":" уже зарезервировано для него, то используется "::"
Needl L Уровень 51
29 августа 2024
такое чувство будто IDEA сама решает за меня задачи
Kostas Уровень 30 Expert
26 сентября 2024
Ну, если нажать - "Решение" -"Правильное решение", то да! :))
Anonymous #3473617 Уровень 23
2 августа 2024
Знатоки, поясните. В последней задаче (Преобразование данных-2) первая мысль была использовать peek(), т.к. в его описании написано "Выполняет действием над каждым данным", но ничего не вышло. Почему тут именно map(), или даже почему peek() не сработал?
SergeyPavlochev Уровень 29
4 августа 2024
Функция map используется когда нужно заменить элементы потока на другие элементы. Функция peek используется, когда нужно изменить внутреннее состояние объекта или получить отладочную информацию в процессе преобразования данных потока (например, peek(System.out::println). В случае с последним заданием нужно перевести строки в верхний регистр. Объекты String неизменяемые, функция toUpperCase возвращает новые объекты String. Поэтому тут нужно использовать map, чтобы физически поменять объекты в потоке на другие. Функция peek в этом задании в таком варианте stream.peek(String::toUpperCase) приведет только к тому, что в момент выборки каждого элемент в функции forEach дополнительно сбоку будут создаваться объекты String в верхнем регистре, а сами элементы в потоке не меняются, как были в нижнем регистре, так и есть. Чтобы увидеть эти создающиеся строки в верхнем регистре достаточно их вывести в консоль, например, так: peek(s -> System.out.println(s.toUpperCase())). Если бы вместо String в потоке был какой-то изменяемый объект, внутри которого можно было поменять регистр строки, то можно было бы использовать peek.
Anonymous #3383133 Уровень 21
3 ноября 2024
Im not alone....
Ринат Уровень 22
4 декабря 2024
Тоже пришёл к таким выводам, после того как пол часа пытался решить, эту задачу через peek(), а ты прям собрал мои мысли в один пост. Спасибо тебе добрый человек.
Victor Уровень 36
14 февраля 2025
Так в задании и в Требованиях ТРЕБУЮТ использовать метод map(). Если бы тебе даже как-то удалось выдавить UpperCace из peek, то валидатор бы не пропустил.
Anton Уровень 34
31 июля 2024
Похоже на то, что создаются потоки из предыдущих потоков, которые были отфильтрованы. Есть труба. В некотором месте стоит фильтр. После этого фильтра начинается новый поток.
JalolsHyper Уровень 24
19 июня 2024
дорогой будуший программист,удачи тебя!