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

Какие сложности основных операций ArrayList

1.8 Middle🔥 151 комментариев
#Коллекции

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

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

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

Ответ

Как хранятся данные в пустой Map

Пустая Map - это интересная тема про внутреннее устройство Java коллекций и управление памятью.

1. Пустая HashMap - структура в памяти

Map<String, String> emptyMap = new HashMap<>();

Что происходит в памяти:

HashMap объект
├── table (массив buckets) - создаётся с CAPACITY = 16
│   ├── [0] -> null
│   ├── [1] -> null
│   ├── [2] -> null
│   ...     -> null
│   └── [15] -> null
├── size = 0
├── threshold = 12 (capacity * load_factor = 16 * 0.75)
└── loadFactor = 0.75

Память которая занимается:

HashMap объект: ~64 байта
  - HashMap reference: 8 bytes
  - table[] array reference: 8 bytes
  - size: 4 bytes
  - threshold: 4 bytes
  - loadFactor: 4 bytes
  - modCount: 4 bytes

table[] array (16 buckets): ~128 байт
  - Array header: 16 bytes
  - 16 null references: 16 * 8 = 128 bytes

Итого: ~200 байт

Одна пара key-value добавит ~50-100 байт в зависимости от размера ключа/значения.

2. Оптимизация пустой Map - Collections.emptyMap()

// Плохо - тратит память
Map<String, String> emptyMap = new HashMap<>();
Map<String, String> anotherEmpty = new HashMap<>();
// Два разных объекта в памяти!

// Хорошо - синглтон
Map<String, String> emptyMap = Collections.emptyMap();
Map<String, String> anotherEmpty = Collections.emptyMap();
// Один объект для всех! (immutable)

// Проверка что это один объект
System.out.println(emptyMap == anotherEmpty);  // true!

3. Когда используется пустая Map

@Service
public class UserService {
    
    public Map<String, Object> getUserData(Long userId) {
        User user = userRepository.findById(userId).orElse(null);
        
        if (user == null) {
            // Вместо null - вернуть пустую Map
            return Collections.emptyMap();
        }
        
        Map<String, Object> data = new HashMap<>();
        data.put("id", user.getId());
        data.put("email", user.getEmail());
        return data;
    }
    
    // Клиент может безопасно итерировать
    Map<String, Object> result = getUserData(123L);
    for (var entry : result.entrySet()) {
        System.out.println(entry.getKey() + ": " + entry.getValue());
    }
    // Если null было бы - NullPointerException!
}

4. Нулевой ёмкости Map - LinkedHashMap

// Пустой LinkedHashMap занимает меньше
Map<String, String> lhm = new LinkedHashMap<>(0);

// Структура:
LinkedHashMap
├── table: null (если capacity = 0)
├── head: null
├── tail: null
├── size: 0
└── accessOrder: false

5. Сравнение пустых коллекций

// Collections.emptyMap() - ЛУЧШИЙ ВЫБОР
Map<String, String> empty1 = Collections.emptyMap();
Map<String, String> empty2 = Collections.emptyMap();
System.out.println(empty1 == empty2);  // true - один объект!

// new HashMap<>() - каждый раз новый объект
Map<String, String> empty3 = new HashMap<>();
Map<String, String> empty4 = new HashMap<>();
System.out.println(empty3 == empty4);  // false

// Stream API
List<String> emptyList = Stream.empty()
    .collect(Collectors.toList());
// Это создаёт новый пустой ArrayList каждый раз

6. Immutable пустые коллекции

// Все эти эффективны
Map<String, String> unmodifiable = Collections.unmodifiableMap(new HashMap<>());
Map<String, String> empty = Collections.emptyMap();  // синглтон
Map<String, String> singleton = Map.of();  // Java 9+ - синглтон

// Попытка изменить - exception
empty.put("key", "value");
// UnsupportedOperationException: Collection is immutable

7. Практический пример - обработка результатов

@Service
public class DataProcessor {
    
    // Плохо - может быть null
    public Map<String, List<String>> groupByCategory(List<Item> items) {
        if (items == null || items.isEmpty()) {
            return null;  // ПЛОХО!
        }
        
        return items.stream()
            .collect(Collectors.groupingBy(Item::getCategory,
                Collectors.mapping(Item::getName, Collectors.toList())));
    }
    
    // Хорошо - никогда null
    public Map<String, List<String>> groupByCategoryBetter(List<Item> items) {
        return items.stream()
            .collect(Collectors.groupingBy(Item::getCategory,
                Collectors.mapping(Item::getName, Collectors.toList())));
        // Если пусто - вернёт пустую Map, не null
    }
    
    // Использование
    public void process() {
        Map<String, List<String>> result = groupByCategoryBetter(Collections.emptyList());
        
        // Безопасно - результат это пустая Map
        result.forEach((category, names) -> {
            System.out.println(category + ": " + names);
        });
    }
}

8. Performance - пустая Map в коллекциях

public class PerformanceTest {
    
    public static void main(String[] args) {
        // Collections.emptyMap() - очень быстро
        long start = System.nanoTime();
        for (int i = 0; i < 1_000_000; i++) {
            Map<String, String> empty = Collections.emptyMap();
        }
        long empty_time = System.nanoTime() - start;
        
        // new HashMap<>() - медленнее
        start = System.nanoTime();
        for (int i = 0; i < 1_000_000; i++) {
            Map<String, String> empty = new HashMap<>();
        }
        long new_time = System.nanoTime() - start;
        
        System.out.println("emptyMap time: " + empty_time);
        System.out.println("new HashMap time: " + new_time);
        System.out.println("Ratio: " + (new_time / empty_time) + "x faster");
        // emptyMap примерно в 10x быстрее!
    }
}

9. Внутренняя реализация Collections.emptyMap()

// Примерно так это реализовано в JDK
private static final Map EMPTY_MAP = 
    new AbstractMap() {
        @Override
        public Set entrySet() {
            return Collections.emptySet();
        }
        
        @Override
        public int size() {
            return 0;
        }
        
        @Override
        public boolean isEmpty() {
            return true;
        }
        
        // Может быть сериализована в пустую Map
        private Object readResolve() {
            return EMPTY_MAP;
        }
    };

public static <K, V> Map<K, V> emptyMap() {
    return (Map<K, V>) EMPTY_MAP;
}

10. Best Practices

  1. Используй Collections.emptyMap() вместо new HashMap<>()
  2. Никогда не возвращай null вместо пустой Map
  3. Используй Map.of() в Java 9+ для синглтонов
  4. Проверяй isEmpty() вместо .size() == 0
  5. Помни что пустые коллекции immutable - не пытайся добавлять
  6. Используй Stream API - обработка пустых коллекций безопаснее

Краткий вывод: Пустая Map хранит минимальное количество данных. Collections.emptyMap() вернёт синглтон без выделения новой памяти. Всегда используй пустые коллекции вместо null для безопасности и производительности.

Какие сложности основных операций ArrayList | PrepBro