SubList: примеры (JAVA)
subList(int fromIndex, int toIndex): ListОписание метода subList
Метод subList(int fromIndex, int toIndex) определён в интерфейсе List и возвращает представление (view) части исходного списка. Он позволяет работать с диапазоном элементов без создания новой копии, что экономит память и время. Изменения, внесённые в подсписок, отражаются на исходном списке, и наоборот.
Параметры:
- fromIndex – начальный индекс включаемой части (включительно).
- toIndex – конечный индекс исключаемой части (исключительно).
Возвращаемое значение: объект типа List, представляющий указанный диапазон исходного списка.
Исключения:
- IndexOutOfBoundsException – если fromIndex меньше 0 или toIndex больше размера списка.
- IllegalArgumentException – если fromIndex больше toIndex.
Метод применяется для извлечения подмножества элементов, для удаления диапазона через вызов clear() на подсписке, а также для выполнения операций над частью списка (сортировка, замена).
Примеры использования
Базовый пример – получение подсписка:
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
List<String> sub = list.subList(1, 4);
System.out.println(sub);[B, C, D]
Изменение подсписка влияет на исходный список:
sub.set(0, "X");
System.out.println(list);[A, X, C, D, E]
Удаление элементов через подсписок:
list.subList(2, 4).clear();
System.out.println(list);[A, B, E]
Использование подсписка для сортировки диапазона:
List<Integer> nums = new ArrayList<>(Arrays.asList(5, 3, 1, 4, 2));
Collections.sort(nums.subList(1, 4));
System.out.println(nums);[5, 1, 3, 4, 2]
Альтернативы в Java
В Java существуют другие способы получения части списка:
- Stream API:
list.stream().skip(from).limit(to - from).collect(Collectors.toList())– создаёт новый независимый список, изменения не передаются исходному. - Копирование подсписка:
new ArrayList<>(list.subList(from, to))– создаёт независимую копию, но использует подсписок для копирования. - List.of(...).subList – для неизменяемых списков подсписок также неизменяем.
Когда предпочтительнее subList? Когда требуется работа с диапазоном как с представлением, особенно для изменения исходного списка через подсписок (например, удаление диапазона). Если нужна отдельная копия, лучше использовать Stream API или конструктор копии.
Аналоги в других языках
Python: срез списка list[1:4] возвращает новый список.
lst = ['A','B','C','D','E']
sub = lst[1:4]
print(sub)['B', 'C', 'D']
JavaScript: метод slice().
let arr = ['A','B','C','D','E'];
let sub = arr.slice(1,4);
console.log(sub);['B', 'C', 'D']
PHP: array_slice($list, 1, 3).
$list = ['A','B','C','D','E'];
$sub = array_slice($list, 1, 3);
print_r($sub);Array ( [0] => B [1] => C [2] => D )
C#: метод GetRange().
List<string> list = new List<string>() { "A","B","C","D","E" };
List<string> sub = list.GetRange(1, 3);
Console.WriteLine(string.Join(", ", sub));B, C, D
Kotlin: функция subList() аналогична Java.
Golang: срез слайса slice[1:4].
slice := []string{"A","B","C","D","E"}
sub := slice[1:4]
fmt.Println(sub)[B C D]
Отличия от Java: в большинстве языков срез создаёт новый массив (копию), тогда как subList в Java – только представление. В Python и Go изменения в срезе не влияют на исходный, если только не используются ссылки на объекты. В PHP array_slice по умолчанию сбрасывает ключи.
Типичные ошибки
IndexOutOfBoundsException при неверных индексах:
list.subList(-1, 2); // fromIndex < 0
list.subList(3, 2); // fromIndex > toIndex
list.subList(0, 10); // toIndex > sizeException in thread "main" java.lang.IndexOutOfBoundsException
ConcurrentModificationException при структурном изменении исходного списка после создания подсписка:
List<String> sub = list.subList(1, 3);
list.add("F"); // структурная модификация
System.out.println(sub);Exception in thread "main" java.util.ConcurrentModificationException
UnsupportedOperationException при попытке изменить подсписок неизменяемого списка (List.of):
List<String> immutable = List.of("A","B","C");
List<String> sub = immutable.subList(0, 2);
sub.add("X"); // попытка модификацииException in thread "main" java.lang.UnsupportedOperationException
Изменения в версиях Java
Метод subList существует с Java 1.2 и не претерпел значительных изменений. В Java 9+ для неизменяемых списков, созданных через List.of или List.copyOf, метод subList возвращает представление, но любые операции модификации (add, set, clear) приводят к UnsupportedOperationException. В Java 21 с введением интерфейса SequencedCollection поведение subList осталось прежним, однако теперь можно использовать методы reversed() для обратного обхода.
Расширенные примеры
Удаление диапазона элементов с помощью подсписка – эффективный способ очистить часть списка:
List<String> list = new ArrayList<>(Arrays.asList("A","B","C","D","E"));
list.subList(1, 4).clear();
System.out.println(list);[A, E]
Сортировка части списка – подсписок можно передать в Collections.sort:
List<Integer> numbers = new ArrayList<>(Arrays.asList(3,1,4,2,5));
Collections.sort(numbers.subList(1, 4));
System.out.println(numbers);[3, 1, 2, 4, 5]
Получение последних N элементов через вычисление индексов:
int n = 3;
List<String> lastN = list.subList(Math.max(0, list.size() - n), list.size());
System.out.println(lastN);[C, D, E] (если исходный список [A,B,C,D,E])
Использование с LinkedList – добавление элемента в подсписок изменяет исходный список:
LinkedList<String> linked = new LinkedList<>(Arrays.asList("A","B","C","D","E"));
List<String> sub = linked.subList(1, 3);
sub.add("X"); // вставка в середину
System.out.println(linked);[A, B, C, X, D, E]
Комбинирование со Stream API для обработки только части элементов:
List<String> processed = list.subList(0, 3).stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(processed);[A, B, C]
Проверка производительности: subList не копирует данные, поэтому операции над ним выполняются быстро. Однако при работе с LinkedList доступ по индексу внутри подсписка может быть медленным (O(n)).