List: примеры (JAVA)

Практические примеры работы с List
Раздел: Ввод-вывод (I/O) файловый
list: String[]

Описание интерфейса List в Java

Интерфейс java.util.List<E> представляет упорядоченную коллекцию элементов с доступом по индексу. List задает поведение для коллекций, в которых допускаются дубликаты и важен порядок вставки. Тип параметра E определяет тип элементов в списке.

Основные назначения: хранение последовательностей объектов, реализация очередей и стеков поверх списков, передача упорядоченных наборов между методами.

Ключевые методы и их назначение, сигнатуры и возвращаемые значения:

  • boolean add(E e) - добавляет элемент в конец списка. Возвращает true (обычно всегда), может бросить UnsupportedOperationException для неизменяемых списков.
  • void add(int index, E element) - вставляет элемент по индексу. При неверном индексе - IndexOutOfBoundsException.
  • boolean addAll(Collection<? extends E> c) - добавляет все элементы коллекции в конец. Возвращает true, если список изменился.
  • E get(int index) - возвращает элемент по индексу. При неверном индексе - IndexOutOfBoundsException.
  • E set(int index, E element) - заменяет элемент по индексу, возвращает прежнее значение.
  • E remove(int index) - удаляет элемент по индексу и возвращает его; может вызвать IndexOutOfBoundsException.
  • boolean remove(Object o) - удаляет первое вхождение объекта, возвращает true, если было удаление.
  • int size() - возвращает число элементов.
  • boolean isEmpty() - возвращает true, если пуст.
  • boolean contains(Object o) - проверяет наличие объекта (использует equals).
  • int indexOf(Object o), int lastIndexOf(Object o) - индекс первого и последнего вхождения или -1.
  • Iterator<E> iterator() и ListIterator<E> listIterator() - итераторы; при структурном изменении во время обхода (без использования итератора) возможен ConcurrentModificationException.
  • List<E> subList(int fromIndex, int toIndex) - представление части списка; изменения в подсписке отражаются в исходном списке и наоборот.
  • Object[] toArray() и <T> T[] toArray(T[] a) - конвертация в массив.
  • Default-методы в интерфейсе (в зависимости от версии JVM): removeIf(Predicate<? super E> filter), replaceAll(UnaryOperator<E> operator), sort(Comparator<? super E> c).

Особенности реализации: ArrayList обеспечивает быстрый произвольный доступ (O(1) для get), LinkedList - эффективные операции вставки/удаления в середине при наличии итератора. Некоторые списки - фиксированного размера (результат Arrays.asList) или неизменяемые (результат List.of или Collections.unmodifiableList), тогда модифицирующие операции бросают UnsupportedOperationException.

Короткие примеры использования List

Создание и базовые операции:

import java.util.*;

class Example1 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("one");
        list.add("two");
        list.add(1, "inserted");
        System.out.println(list); // вывод
        System.out.println(list.get(2));
    }
}
[one, inserted, two]
two

Итерация и удаление через Iterator:

import java.util.*;

class Example2 {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>(Arrays.asList(1,2,3,4));
        Iterator<Integer> it = nums.iterator();
        while (it.hasNext()) {
            Integer n = it.next();
            if (n % 2 == 0) it.remove();
        }
        System.out.println(nums);
    }
}
[1, 3]

Immutable list через List.of и поведение при модификации:

import java.util.*;

class Example3 {
    public static void main(String[] args) {
        List<String> imm = List.of("a", "b");
        System.out.println(imm);
        // imm.add("c"); // бросит исключение
    }
}
[a, b]

subList как представление той же области памяти:

import java.util.*;

class Example4 {
    public static void main(String[] args) {
        List<String> src = new ArrayList<>(Arrays.asList("x","y","z","w"));
        List<String> sub = src.subList(1, 3); // [y, z]
        sub.set(0, "Y");
        System.out.println(src);
    }
}
[x, Y, z, w]

