Java for Beginner
676 subscribers
546 photos
155 videos
12 files
836 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
ArrayList: особенности и внутреннее устройство

ArrayList — это динамический массив, который является одной из наиболее часто используемых реализаций интерфейса List в Java. Он предоставляет упорядоченную коллекцию элементов и позволяет доступ к ним по индексу. В этом посте мы рассмотрим особенности и внутреннее устройство ArrayList.

Основные особенности ArrayList

Динамический размер:
В отличие от обычного массива, размер ArrayList может динамически изменяться. При добавлении элементов его емкость увеличивается автоматически.

Доступ по индексу:
ArrayList обеспечивает быстрый доступ к элементам по индексу. Операция получения элемента по индексу выполняется за постоянное время O(1).

Упорядоченность:
Элементы в ArrayList хранятся в том порядке, в котором они были добавлены.

Не синхронизированность:
ArrayList не является потокобезопасной коллекцией. Если необходимо использовать его в многопоточной среде, требуется внешняя синхронизация.


Внутреннее устройство ArrayList

ArrayList реализован как обертка над массивом, который динамически изменяет свой размер по мере добавления или удаления элементов. Рассмотрим основные аспекты внутреннего устройства ArrayList.

Массив для хранения элементов:
Внутри ArrayList используется массив Object[], называемый elementData, для хранения элементов.
private transient Object[] elementData;


Размер и емкость:
ArrayList имеет два важных параметра: size и capacity. size — это количество элементов, фактически находящихся в списке, а capacity — это размер внутреннего массива elementData.

Инициализация:
При создании ArrayList можно задать начальную емкость. Если она не указана, используется значение по умолчанию (обычно 10).
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = {};
} else {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
}


Если начальная емкость не указана:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}


Добавление элементов:

Метод add добавляет элемент в конец списка. При добавлении элемента проверяется, хватает ли текущей емкости массива. Если нет, создается новый массив с увеличенной емкостью, и элементы копируются в него.
public boolean add(E e) {
ensureCapacityInternal(size + 1); // проверка емкости
elementData[size++] = e;
return true;
}

private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}

private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // увеличивается на 50%
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}


Получение элементов:

Метод get возвращает элемент по указанному индексу. Операция выполняется за постоянное время O(1).
public E get(int index) {
rangeCheck(index);
return elementData(index);
}

E elementData(int index) {
return (E) elementData[index];
}


Удаление элементов:

Метод remove удаляет элемент по индексу или по значению. После удаления элемента все последующие элементы сдвигаются влево, чтобы заполнить пробел.
public E remove(int index) {
rangeCheck(index);

modCount++;
E oldValue = elementData(index);

int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
elementData[--size] = null; // clear to let GC do its work

return oldValue;
}


#Java #Training #Medium #ArrayList
Что выведет код?

import java.util.HashMap;

public class HashMapChallenge {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
map.put("D", 4);
map.put("E", 5);

int result = 0;
for (String key : map.keySet()) {
if (key.compareTo("C") < 0) {
result += map.get(key);
} else {
result -= map.get(key);
}
}

System.out.println("Result: " + result);
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
38%
Result: -3
0%
Result: -5
13%
Result: 1
50%
Result: -9
И возразить нечего🤪

https://t.me/Java_for_beginner_dev

#Mems
Основные компоненты ArrayList

Массив для хранения элементов:

Внутри ArrayList используется массив Object[] для хранения элементов. Этот массив называется elementData.
private transient Object[] elementData;


Размер и емкость:

ArrayList имеет два важных параметра: size и capacity. size — это текущее количество элементов в списке, а capacity — это размер внутреннего массива elementData.

private int size;


Инициализация:

ArrayList можно создать с заданной начальной емкостью или без неё. Если емкость не указана, используется значение по умолчанию (обычно 10).
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = {};
} else {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
}

public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}


Пример использования ArrayList
import java.util.ArrayList;

