Пример 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…
Это учебное руководство объясняет, что делает синхронизированные...
Что выведет код?
#Tasks
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("one", "two", "three"));
List<String> syncList = Collections.synchronizedList(list);
synchronized(syncList) {
for (String s : syncList) {
syncList.remove(s);
}
}
System.out.println(syncList);
}
}
#Tasks
Варианты ответа:
Anonymous Quiz
25%
[]
25%
[two, three]
38%
UnsupportedOperationException
13%
ConcurrentModificationException
Примеры использования синхронизированных коллекций
Пример 1: Управление доступом к общему ресурсу
Одним из типичных сценариев использования синхронизированных коллекций является управление доступом к общему ресурсу. Представим, что у нас есть сервер, который обрабатывает запросы клиентов. Нам нужно сохранить историю запросов для каждого клиента и при этом гарантировать, что история будет корректно обновляться при одновременном доступе нескольких потоков.
Мы можем использовать Collections.synchronizedMap() для создания потокобезопасной карты, где ключами будут идентификаторы клиентов, а значениями — списки с историей запросов.
Пример 2: Очередь задач в многопоточном приложении
Другой распространенный сценарий — использование синхронизированной коллекции для управления очередью задач в многопоточном приложении. Например, у нас есть система, которая должна обрабатывать задания в параллельных потоках, но при этом гарантировать, что каждое задание будет обработано только один раз.
Мы можем использовать Collections.synchronizedList() для создания потокобезопасной очереди заданий. Для обработки заданий можно использовать несколько потоков, каждый из которых будет извлекать задания из очереди и обрабатывать их.
#Java #Training #Medium #SynchronizedCollections
Пример 1: Управление доступом к общему ресурсу
Одним из типичных сценариев использования синхронизированных коллекций является управление доступом к общему ресурсу. Представим, что у нас есть сервер, который обрабатывает запросы клиентов. Нам нужно сохранить историю запросов для каждого клиента и при этом гарантировать, что история будет корректно обновляться при одновременном доступе нескольких потоков.
Мы можем использовать Collections.synchronizedMap() для создания потокобезопасной карты, где ключами будут идентификаторы клиентов, а значениями — списки с историей запросов.
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
public class RequestHistoryManager {
private final Map<String, List<String>> clientRequestHistory = Collections.synchronizedMap(new HashMap<>());
public void addRequest(String clientId, String request) {
clientRequestHistory.computeIfAbsent(clientId, k -> Collections.synchronizedList(new ArrayList<>())).add(request);
}
public List<String> getRequestHistory(String clientId) {
return clientRequestHistory.getOrDefault(clientId, new ArrayList<>());
}
}
// Пример использования
RequestHistoryManager manager = new RequestHistoryManager();
manager.addRequest("client1", "GET /index.html");
manager.addRequest("client1", "POST /login");
manager.addRequest("client2", "GET /products");
System.out.println(manager.getRequestHistory("client1"));
System.out.println(manager.getRequestHistory("client2"));
В этом примере clientRequestHistory представляет собой синхронизированную карту, а списки запросов для каждого клиента также являются синхронизированными. Это гарантирует, что добавление и получение истории запросов будет происходить корректно даже при параллельном доступе.
Пример 2: Очередь задач в многопоточном приложении
Другой распространенный сценарий — использование синхронизированной коллекции для управления очередью задач в многопоточном приложении. Например, у нас есть система, которая должна обрабатывать задания в параллельных потоках, но при этом гарантировать, что каждое задание будет обработано только один раз.
Мы можем использовать Collections.synchronizedList() для создания потокобезопасной очереди заданий. Для обработки заданий можно использовать несколько потоков, каждый из которых будет извлекать задания из очереди и обрабатывать их.
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class TaskQueueManager {
private final List<String> taskQueue = Collections.synchronizedList(new LinkedList<>());
public void addTask(String task) {
taskQueue.add(task);
}
public String getNextTask() {
if (taskQueue.isEmpty()) {
return null;
}
return taskQueue.remove(0);
}
}
// Пример использования
TaskQueueManager taskQueueManager = new TaskQueueManager();
// Добавление задач
taskQueueManager.addTask("Task 1");
taskQueueManager.addTask("Task 2");
taskQueueManager.addTask("Task 3");
// Потоки обработки задач
Runnable worker = () -> {
String task;
while ((task = taskQueueManager.getNextTask()) != null) {
System.out.println(Thread.currentThread().getName() + " processing " + task);
}
};
Thread worker1 = new Thread(worker);
Thread worker2 = new Thread(worker);
worker1.start();
worker2.start();
Здесь taskQueue — это синхронизированный список, используемый как очередь задач. Потоки worker1 и worker2 одновременно извлекают задания из этой очереди и обрабатывают их. Благодаря синхронизации, мы гарантируем, что каждое задание будет обработано только одним потоком.
#Java #Training #Medium #SynchronizedCollections
Пример 3: Счетчик посещений веб-сайта
Представим, что у нас есть веб-сайт, который обрабатывает множество запросов в секунду. Нам нужно вести подсчет посещений сайта, причем из разных потоков одновременно. В этом случае синхронизированные коллекции помогут избежать некорректного подсчета.
Мы можем использовать Collections.synchronizedMap() для создания потокобезопасной карты, где ключом будет страница, а значением — счетчик посещений.
Пример 4: Синхронизированный доступ к общему ресурсу
Рассмотрим задачу, в которой несколько потоков должны безопасно добавлять элементы в общий список и извлекать их для обработки. Важно, чтобы все операции были синхронизированы, чтобы избежать потери данных.
Задача: Создать потокобезопасную очередь задач.
#Java #Training #Medium #SynchronizedCollections
Представим, что у нас есть веб-сайт, который обрабатывает множество запросов в секунду. Нам нужно вести подсчет посещений сайта, причем из разных потоков одновременно. В этом случае синхронизированные коллекции помогут избежать некорректного подсчета.
Мы можем использовать Collections.synchronizedMap() для создания потокобезопасной карты, где ключом будет страница, а значением — счетчик посещений.
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class VisitCounter {
private final Map<String, Integer> visitCounts = Collections.synchronizedMap(new HashMap<>());
public void recordVisit(String page) {
visitCounts.merge(page, 1, Integer::sum);
}
public int getVisitCount(String page) {
return visitCounts.getOrDefault(page, 0);
}
}
// Пример использования
VisitCounter visitCounter = new VisitCounter();
// Моделируем посещения страниц
Runnable visitSimulator = () -> {
for (int i = 0; i < 1000; i++) {
visitCounter.recordVisit("/index.html");
visitCounter.recordVisit("/contact.html");
}
};
Thread thread1 = new Thread(visitSimulator);
Thread thread2 = new Thread(visitSimulator);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Index Page Visits: " + visitCounter.getVisitCount("/index.html"));
System.out.println("Contact Page Visits: " + visitCounter.getVisitCount("/contact.html"));
В этом примере мы используем synchronizedMap для подсчета посещений страниц. Метод merge() безопасен для использования в многопоточной среде, что позволяет корректно увеличивать счетчики.
Пример 4: Синхронизированный доступ к общему ресурсу
Рассмотрим задачу, в которой несколько потоков должны безопасно добавлять элементы в общий список и извлекать их для обработки. Важно, чтобы все операции были синхронизированы, чтобы избежать потери данных.
Задача: Создать потокобезопасную очередь задач.
import java.util.Queue;
import java.util.LinkedList;
import java.util.Collections;
public class SynchronizedTaskQueue {
private final Queue<String> taskQueue = Collections.synchronizedList(new LinkedList<>());
public void addTask(String task) {
synchronized (taskQueue) {
taskQueue.add(task);
taskQueue.notify(); // Уведомляем ждущий поток о новой задаче
}
}
public String getTask() throws InterruptedException {
synchronized (taskQueue) {
while (taskQueue.isEmpty()) {
taskQueue.wait(); // Ждем, пока появится новая задача
}
return taskQueue.poll();
}
}
}
// Пример использования
SynchronizedTaskQueue queue = new SynchronizedTaskQueue();
// Поток для добавления задач
Thread producer = new Thread(() -> {
for (int i = 0; i < 5; i++) {
queue.addTask("Task " + i);
}
});
// Поток для обработки задач
Thread consumer = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
String task = queue.getTask();
System.out.println("Processing " + task);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
producer.start();
consumer.start();
В этом примере мы используем синхронизированную очередь задач, где метод addTask() добавляет задачи в очередь и уведомляет ждущие потоки, а метод getTask() ждет появления новой задачи, если очередь пуста. Таким образом, обеспечивается безопасный доступ к общему ресурсу в многопоточной среде.
#Java #Training #Medium #SynchronizedCollections
Properties, особенности и внутреннее устройство
Properties — это подкласс Hashtable, который используется для хранения ключей и значений в виде строк. Этот класс особенно полезен для хранения конфигурационных данных, таких как настройки приложений, пути к файлам, параметры базы данных и другие подобные параметры.
Основные характеристики Properties:
Наследование от Hashtable: Properties наследуется от класса Hashtable, что позволяет ему использовать все методы и возможности, предоставляемые Hashtable, такие как вставка, удаление, поиск и итерация по элементам.
Хранение только строк: В отличие от Hashtable, Properties хранит только строки в качестве ключей и значений. Это делает его удобным для работы с текстовыми конфигурациями.
Поддержка файлов: Properties предоставляет методы для загрузки и сохранения данных из/в файлы в формате .properties, что делает его идеальным для хранения конфигурационных файлов.
Внутреннее устройство класса Properties
Класс Properties реализован на основе хеш-таблицы, что позволяет эффективно хранить и извлекать данные. Однако, чтобы глубже понять, как работает Properties, давайте рассмотрим его внутреннее устройство.
Основные компоненты:
Наследование от Hashtable: Класс Properties наследует функциональность от Hashtable, что позволяет ему использовать хеширование для быстрого доступа к элементам.
Поля defaults: Поле defaults позволяет определить другой объект Properties, который будет использоваться для предоставления значений по умолчанию, если ключ не найден в текущем объекте.
Методы getProperty() и setProperty(): Эти методы являются основными для работы с парами "ключ-значение" и обеспечивают удобный интерфейс для получения и установки свойств.
Методы load() и store(): Эти методы используются для загрузки свойств из файла и сохранения их обратно в файл. Формат файла .properties поддерживает простую структуру текста, где каждая строка представляет собой пару "ключ=значение".
Формат файлов .properties
Файлы с расширением .properties содержат конфигурационные данные в текстовом формате. Эти файлы широко используются для хранения настроек приложений, переводов и других данных, которые могут изменяться без необходимости изменения исходного кода.
Пример файла config.properties:
#Java #Training #Medium #Properties
Properties — это подкласс Hashtable, который используется для хранения ключей и значений в виде строк. Этот класс особенно полезен для хранения конфигурационных данных, таких как настройки приложений, пути к файлам, параметры базы данных и другие подобные параметры.
Основные характеристики Properties:
Наследование от Hashtable: Properties наследуется от класса Hashtable, что позволяет ему использовать все методы и возможности, предоставляемые Hashtable, такие как вставка, удаление, поиск и итерация по элементам.
Хранение только строк: В отличие от Hashtable, Properties хранит только строки в качестве ключей и значений. Это делает его удобным для работы с текстовыми конфигурациями.
Поддержка файлов: Properties предоставляет методы для загрузки и сохранения данных из/в файлы в формате .properties, что делает его идеальным для хранения конфигурационных файлов.
Внутреннее устройство класса Properties
Класс Properties реализован на основе хеш-таблицы, что позволяет эффективно хранить и извлекать данные. Однако, чтобы глубже понять, как работает Properties, давайте рассмотрим его внутреннее устройство.
public class Properties extends Hashtable<Object, Object> {
// Хранение значений по умолчанию
protected Properties defaults;
// Конструкторы
public Properties() {
this(null);
}
public Properties(Properties defaults) {
this.defaults = defaults;
}
// Основные методы
public String getProperty(String key) {
Object oval = super.get(key);
String sval = (oval instanceof String) ? (String)oval : null;
return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
}
public String getProperty(String key, String defaultValue) {
String val = getProperty(key);
return (val == null) ? defaultValue : val;
}
public Object setProperty(String key, String value) {
return put(key, value);
}
// Методы для работы с файлами
public void load(InputStream inStream) throws IOException {
// ...
}
public void store(OutputStream out, String comments) throws IOException {
// ...
}
}
Основные компоненты:
Наследование от Hashtable: Класс Properties наследует функциональность от Hashtable, что позволяет ему использовать хеширование для быстрого доступа к элементам.
Поля defaults: Поле defaults позволяет определить другой объект Properties, который будет использоваться для предоставления значений по умолчанию, если ключ не найден в текущем объекте.
Методы getProperty() и setProperty(): Эти методы являются основными для работы с парами "ключ-значение" и обеспечивают удобный интерфейс для получения и установки свойств.
Методы load() и store(): Эти методы используются для загрузки свойств из файла и сохранения их обратно в файл. Формат файла .properties поддерживает простую структуру текста, где каждая строка представляет собой пару "ключ=значение".
Формат файлов .properties
Файлы с расширением .properties содержат конфигурационные данные в текстовом формате. Эти файлы широко используются для хранения настроек приложений, переводов и других данных, которые могут изменяться без необходимости изменения исходного кода.
Пример файла config.properties:
database.url=jdbc:mysql://localhost:3306/mydb
database.username=root
database.password=12345
Файл .properties имеет простой формат: каждая строка представляет собой пару "ключ=значение". Комментарии могут быть добавлены с помощью символов # или ! в начале строки.
#Java #Training #Medium #Properties
Особенности работы с Properties
Преемственность значений по умолчанию:
Одной из интересных возможностей Properties является возможность указания значений по умолчанию. Например, вы можете создать объект Properties, который будет содержать значения по умолчанию, и передать его в другой объект Properties.
Работа с файлами:
Одним из ключевых преимуществ Properties является его возможность загружать и сохранять свойства в файлы. Это особенно полезно для создания конфигурационных файлов, которые могут быть изменены без перекомпиляции приложения.
Обработка строковых значений:
Properties работают исключительно с строками, поэтому любые данные, которые необходимо хранить, должны быть преобразованы в строки. Это накладывает определенные ограничения, но также упрощает сериализацию и десериализацию данных.
Управление локализацией:
Properties часто используются в связке с ResourceBundle для управления переводами и локализацией в приложениях. Это позволяет легко поддерживать несколько языков в приложении, используя различные файлы .properties для каждого языка.
Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://www.baeldung.com/java-properties
https://www.geeksforgeeks.org/java-util-properties-class-java/
#Java #Training #Medium #Properties
Преемственность значений по умолчанию:
Одной из интересных возможностей Properties является возможность указания значений по умолчанию. Например, вы можете создать объект Properties, который будет содержать значения по умолчанию, и передать его в другой объект Properties.
Properties defaults = new Properties();
defaults.setProperty("language", "English");
Properties config = new Properties(defaults);
config.setProperty("database.url", "jdbc:mysql://localhost:3306/mydb");
System.out.println(config.getProperty("language")); // Выведет: English
В данном примере, если запрашиваемое свойство не найдено в объекте config, оно будет искаться в объекте defaults.
Работа с файлами:
Одним из ключевых преимуществ Properties является его возможность загружать и сохранять свойства в файлы. Это особенно полезно для создания конфигурационных файлов, которые могут быть изменены без перекомпиляции приложения.
try (FileInputStream input = new FileInputStream("config.properties")) {
Properties config = new Properties();
config.load(input);
System.out.println(config.getProperty("database.url"));
} catch (IOException e) {
e.printStackTrace();
}
В этом примере Properties загружаются из файла config.properties, и после этого можно получить доступ к его значениям.
Обработка строковых значений:
Properties работают исключительно с строками, поэтому любые данные, которые необходимо хранить, должны быть преобразованы в строки. Это накладывает определенные ограничения, но также упрощает сериализацию и десериализацию данных.
Управление локализацией:
Properties часто используются в связке с ResourceBundle для управления переводами и локализацией в приложениях. Это позволяет легко поддерживать несколько языков в приложении, используя различные файлы .properties для каждого языка.
Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://www.baeldung.com/java-properties
https://www.geeksforgeeks.org/java-util-properties-class-java/
#Java #Training #Medium #Properties
Baeldung
Getting Started with Java Properties | Baeldung
Learn how to work with key-value pairs in Java using the java.util.Properties class.
Что выведет код?
#Tasks
public class Main {
public static void main(String[] args) {
int a = 5;
int b = 10;
int c = a;
a = b;
b = c;
System.out.println(a + " " + b + " " + c);
}
}
#Tasks
❗️ ВНИМАНИЕ ❗️
Уважаемые подписчики, для разработки тестовой мини игры на языке JAVA, мы ищем 5-6 новичков в тестовую команду.
Что предстоит тем, кто примет участие:
- погружение в проектирование кода, совместное обдумывание и поиск оптимальных решений при помощи Miro.
- написание кода на Java Core.
- получение задач в JIRA (само собой обучение взаимодействию).
- реализация основных действия на GitHub: clone, pull, push и т.д. (и обучение всему этому).
- работа в команде.
Зачем нам все это?
Основная цель как не странно, это не готовый продукт, а прокачка софт-скилов, таких как командное взаимодействие, понимание процессов разработки, работы в Git и JIRA (которые требуются в каждой второй вакансии на HH), укрепить и улучшить работу с JAVA Core.
Требования:
- 2-3 часа свободно времени в день (в промежутке от 16 до 22 по МСК для общения с командой).
- Начальное знание JAVA Core. (Рассмотрим варианты)
- Неконфликтность и желание учиться))).
Пишите Ваши предложения в комментариях!
Всем лучей добра😉🔆
Уважаемые подписчики, для разработки тестовой мини игры на языке JAVA, мы ищем 5-6 новичков в тестовую команду.
Что предстоит тем, кто примет участие:
- погружение в проектирование кода, совместное обдумывание и поиск оптимальных решений при помощи Miro.
- написание кода на Java Core.
- получение задач в JIRA (само собой обучение взаимодействию).
- реализация основных действия на GitHub: clone, pull, push и т.д. (и обучение всему этому).
- работа в команде.
Зачем нам все это?
Основная цель как не странно, это не готовый продукт, а прокачка софт-скилов, таких как командное взаимодействие, понимание процессов разработки, работы в Git и JIRA (которые требуются в каждой второй вакансии на HH), укрепить и улучшить работу с JAVA Core.
Требования:
- 2-3 часа свободно времени в день (в промежутке от 16 до 22 по МСК для общения с командой).
- Начальное знание JAVA Core. (Рассмотрим варианты)
- Неконфликтность и желание учиться))).
Пишите Ваши предложения в комментариях!
Всем лучей добра😉🔆
Основные методы Properties и примеры использования
setProperty(String key, String value):
Этот метод используется для добавления или обновления пары "ключ-значение" в объекте Properties.
getProperty(String key):
Метод getProperty() позволяет получить значение свойства по его ключу. Если ключ не найден, метод вернет null.
getProperty(String key, String defaultValue):
Этот метод позволяет указать значение по умолчанию, которое будет возвращено в случае, если ключ не найден в объекте Properties.
load(InputStream inStream):
Метод load() загружает свойства из потока ввода (например, из файла).
store(OutputStream out, String comments):
Метод store() сохраняет свойства в выходной поток (например, в файл). Метод также позволяет добавить комментарии, которые будут записаны в начале файла.
propertyNames():
Метод propertyNames() возвращает перечисление всех ключей, содержащихся в объекте Properties.
stringPropertyNames():
Этот метод возвращает набор всех ключей, которые представлены строками.
remove(String key):
Метод remove() удаляет свойство по указанному ключу.
clear():
Метод clear() очищает все свойства из объекта Properties.
#Java #Training #Medium #Properties
setProperty(String key, String value):
Этот метод используется для добавления или обновления пары "ключ-значение" в объекте Properties.
Properties config = new Properties();
config.setProperty("database.url", "jdbc:mysql://localhost:3306/mydb");
config.setProperty("database.username", "root");
config.setProperty("database.password", "12345");
В этом примере мы создаем объект Properties и устанавливаем три свойства: URL базы данных, имя пользователя и пароль.
getProperty(String key):
Метод getProperty() позволяет получить значение свойства по его ключу. Если ключ не найден, метод вернет null.
String url = config.getProperty("database.url");
System.out.println("Database URL: " + url);
В этом примере значение свойства database.url извлекается и выводится на консоль.
getProperty(String key, String defaultValue):
Этот метод позволяет указать значение по умолчанию, которое будет возвращено в случае, если ключ не найден в объекте Properties.
String timeout = config.getProperty("connection.timeout", "30");
System.out.println("Connection timeout: " + timeout);
Если свойство connection.timeout не будет найдено, метод вернет значение "30".
load(InputStream inStream):
Метод load() загружает свойства из потока ввода (например, из файла).
try (FileInputStream input = new FileInputStream("config.properties")) {
Properties config = new Properties();
config.load(input);
} catch (IOException e) {
e.printStackTrace();
}
В этом примере свойства загружаются из файла config.properties.
store(OutputStream out, String comments):
Метод store() сохраняет свойства в выходной поток (например, в файл). Метод также позволяет добавить комментарии, которые будут записаны в начале файла.
try (FileOutputStream output = new FileOutputStream("config.properties")) {
config.store(output, "Database Configuration");
} catch (IOException e) {
e.printStackTrace();
}
В этом примере свойства сохраняются в файл config.properties, и в файл добавляется комментарий "Database Configuration".
propertyNames():
Метод propertyNames() возвращает перечисление всех ключей, содержащихся в объекте Properties.
Enumeration<?> propertyNames = config.propertyNames();
while (propertyNames.hasMoreElements()) {
String key = (String) propertyNames.nextElement();
System.out.println("Key: " + key + ", Value: " + config.getProperty(key));
}
В этом примере мы перебираем все ключи и выводим их вместе с соответствующими значениями.
stringPropertyNames():
Этот метод возвращает набор всех ключей, которые представлены строками.
Set<String> keys = config.stringPropertyNames();
for (String key : keys) {
System.out.println("Key: " + key + ", Value: " + config.getProperty(key));
}
stringPropertyNames() полезен, когда нужно работать с Set, а не с Enumeration.
remove(String key):
Метод remove() удаляет свойство по указанному ключу.
config.remove("database.password");
В этом примере удаляется свойство database.password.
clear():
Метод clear() очищает все свойства из объекта Properties.
config.clear();
После вызова этого метода все свойства будут удалены из объекта Properties.
#Java #Training #Medium #Properties
Примеры использования класса Properties
Пример 1: Загрузка и сохранение конфигурации приложения
Часто приложения требуют загрузки конфигурационных параметров из файла при старте и их сохранения при завершении.
Пример 2: Локализация с использованием ResourceBundle
Класс Properties может использоваться совместно с ResourceBundle для реализации локализации приложения. Например, хранение сообщений на разных языках в отдельных файлах .properties.
Пример 3: Автозаполнение настроек по умолчанию
Иногда нужно использовать настройки по умолчанию, если они не указаны в конфигурационном файле.
#Java #Training #Medium #Properties
Пример 1: Загрузка и сохранение конфигурации приложения
Часто приложения требуют загрузки конфигурационных параметров из файла при старте и их сохранения при завершении.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class AppConfig {
private Properties config = new Properties();
private String configFilePath;
public AppConfig(String configFilePath) {
this.configFilePath = configFilePath;
loadConfig();
}
public void loadConfig() {
try (FileInputStream input = new FileInputStream(configFilePath)) {
config.load(input);
} catch (IOException e) {
e.printStackTrace();
}
}
public void saveConfig() {
try (FileOutputStream output = new FileOutputStream(configFilePath)) {
config.store(output, "Application Configuration");
} catch (IOException e) {
e.printStackTrace();
}
}
public String getSetting(String key, String defaultValue) {
return config.getProperty(key, defaultValue);
}
public void setSetting(String key, String value) {
config.setProperty(key, value);
}
public static void main(String[] args) {
AppConfig appConfig = new AppConfig("app.properties");
// Получение настроек
String url = appConfig.getSetting("database.url", "jdbc:mysql://localhost:3306/defaultdb");
System.out.println("Database URL: " + url);
// Установка и сохранение настроек
appConfig.setSetting("app.theme", "dark");
appConfig.saveConfig();
}
}
В этом примере класс AppConfig управляет загрузкой и сохранением конфигурации приложения, хранящейся в файле app.properties.
Пример 2: Локализация с использованием ResourceBundle
Класс Properties может использоваться совместно с ResourceBundle для реализации локализации приложения. Например, хранение сообщений на разных языках в отдельных файлах .properties.
import java.util.Locale;
import java.util.ResourceBundle;
public class LocalizationExample {
public static void main(String[] args) {
Locale currentLocale = new Locale("en", "US");
ResourceBundle messages = ResourceBundle.getBundle("MessagesBundle", currentLocale);
System.out.println(messages.getString("greeting"));
}
}
Предположим, у нас есть два файла:
MessagesBundle_en_US.properties:
makefile
Копировать код
greeting=Hello!
MessagesBundle_fr_FR.properties:
makefile
Копировать код
greeting=Bonjour!
В зависимости от выбранной локали, приложение будет загружать соответствующий файл и использовать правильные сообщения.
Пример 3: Автозаполнение настроек по умолчанию
Иногда нужно использовать настройки по умолчанию, если они не указаны в конфигурационном файле.
import java.util.Properties;
public class DefaultSettingsExample {
public static void main(String[] args) {
Properties defaults = new Properties();
defaults.setProperty("app.theme", "light");
defaults.setProperty("app.language", "en");
Properties config = new Properties(defaults);
config.setProperty("app.theme", "dark");
System.out.println("Theme: " + config.getProperty("app.theme")); // Вывод: dark
System.out.println("Language: " + config.getProperty("app.language")); // Вывод: en
}
}
Здесь Properties использует значения по умолчанию, если они не были переопределены в основном конфигурационном объекте.
#Java #Training #Medium #Properties
Пример 4: Хранение пользовательских настроек
Предположим, у нас есть приложение, которое позволяет пользователям изменять настройки интерфейса, такие как тема или язык. Эти настройки можно сохранять в файл Properties, чтобы при следующем запуске приложения они автоматически подгружались.
#Java #Training #Medium #Properties
Предположим, у нас есть приложение, которое позволяет пользователям изменять настройки интерфейса, такие как тема или язык. Эти настройки можно сохранять в файл Properties, чтобы при следующем запуске приложения они автоматически подгружались.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class UserSettings {
private Properties settings = new Properties();
private String settingsFilePath;
public UserSettings(String settingsFilePath) {
this.settingsFilePath = settingsFilePath;
loadSettings();
}
private void loadSettings() {
try (FileInputStream input = new FileInputStream(settingsFilePath)) {
settings.load(input);
} catch (IOException e) {
System.out.println("Using default settings.");
}
}
public void saveSettings() {
try (FileOutputStream output = new FileOutputStream(settingsFilePath)) {
settings.store(output, "User Settings");
} catch (IOException e) {
e.printStackTrace();
}
}
public String getTheme() {
return settings.getProperty("theme", "light");
}
public void setTheme(String theme) {
settings.setProperty("theme", theme);
}
public String getLanguage() {
return settings.getProperty("language", "en");
}
public void setLanguage(String language) {
settings.setProperty("language", language);
}
public static void main(String[] args) {
UserSettings userSettings = new UserSettings("user.properties");
System.out.println("Current theme: " + userSettings.getTheme());
System.out.println("Current language: " + userSettings.getLanguage());
userSettings.setTheme("dark");
userSettings.setLanguage("fr");
userSettings.saveSettings();
}
}
В этом примере пользовательские настройки хранятся в файле user.properties и загружаются при запуске приложения. Пользователь может изменить тему и язык, и эти изменения сохраняются для последующего использования.
#Java #Training #Medium #Properties
Всем доброго субботнего утра!☀️
Надеюсь у всех была продуктивная неделя, все цели достигнуты и все желания выполнены!
У кого какие планы? Давайте уже, выкладывайте ваши пет-проекты, будем учиться друг у друга)))
====================================================
А я, если честно, еще не определился с темой которую будем рассматривать на встрече завтра🤷♂️, но думаю что-то придумаю)))
Есть мысли рассмотреть Docker или создание своей кастомной @аннотации))
Если у Вас есть идеи - предлагайте, рассмотрим)))😉
Надеюсь у всех была продуктивная неделя, все цели достигнуты и все желания выполнены!
У кого какие планы? Давайте уже, выкладывайте ваши пет-проекты, будем учиться друг у друга)))
====================================================
А я, если честно, еще не определился с темой которую будем рассматривать на встрече завтра🤷♂️, но думаю что-то придумаю)))
Есть мысли рассмотреть Docker или создание своей кастомной @аннотации))
Если у Вас есть идеи - предлагайте, рассмотрим)))😉