Похожие структуры в Java и их особенности

  • ArrayList - динамический массив; быстрый доступ по индексу, амортизированная вставка в конец. Подходит для частого чтения и редкой вставки/удаления в середине.
  • LinkedList - двусвязный список; эффективные операции добавления/удаления в середине через итератор, медленный произвольный доступ.
  • Vector - как ArrayList, но синхронизирован; устаревший вариант, чаще заменяется коллекциями из java.util.concurrent или Collections.synchronizedList.
  • CopyOnWriteArrayList - потокобезопасный, копирует внутренний массив при модификации; эффективен для сценариев «много читателей, мало писателей».
  • Collections.unmodifiableList и List.of - создают неизменяемые представления; подходят для передачи данных, когда изменение нежелательно.

Выбор основывается на характерной нагрузке: при частом доступе по индексу - ArrayList, при частых вставках/удалениях в середине - LinkedList, при многопоточном чтении - CopyOnWriteArrayList или синхронизация.

Аналоги List в других языках и отличия

  • Python - built-in list. Динамический массив с похожими операциями. Отличие: синтаксис, duck-typing, встроенные методы append, pop, срезы. Пример:
    lst = [1, 2, 3]
    lst.append(4)
    print(lst)
    [1, 2, 3, 4]
  • JavaScript - Array. Динамическая коллекция, методы push/splice/slice. Пример:
    let a = ["a","b"];
    a.push("c");
    console.log(a);
    [ 'a', 'b', 'c' ]
  • PHP - массивы (array) используются как списки и ассоциативные массивы. Пример:
    $a = [1,2,3];
    $a[] = 4;
    print_r($a);
    Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 )
  • C# - List<T> в System.Collections.Generic; очень похоже на Java List/ArrayList. Пример:
    using System;
    using System.Collections.Generic;
    class P{ static void Main(){ var l = new List<int>{1,2}; l.Add(3); Console.WriteLine(string.Join(",",l)); }}
    1,2,3
  • Go - срезы (slices) служат списками. Отличие: внутреннее представление и способы расширения через append. Пример:
    package main
    import "fmt"
    func main(){ s := []int{1,2}; s = append(s,3); fmt.Println(s) }
    [1 2 3]
  • Kotlin - List и MutableList; interop с Java коллекциями, но отличия в null-safety и расширенных функциях. Пример:
    fun main(){ val l = mutableListOf("a","b"); l.add("c"); println(l) }
    [a, b, c]
  • Lua - таблицы как универсальные структуры, используются как массивы. Пример:
    t = {1,2,3}
    table.insert(t,4)
    for i,v in ipairs(t) do print(v) end
    1
    2
    3
    4
  • SQL - реляционные таблицы не являются списком в памяти, но последовательности хранятся в результирующих наборах; операции отличаются семантикой и масштабом.

Краткое отличие от Java: управление типами компиляцией, модель памяти и готовые методы API. В Java строгие generics и набор реализаций в JDK; в динамических языках синтаксис короче, но меньше гарантий типов во время компиляции.

Типичные ошибки при работе с List

  • IndexOutOfBoundsException - при обращении к несуществующему индексу. Пример:
    import java.util.*;
    class E1{ public static void main(String[] a){ List<String> l = List.of("x"); System.out.println(l.get(1)); }}
    Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
     at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
     ...
  • UnsupportedOperationException - попытка изменить неизменяемый или фиксированного размера список (например, результат List.of или Arrays.asList). Пример:
    import java.util.*;
    class E2{ public static void main(String[] a){ List<String> l = Arrays.asList("a","b"); l.add("c"); }}
    Exception in thread "main" java.lang.UnsupportedOperationException
     at java.base/java.util.AbstractList.add(AbstractList.java:153)
     ...
  • ConcurrentModificationException - изменение коллекции вне итератора при обходе. Пример:
    import java.util.*;
    class E3{ public static void main(String[] a){ List<Integer> l = new ArrayList<>(Arrays.asList(1,2,3)); for(Integer x: l) { if (x==2) l.remove(x); } }}
    Exception in thread "main" java.util.ConcurrentModificationException
     at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
     ...
  • NullPointerException - возможен при использовании null с частями API (например в Map ключом), или при работе с методами, ожидающими non-null. Многие реализации List допускают null, но некоторая логика (например, сравнения) может дать NPE.
  • ClassCastException - при использовании сырых типов или при приведения элементов к неверному типу.

Изменения API List в последних версиях Java