public class ArrayListExample {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();

// Добавление элементов
list.add("Apple");
list.add("Banana");
list.add("Cherry");

// Получение элементов
System.out.println("First element: " + list.get(0)); // Apple

// Удаление элемента
list.remove("Banana");
System.out.println("List after removal: " + list); // [Apple, Cherry]

// Размер списка
System.out.println("Size of list: " + list.size()); // 2
}
}


#Java #Training #Medium #ArrayList
LinkedList, отличие от ArrayList

LinkedList — это одна из реализаций интерфейса List в Java. Он представляет собой двусвязный список, где каждый элемент содержит ссылки на предыдущий и следующий элементы. LinkedList подходит для сценариев, где часто выполняются операции вставки и удаления элементов в середине списка.

Особенности LinkedList

Двусвязный список:
Каждый элемент в LinkedList содержит ссылки на предыдущий и следующий элементы, что позволяет эффективно добавлять и удалять элементы в середине списка.

Доступ к элементам:
В отличие от ArrayList, доступ к элементам в LinkedList осуществляется линейным поиском, что делает его менее эффективным для операций случайного доступа.

Итерация по элементам:
Поскольку элементы связаны ссылками, итерация по списку может быть выполнена с постоянным использованием памяти и временем для операций добавления и удаления.

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

Отличие от ArrayList

Структура хранения:
ArrayList использует массив для хранения элементов, тогда как LinkedList использует двусвязный список.

Время доступа:
ArrayList обеспечивает быстрый доступ к элементам по индексу (O(1)), в то время как LinkedList требует линейного времени (O(n)) для доступа к элементам по индексу.


Вставка и удаление элементов:
Вставка и удаление элементов в середине списка эффективнее в LinkedList (O(1)), в то время как в ArrayList эти операции требуют сдвига элементов и выполняются за время O(n).

Емкость и размер:
В ArrayList размер массива увеличивается автоматически при добавлении элементов, что может привести к перераспределению памяти. LinkedList не имеет проблемы перераспределения памяти, так как элементы связаны ссылками.

Примеры использования
import java.util.LinkedList;
import java.util.List;

public class LinkedListExample {
public static void main(String[] args) {
List<String> linkedList = new LinkedList<>();

// Добавление элементов
linkedList.add("Apple");
linkedList.add("Banana");
linkedList.add("Cherry");

// Получение элемента
System.out.println("First element: " + linkedList.get(0)); // Apple

// Вставка элемента
linkedList.add(1, "Orange");
System.out.println("After insertion: " + linkedList); // [Apple, Orange, Banana, Cherry]

// Удаление элемента
linkedList.remove("Banana");
System.out.println("After removal: " + linkedList); // [Apple, Orange, Cherry]

// Итерация по элементам
for (String fruit : linkedList) {
System.out.println(fruit);
}
}
}


Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://habr.com/ru/articles/127864/
https://javarush.com/groups/posts/1938-linkedlist

#Java #Training #Medium #LinkedList
Что выведет код?

import java.util.LinkedList;

public class LinkedListChallenge {
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
list.add(5);
list.add(15);
list.add(25);
list.add(35);
list.add(45);

int sum = 0;
for (int i = 1; i < list.size(); i += 2) {
sum += list.get(i);
}

list.add(1, sum);
list.removeLast();
list.addFirst(sum);

int result = 1;
for (int value : list) {
result *= value;
}

System.out.println("Result: " + result);
}
}


#Tasks
Запоминаем!☝️

https://t.me/Java_for_beginner_dev

#Mems
Внутреннее устройство и основные методы LinkedList

LinkedList основан на структуре данных двусвязного списка. Каждый элемент списка представлен узлом (Node), который содержит данные и ссылки на предыдущий и следующий узлы.

Класс Node:

Класс Node — это внутренний класс LinkedList, который представляет элемент списка.
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;

Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}


Узлы:

LinkedList содержит ссылки на первый (first) и последний (last) узлы списка.
transient Node<E> first;
transient Node<E> last;


Добавление элементов:

При добавлении элемента в конец списка создается новый узел, и ссылки next и prev соответствующим образом обновляются.
public boolean add(E e) {
linkLast(e);
return true;
}

void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}


Удаление элементов:

Удаление элемента включает обновление ссылок next и prev соседних узлов.
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}

