Основные компоненты
✔️ Config Server — сервер, который хранит конфигурации (обычно в Git) и раздает их микросервисам.
✔️ Config Client — клиент в микросервисах, который получает конфигурации от Config Server.
Возможности
✔️ Централизация конфигураций всех сервисов.
✔️ Поддержка версионирования конфигураций (например, через Git).
✔️ Динамическое обновление конфигураций без перезапуска приложений с помощью Spring Cloud Bus.
✔️ Поддержка различных сред и профилей (dev, prod и т.д.).
Пример настройки Config Server:
spring:
cloud:
config:
server:
git:
uri: https://github.com/your-repo/config-repo
Пример настройки Config Client:
spring:
cloud:
config:
uri: http://localhost:8888
profile: dev
Преимущества: упрощает управление конфигурациями, поддерживает разные среды, позволяет динамически обновлять настройки.
Недостатки: важен контроль за доступом и стабильностью Config Server.
#java #Spring #Cloud #Config
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1
В Java есть недооценённая фишка - ленивые вычисления через
Supplier. Это может сильно упростить код и улучшить производительность.📦 Что такое `Supplier`?
Это функциональный интерфейс из
java.util.function, который просто возвращает значение:
Supplier<String> supplier = () -> "Hello";
System.out.println(supplier.get());
Но магия начинается, когда используешь его правильно 👇
🔥 Кейс: дорогое вычисление
public String getData() {
System.out.println("Loading...");
return "data";
}
Теперь сравни:
❌ Обычный вызов:
String result = getData(); // всегда выполняется
✅ Ленивый вызов:
Supplier<String> supplier = this::getData;
// вызов произойдёт только здесь
String result = supplier.get();
👉 Код выполняется только когда реально нужен результат.
⚡ Практическое применение: логирование
logger.debug("Result: " + expensiveOperation());
❗ Даже если debug выключен —
expensiveOperation() всё равно выполнится.✅ Правильно:
logger.debug(() -> "Result: " + expensiveOperation());
👉 Вычисление произойдёт только если лог реально пишется.
🧠 Комбинация с `Optional`
String name = Optional.ofNullable(getName())
.orElseGet(() -> generateDefaultName());
👉
generateDefaultName() вызовется только если значение отсутствует(в отличие от
orElse, который выполняется всегда)🚀 Паттерн: кэширование (lazy cache)
Supplier<String> cached = new Supplier<>() {
private String value;
@Override
public String get() {
if (value == null) {
value = loadExpensiveData();
}
return value;
}
};
👉 Получаешь простую ленивую инициализацию без лишних библиотек
📌 Вывод
Supplier — это не просто "лямбда ради лямбды", а инструмент для:* ленивых вычислений
* оптимизации
* более чистого API
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍1
Одна из самых коварных тем в Java — это контракт между
equals() и hashCode(). Ошибся и HashMap или HashSet начинают вести себя "магически" (читай: ломаются).📦 Проблема на практике
Set<User> users = new HashSet<>();
users.add(new User("Alex"));
System.out.println(users.contains(new User("Alex"))); // ❌ false
🤨 Почему
false, если значения одинаковые?⚠️ Причина
По умолчанию
equals() сравнивает ссылки (==), а не содержимое.✅ Правильная реализация
public class User {
private String name;
// equals
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return Objects.equals(name, user.name);
}
// hashCode
@Override
public int hashCode() {
return Objects.hash(name);
}
}
🔥 Почему важны ОБА метода?
Если переопределить только
equals():
users.add(new User("Alex"));
users.contains(new User("Alex")); // ❌ всё ещё может быть false
👉 Потому что
HashSet сначала смотрит на hashCode(), а потом уже на equals().⚡ Контракт, который нельзя нарушать
1. Если
equals() возвращает true → hashCode() обязан быть одинаковым2. Если
hashCode() одинаковый → equals() может быть как true, так и false💣 Классическая ошибка
Изменяем объект после добавления в
HashSet:
User user = new User("Alex");
users.add(user);
user.setName("Bob");
users.contains(user); // ❌ может вернуть false
👉 Объект "потерялся" в коллекции
🧠 Как избежать проблем
* Делай объекты immutable (final поля)
* Используй
record (Java 16+):
public record User(String name) {}
👉
equals() и hashCode() генерируются автоматически и корректно📌 Вывод
Коллекции в Java работают быстро благодаря
hashCode(),но требуют строгого соблюдения контракта.
Нарушишь - получишь баги, которые очень сложно отловить 🐛
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤1
<?>В Java
<?> называется неограниченным wildcard. Он обозначает, что параметр типа может быть любым, то есть неизвестным на этапе компиляции. Это удобно, когда метод или класс работают с обобщёнными типами, но конкретный тип элемента не важен.Например, выражение
List<?> означает список, элементы которого могут быть любого типа. Такой подход позволяет писать более универсальный и гибкий код, но при этом накладывает ограничения: мы не можем добавлять новые элементы в коллекцию, поскольку компилятор не знает конкретный тип элементов, чтобы обеспечить безопасность типов.
import java.util.List;
public class WildcardExample {
public static void printList(List<?> list) {
for (Object element : list) { // Элементы можно читать как Object
System.out.println(element);
}
}
public static void main(String[] args) {
List<Integer> intList = List.of(1, 2, 3);
List<String> strList = List.of("A", "B", "C");
printList(intList); // Вывод: 1 2 3
printList(strList); // Вывод: A B C
}
}
Здесь
List<?> позволяет передавать любой тип списка, но мы можем безопасно читать только как Object.
public static void addElement(List<?> list) {
// list.add("Hello"); // Ошибка компиляции!
}
#java #wildcard
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤1
nullВозвращение пустых коллекций вместо
null-это рекомендуемый подход для методов, возвращающих коллекции. Он упрощает обработку данных, предотвращает ошибки и делает код более предсказуемым.1. Улучшение читаемости: Код становится проще, так как не нужно проверять результат на null.
2. Предотвращение NullPointerException: Исключается вероятность ошибок, связанных с доступом к null.
3.Соответствие принципу наименьшего удивления: Методы всегда возвращают коллекцию, даже если она пуста.
4. Эффективность: Пустые коллекции создаются один раз и переиспользуются благодаря реализации через паттерн Singleton.
5. Совместимость с функциональным программированием: Пустые коллекции легко интегрируются в стримы и другие функциональные конструкции.
Пример:
public class CacheService {
private final Map<String, List<Object>> cache = new ConcurrentHashMap<>();
public List<Object> getCachedValues(String key) {
return cache.getOrDefault(key, Collections.emptyList());
}
public void addToCache(String key, Object value) {
cache.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
}
}
Использование пустых коллекций вместо null делает код более устойчивым и предсказуемым. Это особенно важно в сложных многопоточных приложениях или системах с большим количеством взаимосвязанных компонентов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1
Многие воспринимают
try-with-resources как просто удобную замену finally. Но под капотом есть важная деталь, о которой часто забывают - подавленные исключения (suppressed exceptions).📦 Классический код
try {
InputStream is = new FileInputStream("file.txt");
// работа с потоком
} finally {
is.close();
}
❗ Проблема: если в
try и в close() произойдут исключения - одно из них потеряется.✅ try-with-resources
try (InputStream is = new FileInputStream("file.txt")) {
// работа с потоком
}
👉 Java сама закроет ресурс и корректно обработает исключения
🔥 Вот где магия
try (MyResource r = new MyResource()) {
throw new RuntimeException("Ошибка в try");
}
И допустим,
close() тоже кидает исключение:
@Override
public void close() {
throw new RuntimeException("Ошибка при закрытии");
}
🤯 Что произойдёт?
* Основное исключение:
"Ошибка в try"* Исключение из
close() НЕ потеряется* Оно попадёт в suppressed exceptions
📌 Как их получить
try (MyResource r = new MyResource()) {
...
} catch (Exception e) {
for (Throwable t : e.getSuppressed()) {
t.printStackTrace();
}
}
⚠️ Почему это важно
Если не знаешь про suppressed exceptions:
* можно потерять важную информацию об ошибках
* сложнее дебажить ресурсы (файлы, сокеты, DB)
🧠 Кастомные ресурсы
Чтобы использовать
try-with-resources, класс должен реализовывать AutoCloseable:
class MyResource implements AutoCloseable {
@Override
public void close() {
// cleanup
}
}
👉 Даже свои классы можно встроить в этот механизм
🚀 Маленький лайфхак (Java 9+)
Можно объявить ресурс заранее:
InputStream is = new FileInputStream("file.txt");
try (is) {
// используем
}
📌 Вывод
try-with-resources это не только удобство, а ещё и правильная модель обработки исключений, которую вручную реализовать сложно.Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1
📌 Что такое
Ключевое слово
✔️ Основные особенности:
1️⃣ Обеспечивает чтение переменной из основной памяти, а не из кэша потока.
2️⃣ Гарантирует видимость изменений между потоками.
Пример:
💡 Ограничение:
#java #volatile #multithreading
volatile и как оно работает?Ключевое слово
volatile в Java используется для переменных, к которым обращаются несколько потоков. Оно гарантирует, что изменения переменной одним потоком будут видны другим.1️⃣ Обеспечивает чтение переменной из основной памяти, а не из кэша потока.
2️⃣ Гарантирует видимость изменений между потоками.
Пример:
class SharedObject {
volatile int count = 0;
}volatile не гарантирует атомарность операций. Для этого используйте synchronized или классы из java.util.concurrent.#java #volatile #multithreading
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2
Метод
deepToString из класса Arrays используется для создания строкового представления многомерных массивов (например, массивов массивов). Он обходит каждый уровень вложенности массива и выводит его элементы в виде строки. Это удобно для работы с многомерными массивами, так как стандартный метод toString не раскрывает их структуру.Пример использования:
int[][] array = {{1, 2, 3}, {4, 5, 6}};
System.out.println(Arrays.deepToString(array));
// [[1, 2, 3], [4, 5, 6]]
Этот метод работает рекурсивно, обеспечивая полное отображение структуры массива любой вложенности.
#java #Arrays #deepToString
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤2
StringBuilder и StringBufferИ
StringBuilder, и StringBuffer используются для работы со строками, но между ними есть важные отличия.✔️ StringBuilder быстрее, но не потокобезопасен.
✔️ StringBuffer потокобезопасен, но медленнее из-за синхронизации.
StringBuilder:StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb); // Hello WorldStringBuffer:StringBuffer sb = new StringBuffer("Hello");
sb.append(" World");
System.out.println(sb); // Hello WorldStringBuilder для лучшей производительности.#java #stringbuilder #stringbuffer
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍1🆒1
✔️ В Java класс может одновременно реализовать несколько интерфейсов, но наследоваться только от одного класса.
✔️ Абстрактные классы используются только тогда, когда присутствует тип отношений «is a» (является). Интерфейсы могут реализоваться классами, которые не связаны друг с другом.
✔️ Абстрактный класс - средство, позволяющее избежать написания повторяющегося кода, инструмент для частичной реализации поведения. Интерфейс - это средство выражения семантики класса, контракт, описывающий возможности. Все методы интерфейса неявно объявляются как
public abstract или (начиная с Java 8) default - методами с реализацией по-умолчанию, а поля - public static final.✔️ Интерфейсы позволяют создавать структуры типов без иерархии.
✔️ Наследуясь от абстрактного, класс «растворяет» собственную индивидуальность. Реализуя интерфейс, он расширяет собственную функциональность.
Абстрактные классы содержат частичную реализацию, которая дополняется или расширяется в подклассах. При этом все подклассы схожи между собой в части реализации, унаследованной от абстрактного класса, и отличаются лишь в части собственной реализации абстрактных методов родителя. Поэтому абстрактные классы применяются в случае построения иерархии однотипных, очень похожих друг на друга классов. В этом случае наследование от абстрактного класса, реализующего поведение объекта по умолчанию может быть полезно, так как позволяет избежать написания повторяющегося кода. Во всех остальных случаях лучше использовать интерфейсы.
#java #interface #abstract
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1🥴1
Comparator и ComparableВ
Java для сортировки объектов используются два ключевых интерфейса: Comparable и Comparator. Понимание их отличий и применения поможет вам эффективно управлять сортировкой данных в коллекциях.📚 Краткие определения:
- Comparable:
- Используется, когда класс должен иметь естественный порядок. Например, мы можем сортировать людей по возрасту.
- Сигнатура метода:
int compareTo(T o).Пример:
class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
@Override
public int compareTo(Person other) {
return Integer.compare(this.age, other.age); // Сравнение по возрасту
}
}
- Comparator:
- Используется для создания внешних стратегий сравнения, позволяя определять несколько способов сортировки. Подходит для сортировки объектов разных классов.
- Сигнатура метода:
int compare(T o1, T o2).Пример:
import java.util.Comparator;
class NameComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name); // Сравнение по имени
}
}
⚖️
Когда использовать:- Comparable:
- Используйте, если у класса есть естественный порядок. Например, чтобы сортировать людей по возрасту.
- Сортировка с помощью
Collections.sort() или Arrays.sort() будет проще.Пример использования:
List<Person> people = Arrays.asList(new Person("Alice", 30), new Person("Bob", 25));
Collections.sort(people); // Сортировка по возрасту с использованием Comparable
- Comparator:
- Идеален для ситуаций, когда необходимо изменить порядок сортировки или сравнивать объекты разных классов.
Пример использования:
List<Person> people = Arrays.asList(new Person("Alice", 30), new Person("Bob", 25));
Collections.sort(people, new NameComparator()); // Сортировка по имени с использованием Comparator
#java #Comparator #Comparable
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1