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

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Что выведет код?

import java.util.HashMap;
import java.util.Map;

public class HashMapChallenge {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("one", 1);
map.put("two", 2);
map.put("three", 3);
map.put("four", 4);

int result = processMap(map);
System.out.println(result);
}

public static int processMap(Map<String, Integer> map) {
int sum = 0;
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getKey().length() % 2 == 0) {
sum += entry.getValue() * 2;
} else {
sum += entry.getValue() * 3;
}
}
return sum;
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
20%
18
60%
26
20%
-8
0%
139
Внутренняя структура ConcurrentHashMap

ConcurrentHashMap состоит из хеш-таблицы, которая делится на сегменты (в старых версиях) или использует мелкие блокировки (в новых версиях), чтобы минимизировать блокировки и увеличить параллелизм.

Бакеты (Buckets):

Подобно HashMap, ConcurrentHashMap использует массив бакетов для хранения пар "ключ-значение".
Внутри каждого бакета используется связанный список (или дерево в случае большого числа элементов) для хранения элементов, что позволяет управлять коллизиями.


Сегменты (Segments) (в старых версиях):


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


Lock Striping (в новых версиях):

В новых версиях (Java 8 и позже) ConcurrentHashMap использует более мелкие блокировки, известные как lock striping.
Вместо сегментов используется механизм блокировок на уровне бакетов или групп бакетов, что уменьшает вероятность блокировок и увеличивает производительность.


Механизмы синхронизации

Мелкие блокировки (Fine-Grained Locks):

ConcurrentHashMap использует мелкие блокировки для управления доступом к отдельным бакетам или небольшим группам бакетов.
Это позволяет нескольким потокам одновременно выполнять операции над различными частями хеш-таблицы, минимизируя блокировки и повышая параллелизм.


CAS (Compare-And-Swap):

Для некоторых операций, таких как вставка и обновление значений, используется механизм CAS, который позволяет атомарно обновлять значения без использования явных блокировок.
CAS операции обеспечивают высокую производительность и минимизируют затраты на синхронизацию.


Механизм Reentrant Lock:

Внутренне для блокировок ConcurrentHashMap использует ReentrantLock, что позволяет потокам безопасно входить в блокировку несколько раз.
ReentrantLock предоставляет больше возможностей управления, таких как блокировка с тайм-аутом и попытка блокировки без ожидания.


Внутреннее устройство бакетов

Каждый бакет в ConcurrentHashMap представлен объектом типа Node:
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V value;
volatile Node<K,V> next;

Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}

public final K getKey() {
return key;
}

public final V getValue() {
return value;
}

public final String toString() {
return key + "=" + value;
}

public final int hashCode() {
return key.hashCode() ^ value.hashCode();
}

public final V setValue(V value) {
throw new UnsupportedOperationException();
}

public final boolean equals(Object o) {
Object k, v, u;
Map.Entry<?,?> e;
return ((o instanceof Map.Entry) &&
(k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
(v = e.getValue()) != null &&
(k == key || k.equals(key)) &&
(v == (u = value) || v.equals(u)));
}
}


#Java #Training #Medium #ConcurrentHashMap
Механизмы синхронизации

Пример использования CAS для вставки элемента:
final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null,
new Node<K,V>(hash, key, value, null)))
break; // no lock when adding to empty bin
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
else {
V oldVal = null;
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node<K,V> e = f;; ++binCount) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.value;
if (!onlyIfAbsent)
e.value = value;
break;
}
Node<K,V> pred = e;
if ((e = e.next) == null) {
pred.next = new Node<K,V>(hash, key,
value, null);
break;
}
}
}
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.value;
if (!onlyIfAbsent)
p.value = value;
}
}
}
}
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}
addCount(1L, binCount);
return null;
}


#Java #Training #Medium #ConcurrentHashMap
LinkedHashMap

LinkedHashMap
— это класс из пакета java.util, который является расширением HashMap и сохраняет порядок вставки или порядок доступа к элементам. Это достигается за счет использования связанного списка, который поддерживает порядок элементов.