E unlink(Node<E> x) {
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;

if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}

if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}

x.item = null;
size--;
modCount++;
return element;
}


Поиск узла:

Для доступа к элементу по индексу необходимо пройти по списку от начала или конца в зависимости от того, ближе ли индекс к началу или концу списка.

Node<E> node(int index) {
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}


Основные методы LinkedList

Добавление элементов:

add(E e): добавляет элемент в конец списка.
add(int index, E element): вставляет элемент по указанному индексу.

linkedList.add("Apple");
linkedList.add(1, "Orange");


Удаление элементов:

remove(int index): удаляет элемент по указанному индексу.
remove(Object o): удаляет первое вхождение указанного элемента.

linkedList.remove(1);
linkedList.remove("Apple");


Получение элементов:

get(int index): возвращает элемент по указанному индексу.
getFirst(), getLast(): возвращают первый и последний элементы соответственно.

String first = linkedList.getFirst();
String element = linkedList.get(1);


Другие методы:

size(): возвращает количество элементов в списке.
clear(): удаляет все элементы из списка.
contains(Object o): проверяет, содержится ли указанный элемент в списке.

int size = linkedList.size();
linkedList.clear();
boolean containsApple = linkedList.contains("Apple");


#Java #Training #Medium #LinkedList
CopyOnWriteArrayList, особенности и преимущества

CopyOnWriteArrayList — это потокобезопасная реализация интерфейса List в Java, которая отличается тем, что при каждой операции изменения создает копию массива. Это делает CopyOnWriteArrayList особенно подходящей для сценариев, где чтение данных происходит гораздо чаще, чем запись.

Особенности CopyOnWriteArrayList

Потокобезопасность:
Все методы, изменяющие содержимое списка, синхронизированы, что обеспечивает безопасность при использовании в многопоточной среде без явной необходимости в дополнительных блокировках.

Immutable при чтении:
Операции чтения (такие как get(), iterator(), и т.д.) не требуют блокировок и происходят в постоянное время (O(1)), так как они работают с неизменяемыми копиями массива.

Создание копий при изменении:
Каждая операция записи (добавление, удаление, обновление элемента) создает новую копию всего внутреннего массива. Это может быть дорогостоящим по памяти и времени при частых операциях записи.

Консистентные итераторы:
Итераторы, возвращаемые CopyOnWriteArrayList, никогда не выбрасывают ConcurrentModificationException, потому что они работают с моментальной копией данных на момент их создания.


Отсутствие возможности удаления через итератор:
Методы итератора, такие как remove(), не поддерживаются и выбрасывают UnsupportedOperationException.


Преимущества CopyOnWriteArrayList

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

Предсказуемое поведение:
Из-за неизменности копий массива при чтении, итераторы не видят промежуточных состояний, что делает поведение программы более предсказуемым.

Безопасность в многопоточных средах:
CopyOnWriteArrayList идеален для программ, которые требуют безопасного доступа к коллекции из нескольких потоков без использования внешних блокировок.

Основные особенности внутреннего устройства

Массив как основа хранения:
Внутренне CopyOnWriteArrayList использует массив для хранения элементов. Этот массив называется array и является volatile-полем, что гарантирует видимость изменений между потоками.


Копирование при записи:
При выполнении любой операции, изменяющей содержимое списка (например, add(), remove(), set()), создается новая копия массива с внесенными изменениями. Это обеспечивает неизменяемость исходного массива, используемого для чтения, и потокобезопасность операций.

Синхронизация методов:
Методы, которые изменяют содержимое списка, синхронизированы, чтобы гарантировать, что только один поток может выполнять изменение в любой момент времени.

Чтение без блокировок:
Операции чтения (такие как get(), size(), итерация) не требуют блокировок, так как они работают с неизменяемыми копиями массива.

Преимущества:

Потокобезопасность: CopyOnWriteArrayList позволяет безопасно использовать коллекцию в многопоточной среде без явной синхронизации.

Высокая производительность для чтения: Благодаря неизменяемости массивов, операции чтения очень быстрые.
Консистентные итераторы: Итераторы никогда не выбрасывают ConcurrentModificationException, так как они работают с моментальной копией данных.