Ключевые изменения, актуальные для современной экосистемы:

  • Java 8: добавлены default-методы, такие как removeIf, replaceAll, sort, что упростило манипуляции над списками прямо в интерфейсе коллекции.
  • Java 9: введены фабричные статические методы List.of для быстрого создания неизменяемых списков и другие фабрики коллекций.
  • Более поздние версии добавили методы для удобного копирования/создания неизменяемых копий коллекций (например, List.copyOf) и интеграцию с новыми возможностями языка. Также улучшена совместимость с потоками и API стримов.

В целом эволюция шла в сторону расширения API через default-методы, добавления фабрик неизменяемых коллекций и упрощения преобразования в потоки/массивы.

Расширенные и нестандартные примеры использования List

1) subList как «вид» исходного списка - поведение и подводные камни:

Пример java
import java.util.*;
class Adv1{
    public static void main(String[] args){
        List<String> base = new ArrayList<><>(Arrays.asList("a","b","c","d"));
        List<String> view = base.subList(1, 3); // [b,c]
        view.clear(); // удаляет элементы и из base
        System.out.println(base);
    }
}
[a, d]

Комментарий: subList не создает отдельного массива, поэтому нужно осторожно модифицировать оба интерфейса, особенно при параллельном доступе.

2) Использование ListIterator для модификации во время обхода (без ConcurrentModificationException):

Пример java
import java.util.*;
class Adv2{
    public static void main(String[] args){
        List<Integer> l = new ArrayList<><>(Arrays.asList(1,2,3));
        ListIterator<Integer> it = l.listIterator();
        while(it.hasNext()){
            int v = it.next();
            if (v == 2) it.add(20); // безопасная вставка в итераторе
        }
        System.out.println(l);
    }
}
[1, 2, 20, 3]

3) Потокобезопасность: Collections.synchronizedList и CopyOnWriteArrayList:

Пример java
import java.util.*;
import java.util.concurrent.*;
class Adv3{
    public static void main(String[] args){
        List<String> sync = Collections.synchronizedList(new ArrayList<><>());
        List<String> cow = new CopyOnWriteArrayList<>();
        sync.add("a"); cow.add("a");
        // при итерации по sync нужен внешний монитор
        synchronized(sync){ for(String s: sync) System.out.println(s); }
    }
}
a

4) Преобразование в массив с указанием типа (рекомендуется в современных версиях):

Пример java
import java.util.*;
class Adv4{
    public static void main(String[] args){
        List<String> l = Arrays.asList("x","y");
        String[] arr = l.toArray(new String[0]);
        System.out.println(java.util.Arrays.toString(arr));
    }
}
[x, y]

5) Использование Stream API и Collectors для создания списков различных типов, включая неизменяемые:

Пример java
import java.util.*;
import java.util.stream.*;
class Adv5{
    public static void main(String[] args){
        List<Integer> l = IntStream.range(0,5).boxed().collect(Collectors.toList());
        List<Integer> unmod = l.stream().filter(n->n%2==0).collect(Collectors.toUnmodifiableList());
        System.out.println(l);
        System.out.println(unmod);
    }
}
[0, 1, 2, 3, 4]
[0, 2, 4]

6) Сортировка и стабильность: list.sort(Comparator) поддерживает стабильную сортировку (сохранение порядка равных элементов) в стандартных реализациях.

7) Удаление по условию и сложные фильтрации:

Пример java
import java.util.*;
class Adv6{
    public static void main(String[] args){
        List<String> names = new ArrayList<>(Arrays.asList("Anna","Bob","Alice","Tom"));
        names.removeIf(s->s.length() <= 3);
        System.out.println(names);
    }
}
[Anna, Alice]

8) Пример создания неизменяемой копии и сравнение ссылок:

Пример java
import java.util.*;
class Adv7{
    public static void main(String[] args){
        List<String> src = new ArrayList<>(Arrays.asList("x","y"));
        List<String> copy = List.copyOf(src); // неизменяемая копия
        System.out.println(copy);
        // copy.add("z"); // UnsupportedOperationException
    }
}
[x, y]

Примечание: некоторые методы поведения зависят от версии JDK и выбранной реализации списка.

джава list function comments

En
List Returns an array of strings naming the files and directories in the directory