Основные характеристики LinkedHashMap

Порядок элементов: LinkedHashMap поддерживает порядок элементов, либо порядок вставки, либо порядок последнего доступа, в зависимости от конфигурации.
Производительность: Поиск, вставка и удаление элементов имеют сложность O(1), аналогично HashMap.
Связанный список: Внутренне LinkedHashMap использует связанный список для поддержания порядка элементов.

Структура LinkedHashMap

Бакеты (Buckets):

LinkedHashMap использует массив бакетов, аналогично HashMap. Каждый бакет представлен связным списком элементов, у которых произошла коллизия по хеш-коду.

Связанный список:

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

Два порядка:

Порядок вставки (Insertion Order): Элементы хранятся в порядке их добавления в карту.
Порядок доступа (Access Order): Элементы перемещаются в конец списка при их доступе, что полезно для реализации LRU-кэшей (Least Recently Used).


Создание и использование LinkedHashMap
import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapExample {
public static void main(String[] args) {
// Создание LinkedHashMap с порядком вставки
LinkedHashMap<String, Integer> insertionOrderMap = new LinkedHashMap<>();

// Добавление элементов
insertionOrderMap.put("Apple", 50);
insertionOrderMap.put("Banana", 30);
insertionOrderMap.put("Orange", 20);

// Перебор элементов в порядке вставки
System.out.println("Insertion Order:");
for (Map.Entry<String, Integer> entry : insertionOrderMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}

// Создание LinkedHashMap с порядком доступа
LinkedHashMap<String, Integer> accessOrderMap = new LinkedHashMap<>(16, 0.75f, true);

// Добавление элементов
accessOrderMap.put("Apple", 50);
accessOrderMap.put("Banana", 30);
accessOrderMap.put("Orange", 20);

// Доступ к элементу, что изменит его порядок
accessOrderMap.get("Banana");

// Перебор элементов в порядке доступа
System.out.println("\nAccess Order:");
for (Map.Entry<String, Integer> entry : accessOrderMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}


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

LinkedHashMap расширяет HashMap и добавляет дополнительную функциональность для поддержания порядка элементов.

Класс Entry:

Внутренний класс Entry наследуется от HashMap.Entry и добавляет ссылки на предыдущий и следующий элементы, что образует двусвязный список.

static class Entry<K, V> extends HashMap.Node<K, V> {
Entry<K, V> before, after;

Entry(int hash, K key, V value, HashMap.Node<K, V> next) {
super(hash, key, value, next);
}
}


Указатели на первый и последний элементы:

LinkedHashMap содержит указатели на первый и последний элементы списка, что позволяет быстро выполнять вставку и удаление элементов в конец списка.
transient LinkedHashMap.Entry<K, V> head;
transient LinkedHashMap.Entry<K, V> tail;

#Java #Training #Medium #LinkedHashMap
Методы для управления порядком:

LinkedHashMap переопределяет методы newNode и afterNodeAccess, чтобы управлять порядком элементов.

Node<K, V> newNode(int hash, K key, V value, Node<K, V> e) {
LinkedHashMap.Entry<K, V> p = new LinkedHashMap.Entry<>(hash, key, value, e);
linkNodeLast(p);
return p;
}

void afterNodeAccess(Node<K, V> e) {
LinkedHashMap.Entry<K, V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K, V> p = (LinkedHashMap.Entry<K, V>) e, b = p.before, a = p.after;
p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}


Порядок вставки (Insertion Order)
import java.util.LinkedHashMap;
import java.util.Map;

public class InsertionOrderExample {
public static void main(String[] args) {
// Создание LinkedHashMap с порядком вставки
LinkedHashMap<String, Integer> map = new LinkedHashMap<>();

// Добавление элементов
map.put("Apple", 50);
map.put("Banana", 30);
map.put("Orange", 20);
map.put("Grapes", 40);

// Перебор элементов в порядке вставки
System.out.println("Insertion Order:");
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}


В этом примере элементы добавляются в порядке "Apple", "Banana", "Orange", "Grapes", и при переборе они выводятся в том же порядке.

Порядок доступа (Access Order)
import java.util.LinkedHashMap;
import java.util.Map;

public class AccessOrderExample {
public static void main(String[] args) {
// Создание LinkedHashMap с порядком доступа
LinkedHashMap<String, Integer> map = new LinkedHashMap<>(16, 0.75f, true);

// Добавление элементов
map.put("Apple", 50);
map.put("Banana", 30);
map.put("Orange", 20);
map.put("Grapes", 40);

// Доступ к элементу, что изменит его порядок
map.get("Banana");
map.get("Apple");

// Перебор элементов в порядке доступа
System.out.println("Access Order:");
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}


В этом примере элементы добавляются в порядке "Apple", "Banana", "Orange", "Grapes". После доступа к "Banana" и "Apple" они перемещаются в конец списка, и при переборе порядок будет "Orange", "Grapes", "Banana", "Apple".

Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://habr.com/ru/articles/129037/
https://www.baeldung.com/java-linked-hashmap

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

import java.util.ArrayList;
import java.util.List;

public class ListConcatenationChallenge {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("a");
list1.add("b");
list1.add("c");

List<String> list2 = new ArrayList<>();
list2.add("d");
list2.add("e");
list2.add("f");

String result = concatenateLists(list1, list2);
System.out.println(result);
}

public static String concatenateLists(List<String> list1, List<String> list2) {
StringBuilder sb = new StringBuilder();

for (int i = 0; i < list1.size(); i++) {
sb.append(list1.get(i));
sb.append(list2.get(i));
}

return sb.toString();
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
0%
"abcdef"
25%
"adbcef"
75%
"adbecf"
0%
"abcdfe"
Ну хоть что-то ищет😂

https://t.me/Java_for_beginner_dev

#Mems
Внутреннее устройство LinkedHashMap

1. Связанный список для порядка элементов

LinkedHashMap расширяет HashMap, добавляя поддержку связанного списка для поддержания порядка элементов. Каждый элемент хранится в виде узла двусвязного списка, что позволяет поддерживать порядок вставки или порядок доступа.
static class Entry<K, V> extends HashMap.Node<K, V> {
Entry<K, V> before, after;

Entry(int hash, K key, V value, HashMap.Node<K, V> next) {
super(hash, key, value, next);
}
}


2. Поля для управления порядком

LinkedHashMap добавляет два новых поля для управления порядком элементов:

transient LinkedHashMap.Entry<K, V> head;
transient LinkedHashMap.Entry<K, V> tail;

Эти поля указывают на первый и последний элементы в связанном списке.

3. Механизм управления порядком элементов

Для управления порядком элементов LinkedHashMap переопределяет методы newNode, afterNodeAccess и afterNodeInsertion:

newNode: Создает новый узел и добавляет его в конец связанного списка.
Node<K, V> newNode(int hash, K key, V value, Node<K, V> e) {
LinkedHashMap.Entry<K, V> p = new LinkedHashMap.Entry<>(hash, key, value, e);
linkNodeLast(p);
return p;
}

private void linkNodeLast(LinkedHashMap.Entry<K, V> p) {
LinkedHashMap.Entry<K, V> last = tail;
tail = p;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}


afterNodeAccess: Обновляет порядок элементов при доступе, если карта настроена на порядок доступа.
void afterNodeAccess(Node<K, V> e) {
LinkedHashMap.Entry<K, V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K, V> p = (LinkedHashMap.Entry<K, V>) e, b = p.before, a = p.after;
p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}


afterNodeInsertion: Удаляет самый старый элемент, если карта настроена на удаление старейших элементов.
void afterNodeInsertion(boolean evict) {
LinkedHashMap.Entry<K, V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}


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


1. Конструкторы

LinkedHashMap предоставляет несколько конструкторов для создания карты с различными настройками:

public LinkedHashMap() {
super();
}

public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
}

public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
}

public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}


2. Метод put
Метод put добавляет пару ключ-значение в карту. Если ключ уже существует, его значение обновляется.
public V put(K key, V value) {
return super.put(key, value);
}


3. Метод get

Метод get возвращает значение, связанное с указанным ключом. Если ключ не найден, возвращается null. При этом порядок элементов обновляется, если карта настроена на порядок доступа.

public V get(Object key) {
Node<K, V> e;
if ((e = getNode(hash(key), key)) == null)
return null;
if (accessOrder)
afterNodeAccess(e);
return e.value;
}


4. Метод remove
Метод remove удаляет пару ключ-значение по указанному ключу и возвращает удаленное значение.
public V remove(Object key) {
Node<K, V> e;
return (e = removeNode(hash(key), key, null, false, true)) == null ? null : e.value;
}


5. Метод containsKey


Метод containsKey проверяет, содержит ли карта указанный ключ.
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}


#Java #Training #Medium #LinkedHashMap
6. Метод containsValue

Метод containsValue проверяет, содержит ли карта указанное значение.

public boolean containsValue(Object value) {
for (Node<K, V> e = head; e != null; e = e.after) {
if (value.equals(e.value))
return true;
}
return false;
}


7. Метод clear


Метод clear очищает карту, удаляя все элементы.
public void clear() {
super.clear();
head = tail = null;
}


8. Метод entrySet

Метод entrySet возвращает набор всех пар ключ-значение в карте.
public Set<Map.Entry<K, V>> entrySet() {
return new LinkedEntrySet();
}


#Java #Training #Medium #LinkedHashMap
"Если мы в ответе за тех кого приручили, в ответе ли мы за то, что они спроектировали?"🧐

#Mems
Введение в TreeMap, принципы работы и внутреннее устройство

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

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

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


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


Красно-черное дерево — это тип самобалансирующегося бинарного дерева поиска с следующими свойствами:

Каждый узел либо красный, либо черный.
Корень дерева всегда черный.
Все листья (NULL-указатели) считаются черными.
Красный узел не может иметь красных дочерних узлов (т.е., красные узлы не могут быть рядом).
Любой путь от корня до листа содержит одинаковое количество черных узлов.


Класс Entry

Внутренний класс Entry представляет узел в дереве:

static final class Entry<K, V> implements Map.Entry<K, V> {
K key;
V value;
Entry<K, V> left, right, parent;
boolean color = BLACK;

Entry(K key, V value, Entry<K, V> parent) {
this.key = key;
this.value = value;
this.parent = parent;
}

public K getKey() { return key; }
public V getValue() { return value; }
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
}


Принципы работы TreeMap

Вставка
При вставке элемента TreeMap сначала находит подходящее место для нового элемента, а затем вставляет его как красный узел и балансирует дерево.

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


Поиск
Поиск элемента осуществляется путем последовательного сравнения ключей и движения по дереву (влево или вправо), пока не будет найден нужный ключ.


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


Метод put
Метод put добавляет пару ключ-значение в TreeMap:
public V put(K key, V value) {
Entry<K, V> t = root;
if (t == null) {
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K, V> parent;
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0) t = t.left;
else if (cmp > 0) t = t.right;
else return t.setValue(value);
} while (t != null);
} else {
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0) t = t.left;
else if (cmp > 0) t = t.right;
else return t.setValue(value);
} while (t != null);
}
Entry<K, V> e = new Entry<>(key, value, parent);
if (cmp < 0) parent.left = e;
else parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}