Недостатки:

Высокие затраты на изменение: Из-за копирования массива при каждой операции изменения, CopyOnWriteArrayList может быть неэффективным для частых операций записи.
Высокие затраты памяти: Копирование массива создает дополнительную нагрузку на память.

Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://for-each.dev/lessons/b/-java-copy-on-write-arraylist
https://www.baeldung.com/java-copy-on-write-arraylist

#Java #Training #Medium #CopyOnWriteArrayList
Варианты ответа:
Anonymous Quiz
0%
Sum: 115
0%
Sum: 130
20%
Sum: 90
80%
Sum: 120
Что выведет код?

import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListChallenge {
public static void main(String[] args) {
CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
list.add(10);
list.add(20);
list.add(30);
list.add(40);
list.add(50);

// Iterate and modify
for (int num : list) {
if (num % 20 == 0) {
list.remove(Integer.valueOf(num));
}
}

// Add new elements
list.add(5);
list.add(25);

int sum = 0;
for (int num : list) {
sum += num;
}

System.out.println("Sum: " + sum);
}
}


#Tasks
Вот так бывает когда разраб остается один😐

https://t.me/Java_for_beginner_dev

#Mems
Основные методы CopyOnWriteArrayList и примеры использования

Добавление элементов:

add(E e): добавляет элемент в конец списка.
add(int index, E element): вставляет элемент по указанному индексу.
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("Apple");
list.add(1, "Banana");


Удаление элементов:

remove(Object o): удаляет первое вхождение указанного элемента.
remove(int index): удаляет элемент по указанному индексу.
list.remove("Banana");
list.remove(0);


Обновление элементов:

set(int index, E element): заменяет элемент по указанному индексу новым элементом.
list.set(0, "Orange");


Получение элементов:

get(int index): возвращает элемент по указанному индексу.
String fruit = list.get(0);


Проверка содержимого:

contains(Object o): проверяет, содержится ли указанный элемент в списке.
size(): возвращает количество элементов в списке.

boolean containsApple = list.contains("Apple");
int size = list.size();


Итерация по элементам:

iterator(): возвращает итератор по элементам списка.
for (String fruit : list) {
System.out.println(fruit);
}


Примеры использования
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.List;
import java.util.Iterator;

public class CopyOnWriteArrayListMethodsExample {
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<>();

// Добавление элементов
list.add("Apple");
list.add("Banana");
list.add("Cherry");
System.out.println("After adding elements: " + list);

// Вставка элемента
list.add(1, "Orange");
System.out.println("After insertion: " + list);

// Обновление элемента
list.set(2, "Mango");
System.out.println("After updating: " + list);

// Удаление элемента по индексу
list.remove(3);
System.out.println("After removing by index: " + list);

// Удаление элемента по значению
list.remove("Apple");
System.out.println("After removing by value: " + list);

// Проверка содержимого
boolean containsBanana = list.contains("Banana");
System.out.println("Contains Banana: " + containsBanana);

// Получение элемента
String fruit = list.get(0);
System.out.println("Element at index 0: " + fruit);

// Итерация по элементам
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println("Iterating: " + iterator.next());
}

// Размер списка
int size = list.size();
System.out.println("Size of list: " + size);

// Очистка списка
list.clear();
System.out.println("After clearing: " + list);
}
}


#Java #Training #Medium #CopyOnWriteArrayList
Всем доброго субботнего утра!☀️

Как Вы собираетесь провести эти выходные?
Делитесь с нами в чате -
https://t.me/Java_Beginner_chat
Секрет раскрыт😮

https://t.me/Java_for_beginner_dev

#Mems
Сегодня воскресение бл…😡😡😡

https://t.me/Java_for_beginner_dev

#Mems
This media is not supported in your browser
VIEW IN TELEGRAM
Напоминаю!☝️

Сегодня в 16:00 по МСК, мы вновь собираемся на онлайн встречу)))

От нас лайф-кодинг, от Вас хорошее настроение и подсказки!))))😉

Ждем всех!🫡