Библиотека Java разработчика
📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP
إظهار المزيد📈 نظرة تحليلية على قناة تيليجرام Библиотека Java разработчика
تُعد قناة Библиотека Java разработчика (@bookjava) في القطاع اللغوي الروسية لاعباً نشطاً. يضم المجتمع حالياً 10 006 مشتركاً، محتلاً المرتبة 12 158 في فئة التكنولوجيات والتطبيقات والمرتبة 63 521 في منطقة روسيا.
📊 مؤشرات الجمهور والحراك
منذ تأسيسه في невідомо، حقق المشروع نمواً سريعاً وجمع 10 006 مشتركاً.
بحسب آخر البيانات بتاريخ 26 أكتوبر, 2026، تحافظ القناة على نشاط مستقر. خلال آخر 30 يوماً تغيّر عدد الأعضاء بمقدار -56، وفي آخر 24 ساعة بمقدار -1، مع بقاء الوصول العام مرتفعاً.
- حالة التحقق: غير موثّقة
- معدل التفاعل (ER): يبلغ متوسط تفاعل الجمهور 8.06%. وخلال أول 24 ساعة من النشر يحصد المحتوى عادةً 4.04% من ردود الفعل نسبةً إلى إجمالي المشتركين.
- وصول المنشورات: يحصل كل منشور على متوسط 806 مشاهدة. وخلال اليوم الأول يجمع عادةً 404 مشاهدة.
- التفاعلات والاستجابة: يتفاعل الجمهور بانتظام؛ متوسط التفاعلات لكل منشور يبلغ 4.
- الاهتمامات الموضوعية: يركز المحتوى على مواضيع رئيسية مثل string, интерфейс, строка, boot, api.
📝 الوصف وسياسة المحتوى
يصف المؤلف القناة بأنها مساحة للتعبير عن الآراء الذاتية:
“📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate.
По всем вопросам @evgenycarter
РКН clck.ru/3KoGeP”
بفضل وتيرة التحديث المرتفعة (أحدث البيانات بتاريخ 27 أكتوبر, 2026) تحافظ القناة على حداثتها ومستوى وصول مرتفع. وتُظهر التحليلات تفاعلاً نشطاً من الجمهور، ما يجعلها نقطة تأثير مهمة ضمن فئة التكنولوجيات والتطبيقات.
CompletableFuture в Java
Сегодня я хочу рассказать вам про CompletableFuture — мощный инструмент для работы с асинхронными операциями в Java. Если вам приходилось ждать выполнения долгих задач в коде и хотелось бы улучшить производительность, то этот пост для вас! 🚀
🔹 Что такое CompletableFuture?
CompletableFuture — это часть java.util.concurrent с Java 8, которая позволяет выполнять асинхронные задачи и удобно комбинировать их. В отличие от обычного Future, CompletableFuture поддерживает цепочки вызовов, композицию задач и обработку ошибок.
🔹 Пример использования
Допустим, у нас есть сервис, который загружает данные по сети. Обычный подход синхронного вызова будет блокировать поток, но с CompletableFuture мы можем избежать этого:
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
CompletableFuture.supplyAsync(() -> {
System.out.println("Загружаем данные...");
sleep(2000);
return "Данные загружены";
}).thenApply(data -> {
System.out.println("Обрабатываем: " + data);
return data.toUpperCase();
}).thenAccept(System.out::println)
.exceptionally(ex -> {
System.out.println("Ошибка: " + ex.getMessage());
return null;
});
sleep(3000); // Даем время асинхронной операции завершиться
}
private static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
🔹 Разбор кода
1️⃣ supplyAsync() — запускает асинхронную задачу в отдельном потоке.
2️⃣ thenApply() — позволяет обработать результат (например, изменить его формат).
3️⃣ thenAccept() — принимает готовый результат и выполняет действие.
4️⃣ exceptionally() — обрабатывает возможные ошибки.
🔹 Зачем это нужно?
✅ Улучшает производительность за счет асинхронного выполнения.
✅ Избегает блокировки основного потока.
✅ Позволяет легко комбинировать операции.
Используете ли вы CompletableFuture в своих проектах? Делитесь опытом в комментариях! 👇
📲 Мы в MAX
👉@BookJava-Xms<size> – задает начальный размер кучи.
- -Xmx<size> – задает максимальный размер кучи.
- -XX:NewRatio=<n> – определяет соотношение между молодым и старым поколением.
- -XX:SurvivorRatio=<n> – соотношение между Eden и Survivor.
⚡ Гаражная сборка (GC):
- -XX:+UseG1GC – включает G1 Garbage Collector (по умолчанию в Java 9+).
- -XX:+UseParallelGC – включает Parallel GC.
- -XX:+UseZGC – включает экспериментальный ZGC (минимальная пауза).
- -XX:+UseShenandoahGC – еще один GC с низкими задержками.
🛠️ Диагностика и отладка:
- -XX:+PrintGCDetails – подробный вывод информации о сборке мусора.
- -XX:+HeapDumpOnOutOfMemoryError – дамп памяти при OOM.
- -XX:HeapDumpPath=<path> – указывает путь для дампа памяти.
- -XX:+ExitOnOutOfMemoryError – завершает JVM при OOM.
🏎️ Оптимизация JIT:
- -XX:+TieredCompilation – адаптивная компиляция кода.
- -XX:+UseStringDeduplication – уменьшает использование памяти строками.
- -XX:+AlwaysPreTouch – аллокация памяти заранее (полезно для больших heap'ов).
Попробуйте поэкспериментировать с этими параметрами и посмотрите, как они влияют на производительность вашего приложения!
Какие параметры JVM используете вы? Пишите в комментариях!
📲 Мы в MAX
👉@BookJava@Transactional в Spring: Где Подводные Камни?
Давайте обсудимм одну из самых популярных аннотаций в Spring — @Transactional. Многие знают, что она используется для управления транзакциями, но не все понимают, как она работает под капотом и какие проблемы могут возникнуть. Давайте разбираться!
🔍 Как работает @Transactional?
Когда вы помечаете метод @Transactional, Spring проксирует этот метод и оборачивает его в транзакцию. Это значит, что до начала метода открывается транзакция, а после — либо коммитится (если нет ошибок), либо откатывается (если есть исключение).
Но тут важно помнить:
🔹 @Transactional работает только на public методах (если используется Spring AOP).
🔹 Вызовы методов внутри одного класса не учитывают @Transactional. Если вызвать метод, аннотированный @Transactional, внутри другого метода того же класса, транзакция не создастся.
🔹 По умолчанию, транзакция откатывается только при RuntimeException. Если бросить checked-исключение, Spring не откатит транзакцию.
⚠️ Распространённые ошибки
❌ Аннотация на private методе
Транзакция просто не будет работать, так как Spring AOP не перехватит вызов.
❌ Вызов @Transactional метода внутри того же класса
Транзакция не создастся, так как вызов происходит без участия Spring Proxy. Решение — выносить такие методы в отдельный бин или использовать TransactionTemplate.
❌ Неправильный rollback
Если в методе выбрасывается checked-исключение, Spring по умолчанию **не откатывает** транзакцию. Чтобы изменить это поведение, нужно явно указать `@Transactional(rollbackFor = Exception.class).
✅ Как избежать проблем?
✔️ Всегда ставьте @Transactional на публичные методы.
✔️ Вызывайте @Transactional-методы только через Spring-управляемые бины.
✔️ Контролируйте rollback через rollbackFor.
✔️ Используйте propagation = REQUIRES_NEW, если хотите создать новую независимую транзакцию.
Кто сталкивался с неожиданным поведением @Transactional? Давайте обсудим в комментариях!
📲 Мы в MAX
👉@BookJava
String str = new String("Hello"); // Избыточно
✅ Хорошо:
String str = "Hello"; // Используем строковый пул
То же самое касается Integer.valueOf() вместо new Integer().
🔄 2. Используйте StringBuilder вместо конкатенации в цикле
Если вы объединяете строки в цикле, StringBuilder будет значительно быстрее.
❌ Плохо:
String result = "";
for (int i = 0; i < 100; i++) {
result += i; // Создает новый объект String на каждой итерации
}
✅ Хорошо:
StringBuilder result = new StringBuilder();
for (int i = 0; i < 100; i++) {
result.append(i);
}
Такой код работает в разы быстрее!
🏎 3. Правильно выбирайте коллекции
Используйте ArrayList, если не нужна частая вставка/удаление элементов в середине списка.
Используйте HashSet, если важны уникальные значения и не нужен порядок.
Используйте LinkedList, если нужна частая вставка/удаление в середине списка.
⚡ 4. Не злоупотребляйте Stream API
Да, Stream API удобен, но иногда он замедляет код. Например:
❌ Плохо:
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
int sum = numbers.stream().reduce(0, Integer::sum);
✅ Хорошо:
int sum = 0;
for (int num : numbers) {
sum += num;
}
Цикл быстрее, потому что не тратит время на создание объектов и лямбды.
🔥 Вывод
Оптимизация — это не просто ускорение кода, но и улучшение его читаемости и поддержки. Используйте правильные структуры данных, избегайте лишних аллокаций, выбирайте оптимальные конструкции.
А какие советы по оптимизации Java кода используете вы? Пишите в комментариях! 👇 🚀
📲 Мы в MAX
👉@BookJavacollection.stream()
🔹 Из массива: Arrays.stream(array)
🔹 Из набора элементов: Stream.of(1, 2, 3)
🔹 Бесконечный поток: Stream.iterate(0, n -> n + 1)
🔹 Бесконечный поток с ограничением (Java 9): Stream.iterate(1, n -> n < 100, n -> n * 2)
🔹 Генерация элементов: Stream.generate(Math::random)
🔹 Диапазон значений:
- IntStream.range(1, 5) (1, 2, 3, 4)
- IntStream.rangeClosed(1, 5) (1, 2, 3, 4, 5)
🔹 Из файла: Files.lines(Path.of("file.txt"))
🔹 Из строки: "abc".chars()
Промежуточные операции
Stream API поддерживает множество преобразований. Наиболее распространенные:
✔️ Фильтрация: filter(Predicate<T>) – оставляет только элементы, соответствующие условию.
✔️ Удаление дубликатов: distinct() – исключает повторяющиеся элементы.
✔️ Ограничение количества: limit(n) – берет первые n элементов.
✔️ Сортировка: sorted() – упорядочивает элементы.
Менее очевидные операции
🔹 map(Function<T, R>) – применяет функцию к каждому элементу.
🔹 flatMap(Function<T, Stream<R>>) – «разворачивает» элементы из вложенных структур.
🔹 takeWhile(Predicate<T>) (Java 9) – берет элементы, пока выполняется условие.
🔹 dropWhile(Predicate<T>) (Java 9) – пропускает элементы, пока условие выполняется.
🔹 peek(Consumer<T>) – выполняет действие без изменения элементов (удобно для логирования).
Конечные операции
Стрим начинает обработку данных только при вызове конечной операции:
📌 Коллекционирование:
- collect(Collectors.toList()) – собирает в List.
- collect(Collectors.toSet()) – собирает в Set.
📌 Поиск элементов:
- findFirst() – первый элемент.
- findAny() – любой элемент (оптимизирован для параллельных потоков).
- anyMatch(Predicate<T>) – хотя бы один элемент удовлетворяет условию.
- allMatch(Predicate<T>) – все элементы удовлетворяют условию.
- noneMatch(Predicate<T>) – ни один элемент не удовлетворяет условию.
📌 Агрегация:
- min(Comparator<T>) – минимальный элемент.
- max(Comparator<T>) – максимальный элемент.
- count() – количество элементов.
- reduce(BinaryOperator<T>) – свертка элементов в одно значение.
📌 Побочные эффекты:
- forEach(Consumer<T>) – выполняет действие над каждым элементом.
- forEachOrdered(Consumer<T>) – выполняет действие, сохраняя порядок (важно для параллельных потоков).
Особенности работы со Stream API
1️⃣ Стрим – это не структура данных
Он лишь обходит источник, выполняя операции лениво.
2️⃣ Стрим нельзя использовать повторно
После вызова конечной операции повторное использование потока приведет к IllegalStateException.
3️⃣ Исходные данные не изменяются
Методы Stream API не модифицируют исходную коллекцию.
Разбор сложных случаев
❌ Ошибочный код:
Stream.of(-1, 0, 1).max(Math::max).get();
✅ Почему ошибка?
Метод max() принимает Comparator<T>, но Math.max(a, b) – это BiFunction<Integer, Integer, Integer>. Они не эквивалентны!
ℹ️ Решение:
Stream.of(-1, 0, 1).max(Integer::compareTo).get(); // Вернет 1
📲 Мы в MAX
👉@BookJavaCompletableFuture в Java: Асинхронность без боли
Всем добрый вечер! Сегодня расскажу про CompletableFuture — мощный инструмент для работы с асинхронными операциями в Java. Если вы хотите избавиться от блокирующего кода и сложных коллбэков, этот пост для вас!
🤔 Что такое CompletableFuture?
Это часть java.util.concurrent, позволяющая писать асинхронный код в декларативном стиле, без создания сложных цепочек Thread и ExecutorService.
🚀 Базовый пример использования
Допустим, у нас есть задача загрузить данные с сервера. Как это сделать асинхронно?
import java.util.concurrent.CompletableFuture;
public class AsyncExample {
public static void main(String[] args) {
CompletableFuture.supplyAsync(() -> {
// Имитация долгого запроса
sleep(2000);
return "Данные загружены";
}).thenAccept(result ->
System.out.println("Результат: " + result)
);
System.out.println("Задача запущена, ждем результат...");
sleep(3000); // Чтобы main не завершился раньше времени
}
private static void sleep(int millis) {
try { Thread.sleep(millis); }
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}
}
🔍 Разбираем код
1️⃣ supplyAsync() — выполняет операцию в фоновом потоке.
2️⃣ thenAccept() — получает результат и выполняет код после завершения.
3️⃣ Главный поток продолжает работать, не блокируя выполнение.
🛠 Расширяем функционал
Можно комбинировать задачи:
CompletableFuture.supplyAsync(() -> "Привет, ")
.thenApply(greeting -> greeting + "мир!")
.thenAccept(System.out::println);
✅ thenApply() изменяет данные перед следующим шагом.
✅ thenAccept() выполняет финальную операцию.
📌 Где использовать?
🔹 Запросы к API без блокировки
🔹 Асинхронная обработка данных
🔹 Параллельные вычисления
📲 Мы в MAX
👉@BookJavavolatile и когда его использовать?
🔥 Что делает volatile?
Ключевое слово volatile гарантирует, что переменная всегда будет читаться из памяти, а не из кэша потока. Это помогает избежать проблем, когда один поток изменяет переменную, но другой поток продолжает работать со старым значением из кэша.
🔄 Разбираем на примере:
class SharedResource {
volatile boolean flag = false;
void changeFlag() {
flag = true;
}
}
class Worker extends Thread {
SharedResource resource;
Worker(SharedResource resource) {
this.resource = resource;
}
public void run() {
while (!resource.flag) {
// Ждём, пока флаг изменится
}
System.out.println("Флаг изменился! Поток завершает работу.");
}
}
public class VolatileExample {
public static void main(String[] args) throws InterruptedException {
SharedResource resource = new SharedResource();
Worker worker = new Worker(resource);
worker.start();
Thread.sleep(1000);
resource.changeFlag(); // Флаг изменится, и поток завершит цикл
worker.join();
}
}
🛑 Важные моменты:
✅ volatile не делает операции атомарными. Если вам нужна атомарность, используйте synchronized или Atomic классы.
✅ Он не предотвращает гонки данных, но гарантирует видимость изменений между потоками.
✅ Лучше всего подходит для флагов завершения потоков и подобных сценариев.
📲 Мы в MAX
👉@BookJavaprevious(), hasPrevious(), add(), set().
— ListIterator позволяет получить индекс текущего элемента.
— ListIterator может начать итерацию с произвольного индекса списка, а Iterator только с начала.
— ListIterator можно получить только из объектов, реализующих List, а Iterator из любой коллекции.
— ListIterator является более функциональным и позволяет вносить изменения в список во время итерации, Iterator — только читать.
— Итераторы безопасны для использования в многопоточных приложениях, а ListIterator — нет.
📲 Мы в MAX
👉@BookJavaOptional в Java: избегаем NullPointerException!
Привет, друзья! Сегодня хочу поговорить о Optional, который помогает нам избежать NullPointerException и делает код чище.
❓ Что такое Optional?
Optional<T> — это контейнер, который может содержать значение типа T или быть пустым. Это альтернатива null, которая явно указывает, что значение может отсутствовать.
🔥 Как использовать?
1️⃣ Создание Optional:
Optional<String> optional = Optional.of("Hello, Java!");
⚠️ Если передать null, будет NullPointerException.
2️⃣ Создание пустого Optional:
Optional<String> emptyOptional = Optional.empty();
3️⃣ Обёртка для возможного null:
Optional<String> nullableOptional = Optional.ofNullable(null);
Если передать null, Optional не упадёт, а просто будет пустым.
4️⃣ Проверка наличия значения:
optional.isPresent(); // true
optional.isEmpty(); // false
Но лучше использовать ifPresent:
optional.ifPresent(value -> System.out.println(value));
5️⃣ Получение значения с orElse:
String result = optional.orElse("Значение по умолчанию");
6️⃣ Получение с orElseGet:
String result = optional.orElseGet(() -> "Вычисленное значение");
7️⃣ Исключение, если значения нет:
String result = optional.orElseThrow(() -> new RuntimeException("Значение отсутствует!"));
8️⃣ Фильтрация:
Optional<String> filtered = optional.filter(val -> val.startsWith("Hello"));
9️⃣ Трансформация с map:
Optional<Integer> length = optional.map(String::length);
🔚 Итог:
Optional — мощный инструмент, но не стоит злоупотреблять им везде. Используйте его в возвращаемых значениях, но не в полях и параметрах методов.
📲 Мы в MAX
👉@BookJava@Data – Комбо-аннотация, которая сразу добавляет @Getter, @Setter, @ToString, @EqualsAndHashCode и @RequiredArgsConstructor. Если у вас обычный POJO-класс, просто ставите @Data, и всё!
@Data
public class User {
private String name;
private int age;
}
📌 Результат: автоматическая генерация геттеров, сеттеров и других методов.
🔹 @Builder – Шаблон проектирования "Строитель" на стероидах!
@Builder
public class User {
private String name;
private int age;
}
📌 Теперь можно создавать объекты так:
User user = User.builder().name("Иван").age(25).build();
🔹 @Value – Неперезаписываемые (иммутабельные) объекты. Это как @Data, но с final полями и без сеттеров.
@Value
public class User {
String name;
int age;
}
📌 Отлично подходит для DTO!
🔹 @Slf4j – Логирование без бойлерплейта.
@Slf4j
public class App {
public static void main(String[] args) {
log.info("Привет, мир!");
}
}
📌 Не нужно вручную объявлять Logger — Lombok всё сделает за вас.
🔹 @SneakyThrows – Скрывает checked исключения (но осторожно! 😬).
@SneakyThrows
public void readFile(String path) {
Files.readAllLines(Path.of(path));
}
📌 Работает так, как будто исключений нет, но лучше использовать осознанно!
👉 Используете Lombok в проектах? Какая аннотация вам больше всего нравится? Делитесь в комментариях! 💬
📲 Мы в MAX
👉@BookJava
// Базовый интерфейс
interface Notifier {
void send(String message);
}
// Основная реализация
class EmailNotifier implements Notifier {
@Override
public void send(String message) {
System.out.println("Отправка email: " + message);
}
}
// Базовый декоратор
class NotifierDecorator implements Notifier {
protected Notifier notifier;
public NotifierDecorator(Notifier notifier) {
this.notifier = notifier;
}
@Override
public void send(String message) {
notifier.send(message);
}
}
// Декоратор для SMS
class SMSNotifier extends NotifierDecorator {
public SMSNotifier(Notifier notifier) {
super(notifier);
}
@Override
public void send(String message) {
super.send(message);
System.out.println("Отправка SMS: " + message);
}
}
// Декоратор для Push-уведомлений
class PushNotifier extends NotifierDecorator {
public PushNotifier(Notifier notifier) {
super(notifier);
}
@Override
public void send(String message) {
super.send(message);
System.out.println("Отправка Push-уведомления: " + message);
}
}
// Использование
public class Main {
public static void main(String[] args) {
Notifier notifier = new EmailNotifier();
notifier = new SMSNotifier(notifier);
notifier = new PushNotifier(notifier);
notifier.send("Важное сообщение!");
}
}
🔥 Выход в консоль:
Отправка email: Важное сообщение! Отправка SMS: Важное сообщение! Отправка Push-уведомления: Важное сообщение!✅ Преимущества: ✔️ Гибкость: можно комбинировать декораторы в любом порядке ✔️ Принцип открытости/закрытости (OCP) — код легко расширяется ✔️ Разделение обязанностей — каждая часть отвечает за свою функцию 📲 Мы в MAX 👉@BookJava
java.time всё стало проще. Самый удобный способ получить timestamp:
Instant instant = Instant.now();
long timestamp = instant.toEpochMilli(); // В миллисекундах
Значение timestamp соответствует количеству миллисекунд, прошедших с 1 января 1970 года (UTC).
2. Преобразование timestamp в дату и время
Допустим, у нас есть временная метка, и нам нужно преобразовать её в локальное время:
long timestamp = 1700000000000L; // Пример временной метки
Instant instant = Instant.ofEpochMilli(timestamp);
ZonedDateTime dateTime = instant.atZone(ZoneId.systemDefault());
System.out.println(dateTime);
Так можно легко получить читабельную дату.
3. Разница между датами
Вычислить разницу между двумя временными метками можно так:
Instant start = Instant.now();
Thread.sleep(2000); // Эмуляция задержки
Instant end = Instant.now();
Duration duration = Duration.between(start, end);
System.out.println("Разница в секундах: " + duration.getSeconds());
Отличный способ измерять производительность кода!
4. Форматирование и вывод даты
Для вывода даты в удобочитаемом формате используем DateTimeFormatter:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss");
String formatted = dateTime.format(formatter);
System.out.println(formatted);
Итог
Работа с временными метками в Java теперь проще, чем когда-либо. Используйте Instant, Duration и DateTimeFormatter для удобного управления временем.
📲 Мы в MAX
👉@BookJava@Hibernate можно использовать только для отношений, но не для простых (базовых) атрибутов.
Чтобы она работала и для полей, необходимо использовать байткод-энхансмент через плагин. В этом случае поля, отмеченные как lazy, будут загружаться при первом обращении к ним.
#Java #JPA
📲 Мы в MAX
👉@BookJavatoString(), equals(), hashCode(). Больше не нужно писать однотипный код вручную!
🔹 Guava – коллекции, кэширование, строки, примитивные типы, функциональные утилиты и многое другое. Разработана Google, широко используется в индустрии.
🔹 Apache Commons – набор утилит для работы со строками, коллекциями, потоками, датами. Позволяет сократить код и улучшить его читаемость.
🔹 Jackson – одна из лучших библиотек для работы с JSON. Позволяет сериализовать и десериализовать Java-объекты быстро и без лишнего кода.
🔹 Junit + Mockito – тестирование в Java. JUnit – основной инструмент для написания юнит-тестов, а Mockito помогает мокировать зависимости и тестировать сложные сценарии.
📲 Мы в MAX
👉@BookJava
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
Здесь используется жадная инициализация – объект создаётся сразу при загрузке класса.
💣 Проблемы Singleton
1️⃣ Нарушение SRP (Single Responsibility Principle) – Singleton управляет своим жизненным циклом.
2️⃣ Проблемы с тестированием – сложность мокирования в юнит-тестах.
3️⃣ Глобальное состояние – сложнее поддерживать код, возможны неожиданные баги.
✅ Когда использовать Singleton?
✔ Если требуется единый точный экземпляр (например, пул соединений, логгер).
✔ Если объект дорого создавать и его состояние неизменно.
✔ Когда глобальная точка доступа действительно оправдана.
🔧 Альтернативы
👉 Dependency Injection (DI) – лучше передавать объект через конструктор.
👉 Enum Singleton – лучший способ создать потокобезопасный Singleton:
public enum SingletonEnum {
INSTANCE;
public void someMethod() {
System.out.println("Работаем!");
}
}
Он защищён от сериализации и reflection-атак! 🚀
📲 Мы в MAX
👉@BookJavavar в Java: Когда использовать, а когда нет?
Сегодня разберёмся с var в Java. Этот локальный тип вывода переменной появился в Java 10 и сразу вызвал много споров. Давайте посмотрим, когда его стоит использовать, а когда лучше отказаться.
✅ Когда var полезен?
1️⃣ Сокращение шаблонного кода
var list = new ArrayList<String>(); // читается проще
2️⃣ Улучшает читаемость при длинных объявлениях
var map = new HashMap<String, List<Integer>>();
3️⃣ Хорош при использовании анонимных классов
var thread = new Thread(() -> System.out.println("Hello"));
4️⃣ Идеален для итераторов
for (var entry : map.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
❌ Когда var ухудшает код?
1️⃣ Неочевидный тип данных
var data = fetchData(); // Что вернет метод? Интуитивно непонятно!
2️⃣ Снижение читаемости сложного кода
var something = doSomethingComplicated(); // А что это такое?
3️⃣ Не подходит для публичных API
Если метод возвращает var, мы теряем контракт с пользователем API.
🔥 Итог
Используйте var, когда тип очевиден и код становится чище. Не злоупотребляйте им, чтобы не терять читаемость!
📌26 рекомендаций по использованию типа var в Java
https://habr.com/ru/articles/438206/
https://dzone.com/articles/var-work-in-progress
📲 Мы в MAX
👉@BookJava