Метод get

Метод get возвращает значение по ключу:
public V get(Object key) {
Entry<K, V> p = getEntry(key);
return (p == null ? null : p.value);
}

final Entry<K, V> getEntry(Object key) {
if (comparator != null) return getEntryUsingComparator(key);
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K, V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0) p = p.left;
else if (cmp > 0) p = p.right;
else return p;
}
return null;
}


Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://javarush.com/groups/posts/2584-osobennosti-treemap
https://www.baeldung.com/java-treemap

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

public class ComplexVariableAssignmentChallenge {
public static void main(String[] args) {
int intVar1 = 8;
int intVar2 = 3;
double doubleVar1 = 4.5;
double doubleVar2 = 2.5;
String strVar1 = "Sum: ";
String strVar2 = "Product: ";

String resultSum = strVar1 + (intVar1 + doubleVar1) + ", " + (intVar2 + doubleVar2);
String resultProduct = strVar2 + (intVar1 * doubleVar1) + ", " + (intVar2 * doubleVar2);
System.out.println(resultSum);
System.out.println(resultProduct);
}
}

#Tasks
Суровая правда жизни🤌

https://t.me/Java_for_beginner_dev

#Mems
Основные методы TreeMap и их применение

Конструкторы TreeMap

Без параметров
TreeMap<String, Integer> map = new TreeMap<>();


