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

Что такое функция map?

1.6 Junior🔥 301 комментариев
#Stream API и функциональное программирование

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

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

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

# Функция map в Java

Определение

Функция map — это операция, которая преобразует каждый элемент коллекции/потока в новый элемент, применяя к нему функцию преобразования. Результат — новая коллекция того же размера, но с преобразованными элементами.

Аналогия

Представьте конвейер на фабрике:

  • На входе: детали разных размеров
  • На конвейере: машина покраски (функция map)
  • На выходе: те же детали, но окрашенные

Map в Streams API (Java 8+)

Базовый пример

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

// Умножить каждое число на 2
List<Integer> doubled = numbers.stream()
    .map(n -> n * 2)
    .collect(Collectors.toList());

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

Преобразование типов

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// Преобразовать строки в их длины
List<Integer> lengths = names.stream()
    .map(String::length)
    .collect(Collectors.toList());

System.out.println(lengths); // [5, 3, 7]

Map с объектами

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

public class UserDTO {
    private String name;
    private String info;
    
    public UserDTO(String name, String info) {
        this.name = name;
        this.info = info;
    }
}

// Использование
List<User> users = Arrays.asList(
    new User("Alice", 25),
    new User("Bob", 30),
    new User("Charlie", 35)
);

// Преобразовать User в UserDTO
List<UserDTO> dtos = users.stream()
    .map(user -> new UserDTO(
        user.getName(),
        "Age: " + user.getAge()
    ))
    .collect(Collectors.toList());

Map с различными типами потоков

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

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

// Преобразовать строки в целые числа
int sum = numbers.stream()
    .mapToInt(Integer::parseInt)
    .sum();

System.out.println("Сумма: " + sum); // 15

mapToLong

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

long product = values.stream()
    .mapToLong(n -> (long) n)
    .reduce(1, (a, b) -> a * b);

System.out.println("Произведение: " + product); // 120

mapToDouble

List<Integer> grades = Arrays.asList(85, 90, 78, 92, 88);

double average = grades.stream()
    .mapToDouble(Double::valueOf)
    .average()
    .orElse(0.0);

System.out.println("Средняя оценка: " + average); // 86.6

FlatMap — вложенные коллекции

Проблема с обычным map

List<List<Integer>> matrix = Arrays.asList(
    Arrays.asList(1, 2, 3),
    Arrays.asList(4, 5, 6),
    Arrays.asList(7, 8, 9)
);

// Неправильно с map — получим List<List<Integer>>
List<List<Integer>> wrong = matrix.stream()
    .map(list -> list.stream().map(n -> n * 2).collect(Collectors.toList()))
    .collect(Collectors.toList());

// Нужно распрямить результат

Решение с flatMap

// Правильно с flatMap — получим List<Integer>
List<Integer> flattened = matrix.stream()
    .flatMap(list -> list.stream())
    .map(n -> n * 2)
    .collect(Collectors.toList());

System.out.println(flattened); // [2, 4, 6, 8, 10, 12, 14, 16, 18]

Map vs forEach

Со Stream (map) — функциональный стиль

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

List<Integer> doubled = numbers.stream()
    .map(n -> n * 2)
    .collect(Collectors.toList());

// Результат — новый список

С forEach — императивный стиль

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

for (Integer n : numbers) {
    doubled.add(n * 2);
}

// Результат — новый список (через мутацию)

Map в Reactive Programming

С Project Reactor

Flux.range(1, 5)
    .map(n -> n * 2)
    .subscribe(System.out::println);

// Output: 2, 4, 6, 8, 10

С RxJava

Observable.range(1, 5)
    .map(n -> n * 2)
    .subscribe(System.out::println);

// Output: 2, 4, 6, 8, 10

Map в функциональном программировании

Высшего порядка функция

public static <T, R> List<R> map(List<T> list, Function<T, R> mapper) {
    List<R> result = new ArrayList<>();
    for (T item : list) {
        result.add(mapper.apply(item));
    }
    return result;
}

// Использование
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> doubled = map(numbers, n -> n * 2);
List<String> strings = map(numbers, String::valueOf);

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

List<String> names = Arrays.asList("alice", "bob", "charlie");

List<String> result = names.stream()
    .map(String::toUpperCase)        // ALICE, BOB, CHARLIE
    .map(s -> s + "!")               // ALICE!, BOB!, CHARLIE!
    .filter(s -> s.length() > 5)     // ALICE!, CHARLIE!
    .collect(Collectors.toList());

System.out.println(result); // [ALICE!, CHARLIE!]

Map с Optional

Optional<User> optionalUser = getUserById(1);

// Если есть пользователь, получить его имя
Optional<String> name = optionalUser
    .map(User::getName);

if (name.isPresent()) {
    System.out.println("Имя: " + name.get());
}

// Альтернативно
name.ifPresent(n -> System.out.println("Имя: " + n));

Производительность

Lazy evaluation

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

// map не выполнится, пока не будет terminal операции
Stream<Integer> stream = numbers.stream()
    .map(n -> {
        System.out.println("Processing " + n);
        return n * 2;
    });

// До этого момента ничего не выполнилось!
List<Integer> result = stream.collect(Collectors.toList());
// Только сейчас выполнится map

Сравнение map операций

МетодНазначениеРезультат
mapПреобразовать элементыStream<T>
mapToIntПреобразовать в intIntStream
mapToLongПреобразовать в longLongStream
mapToDoubleПреобразовать в doubleDoubleStream
flatMapРаспрямить вложенные потокиStream<T>

Когда использовать map

  1. Преобразование типов — int в String
  2. Извлечение данных — объект в его свойства
  3. Вычисления — число в его квадрат
  4. Форматирование — данные в нужный вид
  5. Обогащение данных — добавление вычисленных полей

Плюсы map

  • Функциональный стиль
  • Читаемый код
  • Можно цепить с другими операциями
  • Ленивое вычисление в потоках
  • Не мутирует исходную коллекцию