← Назад к вопросам
Что такое функция 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 | Преобразовать в int | IntStream |
| mapToLong | Преобразовать в long | LongStream |
| mapToDouble | Преобразовать в double | DoubleStream |
| flatMap | Распрямить вложенные потоки | Stream<T> |
Когда использовать map
- Преобразование типов — int в String
- Извлечение данных — объект в его свойства
- Вычисления — число в его квадрат
- Форматирование — данные в нужный вид
- Обогащение данных — добавление вычисленных полей
Плюсы map
- Функциональный стиль
- Читаемый код
- Можно цепить с другими операциями
- Ленивое вычисление в потоках
- Не мутирует исходную коллекцию