С компаратором

TreeMap<String, Integer> map = new TreeMap<>(Comparator.reverseOrder());


Из другого Map
Map<String, Integer> anotherMap = new HashMap<>();
TreeMap<String, Integer> map = new TreeMap<>(anotherMap);


Из SortedMap
SortedMap<String, Integer> sortedMap = new TreeMap<>(anotherMap);
TreeMap<String, Integer> map = new TreeMap<>(sortedMap);


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

Метод put

Добавляет пару ключ-значение. Если ключ уже существует, то значение обновляется.
TreeMap<String, Integer> map = new TreeMap<>();
map.put("Apple", 50);
map.put("Banana", 30);
map.put("Orange", 20);


Метод get

Возвращает значение, связанное с указанным ключом.
Integer value = map.get("Apple");
System.out.println("Value for key 'Apple': " + value);


Метод remove

Удаляет запись по ключу и возвращает удаленное значение.
Integer removedValue = map.remove("Banana");
System.out.println("Removed value: " + removedValue);


Метод containsKey

Проверяет, содержится ли ключ в карте.
boolean contains = map.containsKey("Orange");
System.out.println("Contains key 'Orange': " + contains);


Метод containsValue

Проверяет, содержится ли значение в карте.
boolean containsValue = map.containsValue(20);
System.out.println("Contains value 20: " + containsValue);


