← Назад к вопросам

Как работает промежуточная операция map?

2.0 Middle🔥 81 комментариев
#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Промежуточная операция map в Stream API

Операция map — одна из самых важных операций в Stream API. Она преобразует каждый элемент потока в новый элемент, создавая новый поток с преобразованными значениями.

Основной принцип

map применяет функцию преобразования к каждому элементу потока:

// Простой пример: преобразование чисел
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

List<Integer> doubled = numbers.stream()
    .map(n -> n * 2)           // Преобразование каждого элемента
    .collect(Collectors.toList());

System.out.println(doubled);    // [2, 4, 6, 8, 10]

Сигнатура

<R> Stream<R> map(Function<? super T, ? extends R> mapper)

Где:

  • T — тип входного элемента
  • R — тип выходного элемента
  • Function<T, R> — функция преобразования

Примеры использования

1. Преобразование объектов в строки

class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() { return name; }
    public int getAge() { return age; }
}

List<Person> people = Arrays.asList(
    new Person("Alice", 25),
    new Person("Bob", 30),
    new Person("Charlie", 35)
);

// Получить список имён
List<String> names = people.stream()
    .map(Person::getName)           // Метод-ссылка
    .collect(Collectors.toList());

System.out.println(names);          // [Alice, Bob, Charlie]

2. Преобразование типов данных

List<String> strings = Arrays.asList("1", "2", "3", "4", "5");

List<Integer> integers = strings.stream()
    .map(Integer::parseInt)         // String -> Integer
    .collect(Collectors.toList());

System.out.println(integers);       // [1, 2, 3, 4, 5]

3. Извлечение полей из объектов

class Order {
    private String id;
    private double amount;
    
    public Order(String id, double amount) {
        this.id = id;
        this.amount = amount;
    }
    
    public double getAmount() { return amount; }
}

List<Order> orders = Arrays.asList(
    new Order("O1", 100.0),
    new Order("O2", 200.0),
    new Order("O3", 150.0)
);

// Получить все суммы заказов
double totalAmount = orders.stream()
    .map(Order::getAmount)          // Order -> Double
    .mapToDouble(Double::doubleValue)
    .sum();

System.out.println(totalAmount);    // 450.0

Цепочки map операций

List<String> result = Arrays.asList("apple", "banana", "cherry")
    .stream()
    .map(String::toUpperCase)       // apple -> APPLE
    .map(s -> s + "!")              // APPLE -> APPLE!
    .map(String::length)            // APPLE! -> 6
    .map(String::valueOf)           // 6 -> "6"
    .collect(Collectors.toList());

System.out.println(result);         // [6, 7, 6]

Специализированные версии map

1. mapToInt — преобразование в IntStream

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

int sum = numbers.stream()
    .mapToInt(Integer::parseInt)    // Stream<String> -> IntStream
    .sum();

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

2. mapToLong — для больших чисел

List<Long> ids = Arrays.asList(1L, 2L, 3L, 4L, 5L);

long product = ids.stream()
    .mapToLong(Long::longValue)
    .reduce(1, (a, b) -> a * b);

System.out.println(product);        // 120

3. mapToDouble — для дробных чисел

List<Integer> grades = Arrays.asList(80, 90, 75, 88);

double average = grades.stream()
    .mapToDouble(Integer::doubleValue)
    .average()
    .orElse(0.0);

System.out.println(average);        // 83.25

Визуализация работы map

Входящий поток:        1    2    3    4    5
                         |    |    |    |    |
                         v    v    v    v    v
Операция map(*2):       2    4    6    8    10
                         |    |    |    |    |
                         v    v    v    v    v
Исходящий поток:        2    4    6    8    10

Важное свойство: ленивость (laziness)

List<Integer> result = Arrays.asList(1, 2, 3, 4, 5)
    .stream()
    .map(n -> {
        System.out.println("Преобразование " + n);
        return n * 2;
    })
    .filter(n -> n > 5)             // Промежуточная операция
    .collect(Collectors.toList());  // Терминальная операция

// Вывод: функция map вызовется только для элементов,
// которые пройдут filter (4 -> 8, 5 -> 10)

map vs flatMap

// map — преобразование один-ко-одному
List<Integer> numbers = Arrays.asList(1, 2, 3);
List<Integer> doubled = numbers.stream()
    .map(n -> n * 2)
    .collect(Collectors.toList());  // [2, 4, 6]

// flatMap — преобразование один-ко-многим и выравнивание
List<List<Integer>> nestedLists = Arrays.asList(
    Arrays.asList(1, 2),
    Arrays.asList(3, 4),
    Arrays.asList(5, 6)
);

List<Integer> flattened = nestedLists.stream()
    .flatMap(List::stream)          // Выравнивание списков
    .map(n -> n * 2)                // Преобразование
    .collect(Collectors.toList());  // [2, 4, 6, 8, 10, 12]

Практический пример: обработка JSON

class User {
    private String name;
    private String email;
    
    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }
    
    public String getEmail() { return email; }
}

List<User> users = Arrays.asList(
    new User("Alice", "alice@example.com"),
    new User("Bob", "bob@example.com")
);

// Преобразование в строковое представление
String csvEmails = users.stream()
    .map(User::getEmail)
    .collect(Collectors.joining(","));

System.out.println(csvEmails);      // alice@example.com,bob@example.com

Ключевые свойства map

  • Промежуточная операция — не выполняется до терминальной операции
  • Один-ко-одному преобразование — каждый элемент преобразуется в ровно один элемент
  • Сохранение порядка — элементы остаются в том же порядке
  • Ленивое вычисление — вычисляется только для нужных элементов
  • Функциональная парадигма — чистые функции без побочных эффектов

map — это основной инструмент функционального программирования в Java, используется в 80% работы со Stream API.