Библиотека Java разработчика
📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate. По всем вопросам @evgenycarter РКН clck.ru/3KoGeP
Show more📈 Analytical overview of Telegram channel Библиотека Java разработчика
Channel Библиотека Java разработчика (@bookjava) in the Russian language segment is an active participant. Currently, the community unites 10 280 subscribers, ranking 12 030 in the Technologies & Applications category and 63 913 in the Russia region.
📊 Audience metrics and dynamics
Since its creation on невідомо, the project has demonstrated rapid growth, gathering an audience of 10 280 subscribers.
According to the latest data from 05 June, 2026, the channel demonstrates stable activity. Although there has been a change in the number of participants by 20 over the last 30 days and by 0 over the last 24 hours, overall reach remains high.
- Verification status: Not verified
- Engagement rate (ER): The average audience engagement rate is 8.29%. Within the first 24 hours after publication, content typically collects 3.77% reactions from the total number of subscribers.
- Post reach: On average, each post receives 852 views. Within the first day, a publication typically gains 388 views.
- Reactions and interaction: The audience actively supports content: the average number of reactions per post is 6.
- Thematic interests: Content is focused on key topics such as string, интерфейс, строка, boot, api.
📝 Description and content policy
The author describes the resource as a platform for expressing subjective opinions:
“📚 Лайфхаки, приёмы и лучшие практики для Java-разработчиков. Всё, что ускорит код и прокачает навыки. Java, Spring, Maven, Hibernate.
По всем вопросам @evgenycarter
РКН clck.ru/3KoGeP”
Thanks to the high frequency of updates (latest data received on 07 June, 2026), the channel maintains relevance and a high level of publication reach. Analytics show that the audience actively interacts with content, making it an important point of influence in the Technologies & Applications category.
record лучше class в Java?
В Java 14 появился record – новый тип классов, предназначенный для удобного хранения данных. Чем он лучше обычного class? Давайте разберёмся!
🔹 Запись против класса
Обычный класс:
class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
Много бойлерплейта…
Теперь то же самое с record:
record Person(String name, int age) {}
✅ Меньше кода
✅ Автоматически генерируются toString(), equals(), hashCode()
✅ Иммутабельность по умолчанию
⚠️ Когда НЕ стоит использовать record?
- Если нужен изменяемый объект
- Если требуется сложная бизнес-логика внутри класса
Вы уже используете record в своих проектах? Делитесь опытом! 🚀
👉@BookJavaCompletableFuture: Асинхронность в Java без боли
Привет, коллеги! Сегодня поговорим о CompletableFuture, который помогает писать асинхронный код в Java без коллбэков и потерь в читабельности.
📌 1. Почему CompletableFuture?
В Java давно есть Future, но он неудобен:
❌ Нельзя комбинировать несколько задач.
❌ Блокирует поток при вызове .get().
❌ Нет удобных методов для обработки результатов.
👉 CompletableFuture решает все эти проблемы, позволяя комбинировать задачи, обрабатывать ошибки и не блокировать потоки.
📌 2. Базовый пример использования
import java.util.concurrent.CompletableFuture;
public class AsyncExample {
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
sleep(2000);
return "Привет, мир!";
});
future.thenAccept(result -> System.out.println("Результат: " + result));
System.out.println("Этот текст выведется раньше результата!");
sleep(3000); // Чтобы программа не завершилась раньше времени
}
private static void sleep(int ms) {
try { Thread.sleep(ms); } catch (InterruptedException ignored) {}
}
}
🔹 Здесь supplyAsync() выполняет задачу в другом потоке, а thenAccept() позволяет асинхронно обработать результат.
📌 3. Комбинирование нескольких задач
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<String> result = future1.thenCombine(future2, (s1, s2) -> s1 + " " + s2);
System.out.println(result.join()); // Hello World
✅ thenCombine() объединяет результаты двух асинхронных задач.
📌 4. Обработка ошибок (exceptionally)
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (Math.random() > 0.5) {
throw new RuntimeException("Что-то пошло не так!");
}
return "Все хорошо!";
}).exceptionally(ex -> "Ошибка: " + ex.getMessage());
System.out.println(future.join());
✅ Если в supplyAsync() произошла ошибка, она обработается в exceptionally(), и программа не упадёт.
📌 5. Запуск нескольких задач параллельно
CompletableFuture<Void> allTasks = CompletableFuture.allOf(
CompletableFuture.runAsync(() -> sleepAndPrint("Задача 1", 1000)),
CompletableFuture.runAsync(() -> sleepAndPrint("Задача 2", 2000)),
CompletableFuture.runAsync(() -> sleepAndPrint("Задача 3", 1500))
);
allTasks.join(); // Дождёмся завершения всех задач
private static void sleepAndPrint(String msg, int ms) {
try { Thread.sleep(ms); } catch (InterruptedException ignored) {}
System.out.println(msg);
}
✅ allOf() позволяет запустить несколько задач параллельно и дождаться их завершения.
📌 Итог
🔹 CompletableFuture – это мощный инструмент для работы с асинхронностью в Java.
🔹 Позволяет избежать блокировок, обрабатывать ошибки, комбинировать задачи.
🔹 Улучшает читаемость кода по сравнению с Future и ExecutorService.
📢 А как вы используете CompletableFuture в своих проектах? Делитесь в комментариях! 🚀
👉@BookJavaOptional<T> в Java — это мощный инструмент для работы с возможными null значениями, но часто его используют неправильно. Давайте разберём основные ошибки и лучшие практики.
❌ Плохие примеры:
1️⃣ Использование Optional как поля в классе
class User {
Optional<String> name; // ❌ Плохая практика
}
Лучше просто использовать String, а если нужно, то оборачивать значение в Optional при возврате.
2️⃣ Использование isPresent() вместо ifPresent()
if (optionalValue.isPresent()) {
process(optionalValue.get()); // ❌ Неоптимально
}
Лучше так:
optionalValue.ifPresent(this::process); // ✅ Правильный подход
📌 Хороший пример использования:
public Optional<User> findUserById(int id) {
return Optional.ofNullable(userRepository.get(id));
}
💡 Правильное использование Optional помогает избежать NullPointerException и делает код чище.
🔥 А как вы используете Optional? Пишите в комментариях! 🚀
👉@BookJavaConcurrentHashMap лучше подходит для многопоточной работы, чем HashMap, и как он работает внутри.
В отличие от HashMap, который не потокобезопасен и может приводить к бесконечным циклам при одновременной модификации, ConcurrentHashMap использует сегментированную блокировку, что позволяет работать с разными частями карты параллельно без полной блокировки всей структуры.
📌 Основные особенности:
- Делит данные на сегменты (до JDK 8 или использует synchronized и CAS операции (начиная с JDK 8).
- Чтение (get()) не требует блокировки.
- Запись (put()) использует минимально возможные блокировки.
- Нет null ключей и значений (в отличие от HashMap).
Пример использования:
import java.util.concurrent.ConcurrentHashMap;
public class Main {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("Java", 1);
map.put("Python", 2);
map.put("C++", 3);
System.out.println(map.get("Java")); // 1
}
}
А вы часто используете ConcurrentHashMap? Поделитесь в комментариях! 👇
👉@BookJavatry-catch), либо объявили его в сигнатуре метода (с помощью throws). Если этого не сделать, код не скомпилируется.
- Unchecked исключения: Не проверяются на этапе компиляции. Компилятор не требует их обработки или объявления. Обычно они возникают из-за логических ошибок в коде (например, NullPointerException, ArrayIndexOutOfBoundsException).
2. Поведение во время выполнения
- Checked исключения: Эти исключения обычно связаны с внешними факторами (например, проблемы с файловым вводом-выводом, сетевыми соединениями) и могут возникать в ходе нормального выполнения программы. Если такое исключение выбрасывается и не обрабатывается, оно будет передаваться вверх по стеку вызовов, пока не будет перехвачено или программа не завершится.
- Unchecked исключения: Эти исключения часто вызваны ошибками в коде (например, деление на ноль, обращение к null). Если такое исключение выбрасывается и не перехватывается, оно также будет передаваться вверх по стеку вызовов, но, поскольку их не требуется объявлять или обрабатывать, это может привести к неожиданному завершению программы.
3. Наследование
- Checked исключения: Все исключения, которые наследуют Exception (но не RuntimeException), являются проверяемыми.
- Unchecked исключения: Все исключения, которые наследуют RuntimeException или Error, являются непроверяемыми.
4. Примеры
- Checked исключения: IOException, SQLException, ClassNotFoundException.
- Unchecked исключения: NullPointerException, ArrayIndexOutOfBoundsException, ArithmeticException.
5. Обработка во время выполнения
- Checked исключения: Поскольку они проверяются на этапе компиляции, вы обязаны явно их обрабатывать. Это делает код более устойчивым, но может увеличить его объем.
- Unchecked исключения: Поскольку они не проверяются на этапе компиляции, их сложнее отлаживать и обрабатывать, так как они могут быть неочевидными в коде.
6. Производительность
- Нет значительной разницы в производительности между checked и unchecked исключениями во время выполнения. Стоимость выбрасывания и перехвата исключений одинакова для обоих типов.
Итог
- Checked исключения: Контролируются компилятором, должны быть обработаны или объявлены, обычно используются для recoverable (восстанавливаемых) ситуаций.
- Unchecked исключения: Не контролируются компилятором, часто возникают из-за ошибок в коде и могут привести к аварийному завершению программы, если не обработаны.
Оба типа исключений ведут себя схожим образом во время выполнения, но ключевое различие заключается в том, как они контролируются и обрабатываются на этапе разработки.
👉@BookJavaРеклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ruInteger.valueOf(int) помните, что значения в диапазоне от -128 до 127 кэшируются для повышения производительности. За пределами этого диапазона создаются новые объекты.
Размер кэша можно контролировать с помощью опции -XX:AutoBoxCacheMax=<размер>. 🔥
👉@BookJavaРеклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ruYearMonth, получить его первый день, а затем использовать функцию datesUntil(), которая возвращает Stream всех дней до указанной даты.
👉@BookJavaint`, `double`, `char`): передается копия значения. Изменения внутри метода не влияют на оригинальную переменную.
✅ Объекты (экземпляры классов): передается копия ссылки на объект, а не сам объект. Внутри метода можно изменить состояние объекта, но нельзя изменить саму ссылку на него.
📌 Примеры
🔹 Передача примитивов (значение не изменяется)
public class Test {
public static void modifyPrimitive(int num) {
num = 10; // Это изменение локальное
}
public static void main(String[] args) {
int x = 5;
modifyPrimitive(x);
System.out.println(x); // Выведет: 5 (не изменилось)
}
}
🔹 Передача объекта (изменение состояния объекта сохраняется)
class Person {
String name;
}
public class Test {
public static void modifyObject(Person p) {
p.name = "Alice"; // Изменяет состояние объекта
}
public static void main(String[] args) {
Person person = new Person();
person.name = "Bob";
modifyObject(person);
System.out.println(person.name); // Выведет: Alice
}
}
🔹 Переназначение ссылки (не изменяет оригинальный объект)
class Person {
String name;
}
public class Test {
public static void reassignReference(Person p) {
p = new Person(); // Переназначение ссылки (локально)
p.name = "Charlie";
}
public static void main(String[] args) {
Person person = new Person();
person.name = "Bob";
reassignReference(person);
System.out.println(person.name); // Выведет: Bob (не изменилось)
}
}
🔥 Итог
🔹 Java всегда передает данные по значению!
🔹 Примитивы передаются как копии значений.
🔹 Объекты передаются как копии ссылок, но изменения внутри объекта сохраняются.
🔹 Если внутри метода изменить саму ссылку, это не повлияет на оригинальный объект.
👉@BookJavaРеклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.rusorted() становится меньше и читается почти как естественный язык. Кроме того, вы можете использовать статический импорт.
👉@BookJavaCustomizer - велика вероятность, что вы сможете настроить bean, не отказываясь от автоконфигурации.
👉@BookJavaРеклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ruif). Если предсказание верное, процессор выполняет инструкции быстро. Но если предсказание ошибочное, процессор вынужден откатить выполнение и начать заново, что замедляет работу.
- Отсортированные массивы: В отсортированном массиве данные следуют предсказуемым шаблонам. Например, если вы проверяете условие if (array[i] > threshold), результаты будут более последовательными (например, все true после определённого момента). Это помогает предсказателю ветвлений угадывать правильно, уменьшая простои.
- Неотсортированные массивы: В неотсортированном массиве результаты условных проверок более случайны. Это затрудняет работу предсказателя, увеличивая количество ошибок и замедляя выполнение.
🧠 2. Эффективность кэша
Кэш процессора — это быстрая память, которая хранит недавно использованные данные. Доступ к данным из кэша намного быстрее, чем из основной памяти.
- Отсортированные массивы: При обработке отсортированного массива данные читаются последовательно. Это улучшает эффективность кэша, так как процессор может заранее загружать соседние элементы, уменьшая количество промахов кэша.
- Неотсортированные массивы: В неотсортированном массиве доступ к данным менее предсказуем, что приводит к большему количеству промахов кэша и замедлению работы.
🛠 3. Алгоритмические оптимизации
Некоторые алгоритмы специально разработаны для работы с отсортированными данными. Например:
- Бинарный поиск: Работает только с отсортированными массивами и имеет сложность O(log n), что намного быстрее линейного поиска (**O(n)**) в неотсортированном массиве.
- Слияние массивов: Объединение двух отсортированных массивов происходит эффективнее, чем неотсортированных.
🧪 Пример: Предсказание ветвлений в действии
Рассмотрим пример кода:
int sum = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] >= 128) {
sum += array[i];
}
}
- Если массив отсортирован, условие if будет сначала всегда false, а потом всегда true. Это помогает предсказателю работать эффективно.
- Если массив неотсортирован, условие if будет выполняться хаотично, что приведёт к частым ошибкам предсказания и замедлит программу.
⏱ Бенчмаркинг
Вы можете сами проверить разницу в производительности, запустив тесты на отсортированных и неотсортированных массивах. Отсортированный массив будет обрабатываться быстрее благодаря описанным выше причинам.
🎯 Вывод
Основная причина, по которой обработка отсортированного массива быстрее, — это предсказание ветвлений. Отсортированные данные делают выполнение программы более предсказуемым, уменьшая простои процессора. Также важны эффективность кэша и алгоритмические оптимизации.
👉@BookJavaРеклама. ООО «Отус онлайн-образование», ОГРН 1177746618576public:
- Видимость: Доступен из любого другого класса.
- Использование: Когда класс, метод или поле объявлены как public, они доступны из любого класса в любом пакете.
- Пример:
public class MyClass {
public int myField;
public void myMethod() {
// Реализация метода
}
}
Здесь myField и myMethod доступны из любого другого класса.
2. protected:
- Видимость: Доступен внутри того же пакета и для подклассов (даже если они находятся в других пакетах).
- Использование: Полезно, когда нужно разрешить доступ подклассам, но ограничить доступ для несвязанных классов вне пакета.
- Пример:
public class MyClass {
protected int myField;
protected void myMethod() {
// Реализация метода
}
}
Здесь myField и myMethod доступны для любого подкласса MyClass, даже если он находится в другом пакете.
3. package-private (по умолчанию, без модификатора):
- Видимость: Доступен только внутри того же пакета.
- Использование: Если модификатор доступа не указан, класс, метод или поле считаются package-private. Это уровень доступа по умолчанию.
- Пример:
class MyClass {
int myField;
void myMethod() {
// Реализация метода
}
}
Здесь myField и myMethod доступны только для классов внутри того же пакета.
4. private:
- Видимость: Доступен только внутри того же класса.
- Использование: Используется для инкапсуляции внутренних деталей класса, предотвращая доступ извне.
- Пример:
public class MyClass {
private int myField;
private void myMethod() {
// Реализация метода
}
}
Здесь myField и myMethod доступны только внутри MyClass.
📌 Краткая таблица:
| Модификатор доступа | Тот же класс | Тот же пакет | Подклассы | Другие пакеты |
|---------------------|--------------|--------------|-----------|---------------|
| public | Да | Да | Да | Да |
| protected | Да | Да | Да | Нет |
| package-private | Да | Да | Нет | Нет |
| private | Да | Нет | Нет | Нет |
💡Основные моменты:
- Используйте public для API и методов/полей, которые должны быть доступны всем.
- Используйте protected для методов/полей, которые должны быть доступны подклассам, но не всем остальным.
- Используйте package-private для внутренней реализации, которая не должна быть доступна вне пакета.
- Используйте private для инкапсуляции, скрывая детали реализации внутри класса.
👉@BookJavaРеклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ruHashMap и Hashtable в Java?
Если вы работаете с Java, то наверняка сталкивались с HashMap и Hashtable. Оба используются для хранения пар "ключ-значение", но между ними есть важные различия. Давайте разберемся!
1. Синхронизация (Потокобезопасность)
- `Hashtable`:
- Синхронизирован (потокобезопасен). Все его методы синхронизированы, то есть только один поток может работать с ним одновременно.
- Это делает Hashtable безопасным для многопоточных сред, но может снижать производительность в однопоточных сценариях.
- `HashMap`:
- Не синхронизирован (не потокобезопасен). Несколько потоков могут обращаться к нему одновременно, что может привести к проблемам в многопоточных средах.
- Для потокобезопасности можно использовать Collections.synchronizedMap(new HashMap<>()) или ConcurrentHashMap.
2. Null-ключи и Null-значения
- `Hashtable`:
- Не позволяет использовать null в качестве ключа или значения. Попытка добавить null вызовет NullPointerException.
- `HashMap`:
- Разрешает один `null`-ключ и множество `null`-значений.
3. Производительность
- `Hashtable`:
- Медленнее из-за накладных расходов на синхронизацию.
- `HashMap`:
- Быстрее в однопоточных средах, так как не синхронизирован.
4. Наследие
- `Hashtable`:
- Считается устаревшим классом (появился в Java 1.0). Не является частью Java Collections Framework.
- `HashMap`:
- Часть Java Collections Framework (появился в Java 1.2). Более современный и широко используемый.
5. Итерация
- `Hashtable`:
- Использует Enumeration для перебора ключей и значений.
- `HashMap`:
- Использует Iterator, который более гибкий и позволяет удалять элементы во время перебора.
6. Наследование
- `Hashtable`:
- Наследуется от класса Dictionary (абстрактный класс, который сейчас считается устаревшим).
- `HashMap`:
- Наследуется от AbstractMap, который является частью Java Collections Framework.
7. Рекомендации по использованию
- Используйте HashMap, если:
- Работаете в однопоточной среде.
- Нужна высокая производительность.
- Требуется поддержка null-ключей или значений.
- Используйте Hashtable, если:
- Нужна потокобезопасность в многопоточной среде.
- Однако в современной Java ConcurrentHashMap предпочтительнее, так как он обеспечивает лучшую производительность и масштабируемость.
Пример кода
Hashtable:
Hashtable<String, Integer> hashtable = new Hashtable<>();
hashtable.put("one", 1);
hashtable.put("two", 2);
// hashtable.put(null, 3); // Выбросит NullPointerException
System.out.println(hashtable);
HashMap:
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("one", 1);
hashMap.put("two", 2);
hashMap.put(null, 3); // Разрешено
System.out.println(hashMap);
Итоговая таблица
| Особенность | Hashtable | HashMap |
|-------------------------|---------------------------------|-------------------------------|
| Синхронизация | Синхронизирован | Не синхронизирован |
| Null-ключи/значения | Запрещены | Разрешены |
| Производительность | Медленнее | Быстрее |
| Наследие | Устаревший (Java 1.0) | Современный (Java 1.2) |
| Итерация | Enumeration | Iterator |
| Наследование | Наследует Dictionary | Наследует AbstractMap |
💡Совет: В современной разработке на Java HashMap используется чаще. Если нужна потокобезопасность, лучше выбрать ConcurrentHashMap, а не Hashtable.
👉@BookJava
Available now! Telegram Research 2025 — the year's key insights 