Метод size

Возвращает количество элементов в карте.
int size = map.size();
System.out.println("Size of the map: " + size);


Метод isEmpty

Проверяет, пуста ли карта.
boolean isEmpty = map.isEmpty();
System.out.println("Is the map empty: " + isEmpty);


Метод clear

Очищает карту, удаляя все элементы.
map.clear();
System.out.println("Size after clear: " + map.size());


Специфические методы TreeMap

Метод firstKey

Возвращает первый (минимальный) ключ.
String firstKey = map.firstKey();
System.out.println("First key: " + firstKey);


Метод lastKey

Возвращает последний (максимальный) ключ.
String lastKey = map.lastKey();
System.out.println("Last key: " + lastKey);


Метод pollFirstEntry

Удаляет и возвращает первый (минимальный) элемент.
Map.Entry<String, Integer> firstEntry = map.pollFirstEntry();
System.out.println("Polled first entry: " + firstEntry);


Метод pollLastEntry


Удаляет и возвращает последний (максимальный) элемент.
Map.Entry<String, Integer> lastEntry = map.pollLastEntry();
System.out.println("Polled last entry: " + lastEntry);



Примеры использования TreeMap

Пример 1: Печать элементов в порядке возрастания ключей
TreeMap<String, Integer> map = new TreeMap<>();
map.put("Apple", 50);
map.put("Banana", 30);
map.put("Orange", 20);

for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}


Пример 2: Использование метода subMap

Возвращает отображение части карты.
map.put("Grapes", 40);
SortedMap<String, Integer> subMap = map.subMap("Apple", "Orange");
for (Map.Entry<String, Integer> entry : subMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}


Пример 3: Получение диапазона ключей
NavigableMap<String, Integer> tailMap = map.tailMap("Banana", true);
for (Map.Entry<String, Integer> entry : tailMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}

#Java #Training #Medium #TreeMap
WeakHashMap, особенности использования

