69. Реализовать собственный неизменяемый пустой список
Условие задачи:
Необходимо реализовать аналог Collections.emptyList(), который возвращает неизменяемый пустой список.
Требования:
нельзя использовать
Collections.emptyList()иList.of();при каждом вызове должен возвращаться один и тот же объект;
метод должен сохранять тип элементов списка;
операции изменения должны завершаться
UnsupportedOperationException.
Спойлеры к решению
Подсказки
💡 Храни единственный экземпляр списка в поле
💡 Один пустой список можно безопасно использовать для любых типов.
💡 Метод должен объявлять собственный параметр типа
💡 Унаследуй реализацию от
💡 Метод
static final.💡 Один пустой список можно безопасно использовать для любых типов.
💡 Метод должен объявлять собственный параметр типа
<T>.💡 Унаследуй реализацию от
AbstractList, чтобы получить стандартное поведение списка.💡 Метод
size() всегда должен возвращать 0.Решение
public final class MyCollections {
private static final List<?> EMPTY_LIST = new EmptyList<>();
private MyCollections() {
}
@SuppressWarnings("unchecked")
public static <T> List<T> emptyList() {
return (List<T>) EMPTY_LIST;
}
private static final class EmptyList<T>
extends AbstractList<T>
implements RandomAccess {
@Override
public T get(int index) {
throw new IndexOutOfBoundsException(
"Index: " + index + ", size: 0"
);
}
@Override
public int size() {
return 0;
}
}
}
Пример использования:
List<String> strings = MyCollections.emptyList();
List<Integer> numbers = MyCollections.emptyList();
System.out.println(strings.isEmpty());
System.out.println(strings == (Object) numbers);
Результат:
true
true
Для всех типов возвращается один объект:
private static final List<?> EMPTY_LIST = new EmptyList<>();
Приведение к List<T> безопасно, поскольку список не содержит элементов и не позволяет их добавлять.
Методы изменения, унаследованные от AbstractList, выбрасывают UnsupportedOperationException:
strings.add("value");
Сложность size() и isEmpty() — O(1). Новый экземпляр при вызове emptyList() не создаётся.