❗️❗️❗️2️⃣0️⃣0️⃣ подписчиков!!! ❗️❗️❗️
Ребят, я не знаю, как и зачем Вы к нам пришли, но по всей видимости Вы что-то ищете и ждете от нашего канала.
Я всеми силами буду стараться это Вам дать, и продолжать обучать и самообучаться Java дальше!🫡
Независимо от всего этого я искренне благодарен всем, кто находится здесь, приходит на встречи, интересуется и пишет комментарии, участвует в обсуждениях в чате!
Спасибо ребят!🤝
Давайте и дальше становиться лучшим пабликом для изучающих Java!💪
Дальше будет интереснее....😏
Ребят, я не знаю, как и зачем Вы к нам пришли, но по всей видимости Вы что-то ищете и ждете от нашего канала.
Я всеми силами буду стараться это Вам дать, и продолжать обучать и самообучаться Java дальше!🫡
Независимо от всего этого я искренне благодарен всем, кто находится здесь, приходит на встречи, интересуется и пишет комментарии, участвует в обсуждениях в чате!
Спасибо ребят!🤝
Давайте и дальше становиться лучшим пабликом для изучающих Java!💪
Дальше будет интереснее....😏
Что выведет код?
#Tasks
import java.util.BitSet;
public class Main {
public static void main(String[] args) {
BitSet bitset = new BitSet(10);
bitset.set(0);
bitset.set(3);
bitset.set(5);
bitset.set(7);
bitset.flip(0, 6);
bitset.clear(7);
for (int i = 0; i < 10; i++) {
System.out.print(bitset.get(i) ? "1" : "0");
}
}
}
#Tasks
Основные методы BitSet и их использование
set(int bitIndex) и set(int fromIndex, int toIndex):
Эти методы используются для установки бита или диапазона битов в значение true.
clear(int bitIndex) и clear(int fromIndex, int toIndex):
Эти методы сбрасывают бит или диапазон битов, устанавливая их в false.
get(int bitIndex) и get(int fromIndex, int toIndex):
Эти методы возвращают значение конкретного бита или диапазона битов.
flip(int bitIndex) и flip(int fromIndex, int toIndex):
Переключает (инвертирует) бит или диапазон битов.
length() и size():
length() возвращает индекс самого старшего бита плюс один, т.е. логическую длину BitSet.
size() возвращает текущий размер внутреннего массива, который является кратным 64.
cardinality():
Возвращает количество установленных в true битов (так называемая "мощность" множества).
and(BitSet set), or(BitSet set), xor(BitSet set):
Методы выполняют побитовые операции AND, OR, XOR над текущим BitSet и заданным BitSet.
intersects(BitSet set):
Проверяет, есть ли общие установленные биты между двумя BitSet.
isEmpty():
Проверяет, есть ли хотя бы один установленный бит в BitSet.
stream():
Позволяет создать поток из установленных битов BitSet. Этот метод особенно полезен для работы с Stream API.
Примеры использования
Оптимизация использования памяти:
Если вам нужно хранить большой набор булевых значений, BitSet помогает оптимизировать использование памяти, так как каждый бит занимает всего 1 бит.
#Java #Training #Medium #BitSet
set(int bitIndex) и set(int fromIndex, int toIndex):
Эти методы используются для установки бита или диапазона битов в значение true.
BitSet bitSet = new BitSet();
bitSet.set(2); // Устанавливает бит с индексом 2 в true
bitSet.set(4, 7); // Устанавливает биты с индексами 4, 5 и 6 в true
Если указать диапазон, все биты в этом диапазоне будут установлены в true.
clear(int bitIndex) и clear(int fromIndex, int toIndex):
Эти методы сбрасывают бит или диапазон битов, устанавливая их в false.
bitSet.clear(2); // Сбрасывает бит с индексом 2 в false
bitSet.clear(4, 7); // Сбрасывает биты с индексами 4, 5 и 6 в false
Полезно для обнуления значений или удаления флагов.
get(int bitIndex) и get(int fromIndex, int toIndex):
Эти методы возвращают значение конкретного бита или диапазона битов.
boolean value = bitSet.get(2); // Получает значение бита с индексом 2
BitSet subSet = bitSet.get(4, 7); // Получает поднабор битов с 4 до 6
Возвращаемое значение может быть true или false, а в случае диапазона — новый BitSet.
flip(int bitIndex) и flip(int fromIndex, int toIndex):
Переключает (инвертирует) бит или диапазон битов.
bitSet.flip(2); // Инвертирует бит с индексом 2
bitSet.flip(4, 7); // Инвертирует биты с 4 до 6
Если бит был true, он станет false, и наоборот.
length() и size():
length() возвращает индекс самого старшего бита плюс один, т.е. логическую длину BitSet.
size() возвращает текущий размер внутреннего массива, который является кратным 64.
System.out.println("Length: " + bitSet.length()); // Логическая длина BitSet
System.out.println("Size: " + bitSet.size()); // Текущий размер внутреннего массива
Эти методы полезны для анализа содержимого BitSet и его текущего состояния.
cardinality():
Возвращает количество установленных в true битов (так называемая "мощность" множества).
int numberOfBits = bitSet.cardinality(); // Количество установленных битов
Полезно, когда нужно узнать, сколько значений true содержится в наборе.
and(BitSet set), or(BitSet set), xor(BitSet set):
Методы выполняют побитовые операции AND, OR, XOR над текущим BitSet и заданным BitSet.
BitSet bitSet1 = new BitSet();
bitSet1.set(1);
bitSet1.set(3);
BitSet bitSet2 = new BitSet();
bitSet2.set(2);
bitSet2.set(3);
bitSet1.and(bitSet2); // AND операция между bitSet1 и bitSet2
bitSet1.or(bitSet2); // OR операция между bitSet1 и bitSet2
bitSet1.xor(bitSet2); // XOR операция между bitSet1 и bitSet2
Эти методы полезны для выполнения сложных битовых операций между двумя наборами.
intersects(BitSet set):
Проверяет, есть ли общие установленные биты между двумя BitSet.
boolean hasIntersection = bitSet1.intersects(bitSet2); // true, если есть общие биты
Метод возвращает true, если есть хотя бы один бит, который установлен в true в обоих наборах.
isEmpty():
Проверяет, есть ли хотя бы один установленный бит в BitSet.
boolean isEmpty = bitSet.isEmpty(); // true, если все биты сброшены
Полезно для проверки пустоты множества.
stream():
Позволяет создать поток из установленных битов BitSet. Этот метод особенно полезен для работы с Stream API.
bitSet.stream().forEach(System.out::println); // Выводит индексы установленных битов
Это удобный способ итерирования по установленным битам с использованием функциональных возможностей Java.
Примеры использования
Оптимизация использования памяти:
Если вам нужно хранить большой набор булевых значений, BitSet помогает оптимизировать использование памяти, так как каждый бит занимает всего 1 бит.
BitSet largeSet = new BitSet();
for (int i = 0; i < 1000000; i++) {
if (i % 2 == 0) {
largeSet.set(i);
}
}
System.out.println("Количество установленных битов: " + largeSet.cardinality());
В этом примере BitSet используется для хранения большого количества булевых значений, что значительно экономит память по сравнению с использованием массивов boolean[].
#Java #Training #Medium #BitSet
NavigableSet, особенности и внутреннее устройство
NavigableSet — это один из интерфейсов в Java Collection Framework, который расширяет интерфейс SortedSet. Он предоставляет дополнительные методы для навигации по элементам в наборе на основе их естественного порядка или на основе компаратора, заданного при создании набора. NavigableSet — это специализированная коллекция, которая особенно полезна, когда вам нужно работать с отсортированными наборами данных, и когда важны операции, связанные с поиском ближайших элементов или диапазонов значений.
Особенности NavigableSet
Упорядоченность элементов:
NavigableSet, как и его родительский интерфейс SortedSet, гарантирует, что элементы хранятся в упорядоченном виде. Упорядоченность может быть основана на естественном порядке элементов (если элементы реализуют интерфейс Comparable) или на пользовательском компараторе, переданном в конструктор.
Поддержка поиска ближайших элементов:
NavigableSet предоставляет методы для поиска элементов, которые являются ближайшими к заданному значению. Например, методы ceiling(E e), floor(E e), higher(E e), и lower(E e) позволяют найти наименьший элемент, который больше или равен заданному, наибольший элемент, который меньше или равен заданному, и так далее.
Поддержка поднаборов:
NavigableSet поддерживает создание поднаборов с помощью методов subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive), headSet(E toElement, boolean inclusive), и tailSet(E fromElement, boolean inclusive). Эти методы возвращают новые представления набора, которые включают или исключают определенные диапазоны значений.
Реверсированная версия:
Метод descendingSet() возвращает представление набора в обратном порядке. Это особенно полезно, когда необходимо выполнить операции с набором в порядке, обратном естественному.
Безопасность и неизменяемость:
NavigableSet предоставляет неизменяемые представления поднаборов, что обеспечивает безопасность при многопоточном доступе.
Внутреннее устройство NavigableSet
Хотя интерфейс NavigableSet не определяет, как именно должны быть реализованы коллекции, обычно используется одна из следующих реализаций:
TreeSet:
Самая распространенная реализация NavigableSet в Java — это класс TreeSet. TreeSet основан на структуре данных красно-черного дерева, которая обеспечивает логарифмическое время выполнения основных операций (вставка, удаление, поиск). Поскольку TreeSet является упорядоченной структурой данных, элементы в нем всегда хранятся в отсортированном порядке.
ConcurrentSkipListSet:
Еще одна реализация NavigableSet — это ConcurrentSkipListSet. Этот класс основан на структуре данных, называемой "skip list" (список с пропусками). В отличие от TreeSet, который не является потокобезопасным, ConcurrentSkipListSet предоставляет безопасный для многопоточного использования набор с логарифмическим временем доступа. Это делает его идеальным выбором для использования в средах, где требуется потокобезопасность без блокировок.
NavigableSet будет полезен в следующих сценариях:
Диапазонные запросы:
Если вам нужно работать с подмножествами данных на основе диапазонов, то NavigableSet идеально подходит, так как он позволяет легко извлекать элементы в заданном диапазоне.
Поиск ближайших значений:
Если задача требует частого поиска ближайших значений (например, в географических приложениях для поиска ближайших координат), то NavigableSet предоставляет необходимые методы для таких операций.
Обратный порядок:
Когда нужно получить элементы в порядке, обратном их естественному порядку, метод descendingSet() упрощает эту задачу.
#Java #Training #Medium #NavigableSet
NavigableSet — это один из интерфейсов в Java Collection Framework, который расширяет интерфейс SortedSet. Он предоставляет дополнительные методы для навигации по элементам в наборе на основе их естественного порядка или на основе компаратора, заданного при создании набора. NavigableSet — это специализированная коллекция, которая особенно полезна, когда вам нужно работать с отсортированными наборами данных, и когда важны операции, связанные с поиском ближайших элементов или диапазонов значений.
Особенности NavigableSet
Упорядоченность элементов:
NavigableSet, как и его родительский интерфейс SortedSet, гарантирует, что элементы хранятся в упорядоченном виде. Упорядоченность может быть основана на естественном порядке элементов (если элементы реализуют интерфейс Comparable) или на пользовательском компараторе, переданном в конструктор.
Поддержка поиска ближайших элементов:
NavigableSet предоставляет методы для поиска элементов, которые являются ближайшими к заданному значению. Например, методы ceiling(E e), floor(E e), higher(E e), и lower(E e) позволяют найти наименьший элемент, который больше или равен заданному, наибольший элемент, который меньше или равен заданному, и так далее.
Поддержка поднаборов:
NavigableSet поддерживает создание поднаборов с помощью методов subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive), headSet(E toElement, boolean inclusive), и tailSet(E fromElement, boolean inclusive). Эти методы возвращают новые представления набора, которые включают или исключают определенные диапазоны значений.
Реверсированная версия:
Метод descendingSet() возвращает представление набора в обратном порядке. Это особенно полезно, когда необходимо выполнить операции с набором в порядке, обратном естественному.
Безопасность и неизменяемость:
NavigableSet предоставляет неизменяемые представления поднаборов, что обеспечивает безопасность при многопоточном доступе.
Внутреннее устройство NavigableSet
Хотя интерфейс NavigableSet не определяет, как именно должны быть реализованы коллекции, обычно используется одна из следующих реализаций:
TreeSet:
Самая распространенная реализация NavigableSet в Java — это класс TreeSet. TreeSet основан на структуре данных красно-черного дерева, которая обеспечивает логарифмическое время выполнения основных операций (вставка, удаление, поиск). Поскольку TreeSet является упорядоченной структурой данных, элементы в нем всегда хранятся в отсортированном порядке.
NavigableSet<Integer> navigableSet = new TreeSet<>();
navigableSet.add(5);
navigableSet.add(2);
navigableSet.add(9);
System.out.println(navigableSet); // [2, 5, 9]
ConcurrentSkipListSet:
Еще одна реализация NavigableSet — это ConcurrentSkipListSet. Этот класс основан на структуре данных, называемой "skip list" (список с пропусками). В отличие от TreeSet, который не является потокобезопасным, ConcurrentSkipListSet предоставляет безопасный для многопоточного использования набор с логарифмическим временем доступа. Это делает его идеальным выбором для использования в средах, где требуется потокобезопасность без блокировок.
NavigableSet<String> navigableSet = new ConcurrentSkipListSet<>();
navigableSet.add("banana");
navigableSet.add("apple");
navigableSet.add("cherry");
System.out.println(navigableSet); // [apple, banana, cherry]
NavigableSet будет полезен в следующих сценариях:
Диапазонные запросы:
Если вам нужно работать с подмножествами данных на основе диапазонов, то NavigableSet идеально подходит, так как он позволяет легко извлекать элементы в заданном диапазоне.
Поиск ближайших значений:
Если задача требует частого поиска ближайших значений (например, в географических приложениях для поиска ближайших координат), то NavigableSet предоставляет необходимые методы для таких операций.
Обратный порядок:
Когда нужно получить элементы в порядке, обратном их естественному порядку, метод descendingSet() упрощает эту задачу.
#Java #Training #Medium #NavigableSet
Варианты ответа:
Anonymous Quiz
0%
20, 30, 20, 50
33%
20, 30, 30, null
33%
20, 30, 25, null
33%
30, 30, 30, 50
Что выведет код?
#Tasks
import java.util.*;
public class Main {
public static void main(String[] args) {
NavigableSet<Integer> set = new TreeSet<>(Arrays.asList(10, 20, 30, 40, 50));
System.out.println(set.lower(30));
System.out.println(set.floor(30));
System.out.println(set.ceiling(25));
System.out.println(set.higher(50));
}
}
#Tasks
Основные методы NavigableSet и примеры использования
Основные методы NavigableSet
E lower(E e)
Возвращает наибольший элемент в наборе, который меньше заданного элемента e. Если такого элемента нет, возвращает null.
E floor(E e)
Возвращает наибольший элемент в наборе, который меньше или равен заданному элементу e. Если такого элемента нет, возвращает null.
E ceiling(E e)
Возвращает наименьший элемент в наборе, который больше или равен заданному элементу e. Если такого элемента нет, возвращает null.
E higher(E e)
Возвращает наименьший элемент в наборе, который больше заданного элемента e. Если такого элемента нет, возвращает null.
E pollFirst() и E pollLast()
Эти методы удаляют и возвращают первый и последний элемент набора соответственно. Если набор пуст, они возвращают null.
NavigableSet<E> descendingSet()
Возвращает представление текущего набора в обратном порядке. Любые изменения в этом представлении будут отражаться на исходном наборе и наоборот.
NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)
Возвращает поднабор элементов от fromElement до toElement, при этом можно указать, включать ли эти элементы в поднабор.
NavigableSet<E> headSet(E toElement, boolean inclusive)
Возвращает поднабор элементов от начала набора до toElement. Можно указать, включать ли элемент toElement в поднабор.
NavigableSet<E> tailSet(E fromElement, boolean inclusive)
Возвращает поднабор элементов от fromElement до конца набора. Можно указать, включать ли элемент fromElement в поднабор.
Примеры использования NavigableSet
Пример 1: Фильтрация диапазона значений
Предположим, у нас есть набор температур за неделю, и мы хотим получить все температуры в диапазоне от 15 до 25 градусов:
Пример 2: Поиск ближайшей даты
Допустим, у нас есть набор дат, и мы хотим найти ближайшую дату, которая будет после сегодняшнего дня:
#Java #Training #Medium #NavigableSet
Основные методы NavigableSet
E lower(E e)
Возвращает наибольший элемент в наборе, который меньше заданного элемента e. Если такого элемента нет, возвращает null.
NavigableSet<Integer> set = new TreeSet<>(Arrays.asList(1, 2, 3, 4, 5));
System.out.println(set.lower(3)); // Output: 2
E floor(E e)
Возвращает наибольший элемент в наборе, который меньше или равен заданному элементу e. Если такого элемента нет, возвращает null.
System.out.println(set.floor(3)); // Output: 3
System.out.println(set.floor(6)); // Output: 5
E ceiling(E e)
Возвращает наименьший элемент в наборе, который больше или равен заданному элементу e. Если такого элемента нет, возвращает null.
System.out.println(set.ceiling(3)); // Output: 3
System.out.println(set.ceiling(0)); // Output: 1
E higher(E e)
Возвращает наименьший элемент в наборе, который больше заданного элемента e. Если такого элемента нет, возвращает null.
System.out.println(set.higher(3)); // Output: 4
System.out.println(set.higher(5)); // Output: null
E pollFirst() и E pollLast()
Эти методы удаляют и возвращают первый и последний элемент набора соответственно. Если набор пуст, они возвращают null.
NavigableSet<String> set = new TreeSet<>(Arrays.asList("apple", "banana", "cherry"));
System.out.println(set.pollFirst()); // Output: apple
System.out.println(set.pollLast()); // Output: cherry
System.out.println(set); // Output: [banana]
NavigableSet<E> descendingSet()
Возвращает представление текущего набора в обратном порядке. Любые изменения в этом представлении будут отражаться на исходном наборе и наоборот.
NavigableSet<String> set = new TreeSet<>(Arrays.asList("apple", "banana", "cherry"));
NavigableSet<String> descendingSet = set.descendingSet();
System.out.println(descendingSet); // Output: [cherry, banana, apple]
NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)
Возвращает поднабор элементов от fromElement до toElement, при этом можно указать, включать ли эти элементы в поднабор.
NavigableSet<Integer> set = new TreeSet<>(Arrays.asList(1, 2, 3, 4, 5));
NavigableSet<Integer> subSet = set.subSet(2, true, 4, false);
System.out.println(subSet); // Output: [2, 3]
NavigableSet<E> headSet(E toElement, boolean inclusive)
Возвращает поднабор элементов от начала набора до toElement. Можно указать, включать ли элемент toElement в поднабор.
NavigableSet<Integer> headSet = set.headSet(4, true);
System.out.println(headSet); // Output: [1, 2, 3, 4]
NavigableSet<E> tailSet(E fromElement, boolean inclusive)
Возвращает поднабор элементов от fromElement до конца набора. Можно указать, включать ли элемент fromElement в поднабор.
NavigableSet<Integer> tailSet = set.tailSet(3, false);
System.out.println(tailSet); // Output: [4, 5]
Примеры использования NavigableSet
Пример 1: Фильтрация диапазона значений
Предположим, у нас есть набор температур за неделю, и мы хотим получить все температуры в диапазоне от 15 до 25 градусов:
NavigableSet<Integer> temperatures = new TreeSet<>(Arrays.asList(10, 15, 20, 25, 30));
NavigableSet<Integer> comfortableTemperatures = temperatures.subSet(15, true, 25, true);
System.out.println(comfortableTemperatures); // Output: [15, 20, 25]
Пример 2: Поиск ближайшей даты
Допустим, у нас есть набор дат, и мы хотим найти ближайшую дату, которая будет после сегодняшнего дня:
NavigableSet<LocalDate> dates = new TreeSet<>(Arrays.asList(
LocalDate.of(2023, 8, 20),
LocalDate.of(2023, 9, 5),
LocalDate.of(2023, 10, 10)
));
LocalDate today = LocalDate.of(2023, 8, 25);
LocalDate nextDate = dates.ceiling(today);
System.out.println(nextDate); // Output: 2023-09-05
#Java #Training #Medium #NavigableSet
Неизменяемые коллекции, их внутреннее устройство и особенности
Неизменяемые коллекции в Java представляют собой структуры данных, которые нельзя модифицировать после их создания. Это означает, что после того как вы создали такую коллекцию, вы не сможете добавить, удалить или изменить элементы внутри нее. Неизменяемые коллекции становятся все более популярными благодаря их безопасности, простоте использования и эффективности в определенных контекстах, таких как многопоточность.
Неизменяемые коллекции предлагают ряд преимуществ, которые делают их полезными в различных сценариях:
Безопасность и предсказуемость:
Поскольку неизменяемые коллекции нельзя изменить после создания, это делает их идеальными для использования в многопоточных средах. Отсутствие изменений гарантирует, что коллекция останется в консистентном состоянии во время выполнения программы.
Простота и минимизация ошибок:
Использование неизменяемых коллекций снижает вероятность ошибок, связанных с непреднамеренными изменениями данных. Это делает код более предсказуемым и легким для понимания.
Производительность:
Неизменяемые коллекции могут быть более эффективными с точки зрения производительности, так как отпадает необходимость в синхронизации или копировании данных при передаче коллекции между потоками.
Кэширование и мемоизация:
Из-за их неизменности, неизменяемые объекты могут быть безопасно закэшированы и повторно использованы, что снижает нагрузку на систему и уменьшает потребность в выделении новой памяти.
Виды неизменяемых коллекций
В Java неизменяемые коллекции можно создать несколькими способами. Наиболее известные из них включают использование утилитарных методов, представленных в JDK 9 и более поздних версиях, а также использование классов-оболочек.
Начиная с Java 9, были добавлены статические фабричные методы для создания неизменяемых коллекций, такие как List.of(), Set.of() и Map.of().
Collections.unmodifiableXXX():
До Java 9 неизменяемые коллекции можно было создавать с помощью методов из класса Collections. Эти методы возвращают "обернутые" коллекции, которые блокируют модификации.
Guava Immutable Collections:
Библиотека Google Guava предоставляет собственные реализации неизменяемых коллекций, такие как ImmutableList, ImmutableSet, и ImmutableMap.
#Java #Training #Medium #ImmutableCollections
Неизменяемые коллекции в Java представляют собой структуры данных, которые нельзя модифицировать после их создания. Это означает, что после того как вы создали такую коллекцию, вы не сможете добавить, удалить или изменить элементы внутри нее. Неизменяемые коллекции становятся все более популярными благодаря их безопасности, простоте использования и эффективности в определенных контекстах, таких как многопоточность.
Неизменяемые коллекции предлагают ряд преимуществ, которые делают их полезными в различных сценариях:
Безопасность и предсказуемость:
Поскольку неизменяемые коллекции нельзя изменить после создания, это делает их идеальными для использования в многопоточных средах. Отсутствие изменений гарантирует, что коллекция останется в консистентном состоянии во время выполнения программы.
Простота и минимизация ошибок:
Использование неизменяемых коллекций снижает вероятность ошибок, связанных с непреднамеренными изменениями данных. Это делает код более предсказуемым и легким для понимания.
Производительность:
Неизменяемые коллекции могут быть более эффективными с точки зрения производительности, так как отпадает необходимость в синхронизации или копировании данных при передаче коллекции между потоками.
Кэширование и мемоизация:
Из-за их неизменности, неизменяемые объекты могут быть безопасно закэшированы и повторно использованы, что снижает нагрузку на систему и уменьшает потребность в выделении новой памяти.
Виды неизменяемых коллекций
В Java неизменяемые коллекции можно создать несколькими способами. Наиболее известные из них включают использование утилитарных методов, представленных в JDK 9 и более поздних версиях, а также использование классов-оболочек.
Начиная с Java 9, были добавлены статические фабричные методы для создания неизменяемых коллекций, такие как List.of(), Set.of() и Map.of().
List<String> immutableList = List.of("apple", "banana", "cherry");
Set<Integer> immutableSet = Set.of(1, 2, 3);
Map<Integer, String> immutableMap = Map.of(1, "one", 2, "two", 3, "three");
Эти коллекции обеспечивают высокую производительность и компактность, так как они реализованы с использованием специализированных внутренних структур данных.
Collections.unmodifiableXXX():
До Java 9 неизменяемые коллекции можно было создавать с помощью методов из класса Collections. Эти методы возвращают "обернутые" коллекции, которые блокируют модификации.
List<String> mutableList = new ArrayList<>(Arrays.asList("apple", "banana", "cherry"));
List<String> immutableList = Collections.unmodifiableList(mutableList);
Однако важно помнить, что хотя сам объект коллекции становится неизменяемым, если исходная коллекция, переданная в метод, изменится, это отразится и на неизменяемой коллекции.
Guava Immutable Collections:
Библиотека Google Guava предоставляет собственные реализации неизменяемых коллекций, такие как ImmutableList, ImmutableSet, и ImmutableMap.
List<String> guavaImmutableList = ImmutableList.of("apple", "banana", "cherry");
Set<Integer> guavaImmutableSet = ImmutableSet.of(1, 2, 3);
Коллекции Guava полностью независимы от оригинальной коллекции и не изменяются, даже если исходная коллекция изменяется.
#Java #Training #Medium #ImmutableCollections
Внутреннее устройство неизменяемых коллекций
Неизменяемые коллекции реализуются по-разному в зависимости от их конкретной реализации, но основные принципы остаются схожими:
Отсутствие изменяемых ссылок:
Неизменяемые коллекции не предоставляют методов для изменения своего содержимого (таких как add(), remove(), и т. д.). Даже если такие методы существуют (например, в случае с Collections.unmodifiableList()), они выбрасывают исключения UnsupportedOperationException.
Минимизация памяти:
В реализации неизменяемых коллекций часто применяются специализированные структуры данных, которые минимизируют потребление памяти. Например, для хранения маленьких списков List.of() использует компактные структуры.
Предсказуемое поведение:
Поскольку неизменяемые коллекции не могут быть изменены, они обеспечивают предсказуемое поведение и стабильность. Это делает их идеальными кандидатами для кэширования и использования в хэш-структурах.
Копирование данных:
Некоторые неизменяемые коллекции создают свои копии данных, чтобы гарантировать, что оригинальные данные не изменятся (например, коллекции Guava). Это может увеличить время создания коллекции, но делает ее безопасной для использования.
Особенности неизменяемых коллекций
Поддержка null:
Важно помнить, что коллекции, созданные с помощью List.of(), Set.of(), или Map.of() в Java 9 и выше, не поддерживают null в качестве элемента. Попытка добавить null приведет к выбросу NullPointerException.
Порядок элементов:
В случае Set.of() элементы не сохраняют порядок, но List.of() и Map.of() сохраняют порядок добавления элементов.
Производительность:
Неизменяемые коллекции могут быть быстрее, чем изменяемые, благодаря отсутствию необходимости обрабатывать изменения данных. Однако стоит учитывать время, необходимое для их создания, особенно если коллекция очень большая.
Совместимость:
Неизменяемые коллекции полностью совместимы с остальными частями Java Collection Framework. Они могут быть использованы в любом месте, где требуется коллекция, но вы должны помнить, что они не поддерживают операции изменения.
#Java #Training #Medium #ImmutableCollections
Неизменяемые коллекции реализуются по-разному в зависимости от их конкретной реализации, но основные принципы остаются схожими:
Отсутствие изменяемых ссылок:
Неизменяемые коллекции не предоставляют методов для изменения своего содержимого (таких как add(), remove(), и т. д.). Даже если такие методы существуют (например, в случае с Collections.unmodifiableList()), они выбрасывают исключения UnsupportedOperationException.
Минимизация памяти:
В реализации неизменяемых коллекций часто применяются специализированные структуры данных, которые минимизируют потребление памяти. Например, для хранения маленьких списков List.of() использует компактные структуры.
Предсказуемое поведение:
Поскольку неизменяемые коллекции не могут быть изменены, они обеспечивают предсказуемое поведение и стабильность. Это делает их идеальными кандидатами для кэширования и использования в хэш-структурах.
Копирование данных:
Некоторые неизменяемые коллекции создают свои копии данных, чтобы гарантировать, что оригинальные данные не изменятся (например, коллекции Guava). Это может увеличить время создания коллекции, но делает ее безопасной для использования.
Особенности неизменяемых коллекций
Поддержка null:
Важно помнить, что коллекции, созданные с помощью List.of(), Set.of(), или Map.of() в Java 9 и выше, не поддерживают null в качестве элемента. Попытка добавить null приведет к выбросу NullPointerException.
List<String> listWithNull = List.of("apple", null, "cherry"); // Throws NullPointerException
Порядок элементов:
В случае Set.of() элементы не сохраняют порядок, но List.of() и Map.of() сохраняют порядок добавления элементов.
Производительность:
Неизменяемые коллекции могут быть быстрее, чем изменяемые, благодаря отсутствию необходимости обрабатывать изменения данных. Однако стоит учитывать время, необходимое для их создания, особенно если коллекция очень большая.
Совместимость:
Неизменяемые коллекции полностью совместимы с остальными частями Java Collection Framework. Они могут быть использованы в любом месте, где требуется коллекция, но вы должны помнить, что они не поддерживают операции изменения.
#Java #Training #Medium #ImmutableCollections
Что выведет код?
#Tasks
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> list = List.of("apple", "banana", "cherry");
list.add("date");
System.out.println(list);
}
}
#Tasks
Варианты ответа:
Anonymous Quiz
44%
[apple, banana, cherry, date]
31%
[apple, banana, cherry]
19%
UnsupportedOperationException
6%
Ошибка времени компиляции
Примеры использования неизменяемых коллекций в реальных задачах
Пример 1: Использование в многопоточных приложениях
Одним из ключевых преимуществ неизменяемых коллекций является их безопасность в многопоточных средах. Поскольку такие коллекции нельзя изменить после создания, несколько потоков могут безопасно обращаться к одной и той же коллекции без риска возникновения проблем с синхронизацией.
Задача: Представим ситуацию, в которой несколько потоков читают список конфигураций приложения. Эти конфигурации не должны изменяться во время выполнения программы.
Пример 2: Защита от несанкционированных изменений
Иногда необходимо защитить коллекцию от изменений, чтобы избежать непреднамеренных или злонамеренных изменений данных.
Задача: Допустим, у нас есть список сотрудников компании, и мы хотим предоставить доступ к этому списку в разных частях программы, но при этом гарантировать, что список не будет изменен.
#Java #Training #Medium #ImmutableCollections
Пример 1: Использование в многопоточных приложениях
Одним из ключевых преимуществ неизменяемых коллекций является их безопасность в многопоточных средах. Поскольку такие коллекции нельзя изменить после создания, несколько потоков могут безопасно обращаться к одной и той же коллекции без риска возникновения проблем с синхронизацией.
Задача: Представим ситуацию, в которой несколько потоков читают список конфигураций приложения. Эти конфигурации не должны изменяться во время выполнения программы.
import java.util.List;
public class ConfigurationManager {
private final List<String> configurations;
public ConfigurationManager(List<String> configurations) {
this.configurations = List.copyOf(configurations);
}
public List<String> getConfigurations() {
return configurations;
}
}
// Пример использования
List<String> initialConfigs = Arrays.asList("config1", "config2", "config3");
ConfigurationManager manager = new ConfigurationManager(initialConfigs);
List<String> configs = manager.getConfigurations();
configs.forEach(System.out::println);
В этом примере, использование List.copyOf() в конструкторе ConfigurationManager гарантирует, что коллекция configurations будет неизменяемой, и любые попытки изменить ее извне будут заблокированы.
Пример 2: Защита от несанкционированных изменений
Иногда необходимо защитить коллекцию от изменений, чтобы избежать непреднамеренных или злонамеренных изменений данных.
Задача: Допустим, у нас есть список сотрудников компании, и мы хотим предоставить доступ к этому списку в разных частях программы, но при этом гарантировать, что список не будет изменен.
import java.util.Collections;
import java.util.List;
public class Company {
private final List<String> employees;
public Company(List<String> employees) {
this.employees = Collections.unmodifiableList(employees);
}
public List<String> getEmployees() {
return employees;
}
}
// Пример использования
List<String> employeeList = Arrays.asList("Alice", "Bob", "Charlie");
Company company = new Company(employeeList);
List<String> employees = company.getEmployees();
employees.forEach(System.out::println);
// Попытка изменения списка приведет к исключению UnsupportedOperationException
employees.add("David"); // This line will throw an exception
Здесь мы используем Collections.unmodifiableList(), чтобы создать неизменяемый список сотрудников. Это предотвращает любые попытки изменить список и гарантирует его неизменность в течение всего жизненного цикла программы.
#Java #Training #Medium #ImmutableCollections
Пример 3: Использование неизменяемых коллекций в качестве ключей в Map
Еще одна распространенная задача — использование сложных объектов, таких как списки или множества, в качестве ключей в Map. Для этого неизменяемые коллекции подходят идеально, так как они гарантируют, что значения ключей не изменятся после добавления их в Map.
Задача: Допустим, у нас есть Map, где ключами являются списки, представляющие комбинации параметров, а значениями — результаты расчетов. Мы хотим, чтобы ключи были неизменяемыми, чтобы избежать проблем с изменением комбинаций после добавления в Map.
Пример 4: Кэширование результатов
Неизменяемые коллекции идеально подходят для кэширования, так как их неизменность гарантирует, что закэшированные данные останутся консистентными на протяжении всего времени использования кэша.
Задача: Представим, что у нас есть метод, который выполняет сложные вычисления, и мы хотим кэшировать результаты этих вычислений для последующего использования.
#Java #Training #Medium #ImmutableCollections
Еще одна распространенная задача — использование сложных объектов, таких как списки или множества, в качестве ключей в Map. Для этого неизменяемые коллекции подходят идеально, так как они гарантируют, что значения ключей не изменятся после добавления их в Map.
Задача: Допустим, у нас есть Map, где ключами являются списки, представляющие комбинации параметров, а значениями — результаты расчетов. Мы хотим, чтобы ключи были неизменяемыми, чтобы избежать проблем с изменением комбинаций после добавления в Map.
import java.util.List;
import java.util.Map;
import java.util.HashMap;
public class CalculationManager {
private final Map<List<Integer>, Integer> calculationResults = new HashMap<>();
public void addCalculationResult(List<Integer> params, int result) {
List<Integer> immutableParams = List.copyOf(params);
calculationResults.put(immutableParams, result);
}
public Integer getResult(List<Integer> params) {
return calculationResults.get(params);
}
}
// Пример использования
CalculationManager manager = new CalculationManager();
List<Integer> params = Arrays.asList(1, 2, 3);
manager.addCalculationResult(params, 10);
params.set(0, 5); // Изменение оригинального списка не повлияет на ключ в Map
System.out.println(manager.getResult(Arrays.asList(1, 2, 3))); // Output: 10
В этом примере мы используем List.copyOf() для создания неизменяемой версии списка параметров перед добавлением его в Map. Это гарантирует, что изменения оригинального списка params не повлияют на ключ в Map, сохраняя целостность данных.
Пример 4: Кэширование результатов
Неизменяемые коллекции идеально подходят для кэширования, так как их неизменность гарантирует, что закэшированные данные останутся консистентными на протяжении всего времени использования кэша.
Задача: Представим, что у нас есть метод, который выполняет сложные вычисления, и мы хотим кэшировать результаты этих вычислений для последующего использования.
import java.util.List;
import java.util.Map;
import java.util.HashMap;
public class CacheManager {
private final Map<List<Integer>, Integer> cache = new HashMap<>();
public Integer computeIfAbsent(List<Integer> params, Calculation calculation) {
List<Integer> immutableParams = List.copyOf(params);
return cache.computeIfAbsent(immutableParams, calculation::calculate);
}
public interface Calculation {
Integer calculate(List<Integer> params);
}
}
// Пример использования
CacheManager cacheManager = new CacheManager();
List<Integer> params = Arrays.asList(2, 3, 4);
int result = cacheManager.computeIfAbsent(params, (p) -> p.stream().reduce(1, (a, b) -> a * b));
System.out.println(result); // Output: 24
// Повторный вызов с теми же параметрами вернет кэшированный результат
result = cacheManager.computeIfAbsent(params, (p) -> p.stream().reduce(1, (a, b) -> a * b));
System.out.println(result); // Output: 24
Здесь неизменяемая коллекция используется в качестве ключа для кэширования результата вычислений. Это позволяет избежать проблем с изменением параметров, которые могут привести к некорректному поведению кэша.
#Java #Training #Medium #ImmutableCollections
Java for Beginner
goodbyedpi-0.2.3rc1.zip
Скинул не туда)))
Но думаю всем пригодится))) Если запустить батник под номером 1, ютуб должен работать без впн с хорошим качеством)))
Всем хорошего вечера)))🤣
Но думаю всем пригодится))) Если запустить батник под номером 1, ютуб должен работать без впн с хорошим качеством)))
Всем хорошего вечера)))🤣
Cинхронизированные коллекции, их внутреннее устройство и особенности
Синхронизированные коллекции — это специальные версии стандартных коллекций в Java, которые обеспечивают безопасность при доступе из нескольких потоков. В многопоточных средах важно гарантировать, что несколько потоков не смогут одновременно изменить коллекцию, что может привести к непредсказуемому поведению и ошибкам. Синхронизированные коллекции решают эту проблему, обеспечивая защиту от таких ситуаций.
Cозданиe синхронизированных коллекций
Один из наиболее распространенных методов — использование класса Collections, который предлагает методы для обертывания стандартных коллекций в их синхронизированные версии.
Использование Collections.synchronizedXXX():
Класс Collections предоставляет статические методы для создания синхронизированных коллекций:
CopyOnWriteArrayList и CopyOnWriteArraySet:
Помимо использования Collections.synchronizedXXX(), в Java также доступны коллекции, специально разработанные для использования в многопоточных средах. Например, CopyOnWriteArrayList и CopyOnWriteArraySet — это коллекции, которые создают копию набора данных при каждом изменении.
ConcurrentHashMap:
Для синхронизированных ассоциативных массивов (Map) Java предлагает ConcurrentHashMap, который представляет собой высокоэффективную и масштабируемую альтернативу синхронизированному HashMap. ConcurrentHashMap разделяет коллекцию на сегменты и блокирует их независимо, что повышает производительность в условиях высокой конкуренции.
Внутреннее устройство синхронизированных коллекций
Синхронизация доступа:
Методы синхронизированных коллекций, созданных с помощью Collections.synchronizedXXX(), обернуты в блоки synchronized, которые обеспечивают монопольный доступ к коллекции для каждого потока:
#Java #Training #Medium #SynchronizedCollections
Синхронизированные коллекции — это специальные версии стандартных коллекций в Java, которые обеспечивают безопасность при доступе из нескольких потоков. В многопоточных средах важно гарантировать, что несколько потоков не смогут одновременно изменить коллекцию, что может привести к непредсказуемому поведению и ошибкам. Синхронизированные коллекции решают эту проблему, обеспечивая защиту от таких ситуаций.
Cозданиe синхронизированных коллекций
Один из наиболее распространенных методов — использование класса Collections, который предлагает методы для обертывания стандартных коллекций в их синхронизированные версии.
Использование Collections.synchronizedXXX():
Класс Collections предоставляет статические методы для создания синхронизированных коллекций:
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
Set<Integer> synchronizedSet = Collections.synchronizedSet(new HashSet<>());
Map<Integer, String> synchronizedMap = Collections.synchronizedMap(new HashMap<>());
Эти методы оборачивают оригинальные коллекции в специальные прокси-объекты, которые обеспечивают синхронизацию доступа к ним.
CopyOnWriteArrayList и CopyOnWriteArraySet:
Помимо использования Collections.synchronizedXXX(), в Java также доступны коллекции, специально разработанные для использования в многопоточных средах. Например, CopyOnWriteArrayList и CopyOnWriteArraySet — это коллекции, которые создают копию набора данных при каждом изменении.
List<String> copyOnWriteList = new CopyOnWriteArrayList<>();
Set<String> copyOnWriteSet = new CopyOnWriteArraySet<>();
Эти коллекции оптимизированы для сценариев, где частое чтение данных значительно превосходит частоту их изменения, так как они избегают блокировок при чтении.
ConcurrentHashMap:
Для синхронизированных ассоциативных массивов (Map) Java предлагает ConcurrentHashMap, который представляет собой высокоэффективную и масштабируемую альтернативу синхронизированному HashMap. ConcurrentHashMap разделяет коллекцию на сегменты и блокирует их независимо, что повышает производительность в условиях высокой конкуренции.
Map<Integer, String> concurrentMap = new ConcurrentHashMap<>();
В отличие от Collections.synchronizedMap(), ConcurrentHashMap предоставляет более гибкие методы для работы с параллельными потоками, такие как putIfAbsent(), replace() и computeIfAbsent().
Внутреннее устройство синхронизированных коллекций
Синхронизация доступа:
Методы синхронизированных коллекций, созданных с помощью Collections.synchronizedXXX(), обернуты в блоки synchronized, которые обеспечивают монопольный доступ к коллекции для каждого потока:
public static <T> List<T> synchronizedList(List<T> list) {
return new SynchronizedList<>(list);
}
static class SynchronizedList<E> implements List<E> {
private final List<E> list;
public synchronized boolean add(E e) {
synchronized (this) {
return list.add(e);
}
}
// Другие методы с аналогичной синхронизацией
}
В данном примере каждый метод обернут в блок synchronized, что гарантирует, что только один поток сможет выполнять операцию над коллекцией в любой момент времени.
#Java #Training #Medium #SynchronizedCollections
Реализация CopyOnWriteArrayList и CopyOnWriteArraySet:
CopyOnWriteArrayList и CopyOnWriteArraySet реализованы таким образом, что при добавлении или удалении элементов создается новая копия коллекции. Это обеспечивает потокобезопасное чтение, но при этом имеет некоторую стоимость в виде дополнительной памяти и времени на копирование данных.
Реализация ConcurrentHashMap:
ConcurrentHashMap основан на концепции сегментирования, где весь набор данных разделяется на сегменты, каждый из которых может быть заблокирован независимо. Это позволяет нескольким потокам одновременно модифицировать разные сегменты карты без взаимной блокировки.
Особенности синхронизированных коллекций
Производительность:
Синхронизированные коллекции обеспечивают безопасность потоков, но иногда это происходит за счет производительности. Частая блокировка может привести к увеличению времени ожидания для потоков, что особенно заметно в условиях высокой конкуренции. В таких случаях, специализированные коллекции, такие как ConcurrentHashMap или CopyOnWriteArrayList, могут предложить лучшие решения.
Блокировки и взаимоблокировки:
При использовании синхронизированных коллекций важно избегать взаимоблокировок, которые могут возникнуть, если несколько потоков одновременно пытаются захватить блокировки в разном порядке.
Порядок доступа:
В синхронизированных коллекциях порядок доступа может быть менее предсказуемым, чем в несинхронизированных. Например, если один поток изменяет коллекцию, а другой читает, порядок элементов, возвращаемых во время итерации, может быть непредсказуемым.
Совместимость с другими частями Java Collection Framework:
Синхронизированные коллекции полностью совместимы с остальной частью Java Collection Framework, что позволяет использовать их вместе с другими коллекциями и утилитами, такими как сортировка или фильтрация.
Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://javarush.com/groups/posts/23615-kofe-breyk-278-chto-takoe-sinkhronizirovannihe-kollekcii-v-java-i-kak-oni-rabotajut-razlichija
https://for-each.dev/lessons/b/-java-synchronized-collections
#Java #Training #Medium #SynchronizedCollections
CopyOnWriteArrayList и CopyOnWriteArraySet реализованы таким образом, что при добавлении или удалении элементов создается новая копия коллекции. Это обеспечивает потокобезопасное чтение, но при этом имеет некоторую стоимость в виде дополнительной памяти и времени на копирование данных.
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
Здесь используется ReentrantLock для блокировки доступа при изменении коллекции, а чтение происходит без блокировок, что делает коллекцию чрезвычайно эффективной при большом количестве операций чтения.
Реализация ConcurrentHashMap:
ConcurrentHashMap основан на концепции сегментирования, где весь набор данных разделяется на сегменты, каждый из которых может быть заблокирован независимо. Это позволяет нескольким потокам одновременно модифицировать разные сегменты карты без взаимной блокировки.
static class Segment<K,V> extends ReentrantLock {
volatile HashEntry<K,V>[] table;
// Методы для работы с сегментами карты
}
Каждая операция, которая изменяет данные, блокирует только соответствующий сегмент, что значительно увеличивает параллелизм и производительность по сравнению с глобальной блокировкой.
Особенности синхронизированных коллекций
Производительность:
Синхронизированные коллекции обеспечивают безопасность потоков, но иногда это происходит за счет производительности. Частая блокировка может привести к увеличению времени ожидания для потоков, что особенно заметно в условиях высокой конкуренции. В таких случаях, специализированные коллекции, такие как ConcurrentHashMap или CopyOnWriteArrayList, могут предложить лучшие решения.
Блокировки и взаимоблокировки:
При использовании синхронизированных коллекций важно избегать взаимоблокировок, которые могут возникнуть, если несколько потоков одновременно пытаются захватить блокировки в разном порядке.
Порядок доступа:
В синхронизированных коллекциях порядок доступа может быть менее предсказуемым, чем в несинхронизированных. Например, если один поток изменяет коллекцию, а другой читает, порядок элементов, возвращаемых во время итерации, может быть непредсказуемым.
Совместимость с другими частями Java Collection Framework:
Синхронизированные коллекции полностью совместимы с остальной частью Java Collection Framework, что позволяет использовать их вместе с другими коллекциями и утилитами, такими как сортировка или фильтрация.
Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://javarush.com/groups/posts/23615-kofe-breyk-278-chto-takoe-sinkhronizirovannihe-kollekcii-v-java-i-kak-oni-rabotajut-razlichija
https://for-each.dev/lessons/b/-java-synchronized-collections
#Java #Training #Medium #SynchronizedCollections
JavaRush
Кофе-брейк #278. Что такое синхронизированные коллекции в Java и как они работают. Различия между коллекторами потоков GroupingBy…
Это учебное руководство объясняет, что делает синхронизированные...