WeakHashMap — это реализация интерфейса Map, которая использует слабые ссылки на ключи. Эта структура данных особенно полезна для кеширования, где не требуется жесткая ссылка на ключи, и объекты могут быть автоматически удалены сборщиком мусора, когда они больше не используются. Рассмотрим подробно особенности и использование WeakHashMap.

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

Слабые ссылки: Ключи в WeakHashMap хранятся как слабые ссылки. Это значит, что если на объект-ключ нет жестких ссылок из других объектов, то он может быть удален сборщиком мусора.
Автоматическое удаление: При удалении ключа сборщиком мусора, соответствующая пара ключ-значение также удаляется из карты.
Потокобезопасность: WeakHashMap не является потокобезопасной и требует внешней синхронизации при доступе из нескольких потоков.


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

WeakHashMap основан на массиве сегментов (bucket), где каждая ячейка массива может содержать связанный список элементов, как в HashMap. Однако, ключи хранятся в виде слабых ссылок (WeakReference), что позволяет сборщику мусора удалять их при необходимости.


Примеры использования WeakHashMap

Создание и добавление элементов
import java.util.WeakHashMap;
import java.util.Map;

public class WeakHashMapExample {
public static void main(String[] args) {
WeakHashMap<String, String> weakMap = new WeakHashMap<>();

String key1 = new String("key1");
String key2 = new String("key2");

weakMap.put(key1, "value1");
weakMap.put(key2, "value2");

System.out.println("Before GC: " + weakMap);

key1 = null;
System.gc();

// Подождем немного, чтобы GC мог удалить key1
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("After GC: " + weakMap);
}
}


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

Метод put

Добавляет пару ключ-значение в карту.
WeakHashMap<String, Integer> map = new WeakHashMap<>();
map.put("Apple", 50);
map.put("Banana", 30);


Метод get

Возвращает значение, связанное с указанным ключом.
Integer value = map.get("Apple");
System.out.println("Value for key 'Apple': " + value);


Метод remove

Удаляет запись по ключу и возвращает удаленное значение.
Integer removedValue = map.remove("Banana");
System.out.println("Removed value: " + removedValue);


Метод containsKey


Проверяет, содержится ли ключ в карте.
boolean contains = map.containsKey("Apple");
System.out.println("Contains key 'Apple': " + contains);


Метод containsValue

Проверяет, содержится ли значение в карте.
boolean containsValue = map.containsValue(50);
System.out.println("Contains value 50: " + containsValue);


Метод size

Возвращает количество элементов в карте.
int size = map.size();
System.out.println("Size of the map: " + size);


Метод isEmpty

Проверяет, пуста ли карта.
boolean isEmpty = map.isEmpty();
System.out.println("Is the map empty: " + isEmpty);


Метод clear

Очищает карту, удаляя все элементы.
map.clear();
System.out.println("Size after clear: " + map.size());



Особенности использования WeakHashMap

Кеширование

WeakHashMap идеально подходит для кеширования данных, которые можно восстанавливать, если они удалены сборщиком мусора. Например, кеширование изображений в приложении, где изображения могут быть загружены повторно, если они были удалены.

Автоматическое удаление
В ситуациях, когда необходимо автоматически удалять элементы карты при отсутствии ссылок на ключи, WeakHashMap будет полезен. Например, для ассоциации метаданных с объектами без предотвращения их сборки мусора.


Полезные ссылки для более полного ознакомления с WeakHashMap (спасибо авторам за их кропотливую работу):
https://www.baeldung.com/java-weakhashmap
https://javarush.com/quests/lectures/questservlets.level18.lecture08

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

import java.util.*;

public class AlgorithmChallenge {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(5, 2, 8, 7, 1);
Collections.sort(numbers, (a, b) -> b - a);

int sum = 0;
for (int i = 0; i < numbers.size(); i++) {
if (i % 2 == 0) {
sum += numbers.get(i) * 2;
} else {
sum -= numbers.get(i) * 3;
}
}
System.out.println("Result: " + sum);
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
0%
3
14%
5
29%
14
57%
1