🚀 В Spring Boot можно точечно отключать ненужную автоконфигурацию через аннотацию
**@SpringBootApplication(exclude = …)**.
Это удобно, когда в проекте есть своя кастомная конфигурация, которая конфликтует с дефолтной, или когда вы хотите убрать лишние автоматические настройки и контролировать поведение вручную.
Так вы оставляете только нужные части автоконфигурации и избегаете скрытых конфликтов.
#SpringBoot #JavaDev
**@SpringBootApplication(exclude = …)**.
Это удобно, когда в проекте есть своя кастомная конфигурация, которая конфликтует с дефолтной, или когда вы хотите убрать лишние автоматические настройки и контролировать поведение вручную.
Так вы оставляете только нужные части автоконфигурации и избегаете скрытых конфликтов.
#SpringBoot #JavaDev
👍7
💡 Java tip: если вы делаете кеш, где ключи должны автоматически удаляться, когда на них больше нет ссылок в программе, используйте WeakHashMap.
Это удобный способ создавать "самоочищающийся" кеш: как только ключ становится недостижимым, GC выбрасывает его, и запись исчезает из карты.
#Java #JavaDev
@javatg
Это удобный способ создавать "самоочищающийся" кеш: как только ключ становится недостижимым, GC выбрасывает его, и запись исчезает из карты.
#Java #JavaDev
@javatg
👍14🔥4❤2
⚡️ Совет по Spring Boot
💡 Если нужно написать интеграционные тесты для Spring MVC-контроллеров и замокать всё остальное — используй @WebMvcTest.
Эта аннотация поднимает только MVC-слой (контроллеры, маппинг, валидацию), не загружая весь контекст приложения.
Это делает тесты быстрее, чище и проще.
#SpringBoot #JavaDev
💡 Если нужно написать интеграционные тесты для Spring MVC-контроллеров и замокать всё остальное — используй @WebMvcTest.
Эта аннотация поднимает только MVC-слой (контроллеры, маппинг, валидацию), не загружая весь контекст приложения.
Это делает тесты быстрее, чище и проще.
#SpringBoot #JavaDev
❤7👍4🔥4
💡 Java-совет: всегда используй @Override
Аннотация
Ты думаешь, что переопределил метод родительского класса, но из-за опечатки или неверной сигнатуры создаёшь новый метод, и Java молча это принимает.
Пример ошибки
Метод
Решение
Используй
Что это даёт
- Компилятор проверяет, что метод реально переопределяет родительский
- Опечатки и неверные сигнатуры ловятся сразу
- Код становится безопаснее и понятнее
- IDE лучше подсказывает и рефакторит
Правило
Если метод должен переопределять родительский —
Маленькая аннотация - большая экономия времени на дебаге.
#Java #JavaDev
@javatg
Аннотация
@Override помогает ловить ошибки на этапе компиляции, а не в рантайме.Ты думаешь, что переопределил метод родительского класса, но из-за опечатки или неверной сигнатуры создаёшь новый метод, и Java молча это принимает.
Пример ошибки
Метод
print() в родителе, а в наследнике случайно написано prnt() — код скомпилируется, но логика сломается.Решение
Используй
Override.Что это даёт
- Компилятор проверяет, что метод реально переопределяет родительский
- Опечатки и неверные сигнатуры ловятся сразу
- Код становится безопаснее и понятнее
- IDE лучше подсказывает и рефакторит
Правило
Если метод должен переопределять родительский —
@Override обязателен. Всегда.Маленькая аннотация - большая экономия времени на дебаге.
#Java #JavaDev
@javatg
❤11👍7🔥2🥰1
💡 SOLID: принцип подстановки Лисков (LSP) говорит:
🔁 объекты базового класса должны без проблем заменяться объектами его подклассов.
Если подкласс меняет поведение так, что код начинает ломаться — дизайн неправильный.
❌ Плохой пример
У нас есть Vehicle с методом startEngine().
Мы наследуем Bicycle, но… у велосипеда нет двигателя — и метод бросает исключение.
Такая иерархия:
Теперь любой тест, ожидающий, что любой Vehicle умеет завести двигатель, падает.
👉 Подкласс ведёт себя не так, как базовый — LSP нарушен.
✅ Как исправить
Разделяем ответственность на интерфейсы:
Теперь только те объекты, которым по смыслу нужен двигатель, реализуют Motorized.
🧠 Вывод
✔ Подклассы не должны ломать ожидания, заложенные в базовый класс.
✔ Лучше разделить поведение, чем «затыкать» методы исключениями.
✔ LSP делает код предсказуемым и безопасным для расширения.
#Java #JavaDev #SOLID #CleanCode
🔁 объекты базового класса должны без проблем заменяться объектами его подклассов.
Если подкласс меняет поведение так, что код начинает ломаться — дизайн неправильный.
❌ Плохой пример
У нас есть Vehicle с методом startEngine().
Мы наследуем Bicycle, но… у велосипеда нет двигателя — и метод бросает исключение.
Такая иерархия:
class Vehicle {
public void startEngine() { ... }
}
class Bicycle extends Vehicle {
@Override
public void startEngine() {
throw new UnsupportedOperationException("Bicycles don't have engines!");
}
}
Теперь любой тест, ожидающий, что любой Vehicle умеет завести двигатель, падает.
👉 Подкласс ведёт себя не так, как базовый — LSP нарушен.
✅ Как исправить
Разделяем ответственность на интерфейсы:
interface Vehicle {}
interface Motorized {
void startEngine();
}
class Car implements Vehicle, Motorized {
public void startEngine() { ... }
}
class Bicycle implements Vehicle {
// без двигателя — всё ок
}
Теперь только те объекты, которым по смыслу нужен двигатель, реализуют Motorized.
🧠 Вывод
✔ Подклассы не должны ломать ожидания, заложенные в базовый класс.
✔ Лучше разделить поведение, чем «затыкать» методы исключениями.
✔ LSP делает код предсказуемым и безопасным для расширения.
#Java #JavaDev #SOLID #CleanCode
❤13👍12🔥3
🚀 Spring Boot: хочешь, чтобы Jackson создавал объекты из JSON явно и предсказуемо - используй
Почему это важно:
🟢 Jackson не “угадывает”, какой конструктор использовать
🟢 Каждый параметр жёстко привязан к полю JSON через
🟢 Меньше магии - меньше багов при рефакторинге
Идеально для immutable-классов (`final` поля) и DTO.
@javatg
#SpringBoot #JavaDev
@JsonCreator.Почему это важно:
🟢 Jackson не “угадывает”, какой конструктор использовать
🟢 Каждый параметр жёстко привязан к полю JSON через
@JsonProperty 🟢 Меньше магии - меньше багов при рефакторинге
Идеально для immutable-классов (`final` поля) и DTO.
@javatg
#SpringBoot #JavaDev
👍14❤4🥰1
🚀 Spring совет: таймауты RestTemplate лучше настраивать централизованно
Если в проекте много REST-запросов через
✅ Правильнее сделать конфигурацию через
- один общий
- плюс отдельные клиенты под “медленные” сервисы (через `@Qualifier`)
Так у тебя:
- единая точка настройки
- меньше багов в проде из-за “вечных” запросов
- проще дебажить и менять параметры
💡 Особенно полезно в микросервисах, где внешние сервисы могут подвисать.
#SpringBoot #JavaDev
Если в проекте много REST-запросов через
RestTemplate, не разбрасывай таймауты по коду.✅ Правильнее сделать конфигурацию через
RestTemplateBuilder:- один общий
RestTemplate с дефолтными timeout- плюс отдельные клиенты под “медленные” сервисы (через `@Qualifier`)
Так у тебя:
- единая точка настройки
- меньше багов в проде из-за “вечных” запросов
- проще дебажить и менять параметры
💡 Особенно полезно в микросервисах, где внешние сервисы могут подвисать.
#SpringBoot #JavaDev
👍14❤1🔥1😱1🤬1
💡 Java совет: используй `Instant` и `Duration` для точных вычислений времени
Работа со временем через
В современном Java для точных измерений есть java.time API.
🔹
Поддерживает точность до наносекунд.
// твоя логика
Instant end = Instant.now();
Duration elapsed = Duration.between(start, end);
📌 Почему это важно:
• Наноcекундная точность
• Читаемый и современный API
• Меньше багов, связанных с таймзонами и устаревшими классами
Используй правильные инструменты — и время в коде перестанет быть источником боли.
#Java #JavaDev #Backend #CleanCode
Работа со временем через
System.currentTimeMillis() — это прошлый век. В современном Java для точных измерений есть java.time API.
🔹
Instant - это конкретная точка времени в UTC Поддерживает точность до наносекунд.
Instant now = Instant.now();
🔹 Duration - это разница между двумя моментами времени
Идеально подходит для измерения времени выполнения кода.
Instant start = Instant.now();
// твоя логика
Instant end = Instant.now();
Duration elapsed = Duration.between(start, end);
📌 Почему это важно:
• Наноcекундная точность
• Читаемый и современный API
• Меньше багов, связанных с таймзонами и устаревшими классами
Используй правильные инструменты — и время в коде перестанет быть источником боли.
#Java #JavaDev #Backend #CleanCode
👍9😁3❤1🔥1
💡 Java совет: считаем разницу во времени без ручной математики
Начиная с Java 8 можно использовать
Вместо того чтобы самому высчитывать миллисекунды и делить их на 1000×60×60, просто используйте API из
Пример:
Так же можно считать:
Чисто, читаемо и без ошибок из-за ручных расчётов времени.
#Java #JavaDev
@javatg
Начиная с Java 8 можно использовать
ChronoUnit.between(start, end), чтобы посчитать интервал между датами или временем в нужных единицах — дни, часы, минуты и т.д.Вместо того чтобы самому высчитывать миллисекунды и делить их на 1000×60×60, просто используйте API из
java.time.Пример:
import java.time.*;
import java.time.temporal.ChronoUnit;
public class Demo {
public static void main(String[] args) {
LocalDate d1 = LocalDate.of(2023, 1, 1);
LocalDate d2 = LocalDate.of(2023, 1, 10);
long days = ChronoUnit.DAYS.between(d1, d2);
System.out.println(days); // 9
}
}
Так же можно считать:
ChronoUnit.HOURS.between(...)
ChronoUnit.MINUTES.between(...)
ChronoUnit.MONTHS.between(...)
Чисто, читаемо и без ошибок из-за ручных расчётов времени.
#Java #JavaDev
@javatg
👍15❤1🥰1🤔1
💡 Совет по Java: Начиная с Java 12 можно использовать String.indent(n) для форматирования многострочных строк с отступами.
Метод работает очень просто:
n > 0 - добавляет n пробелов в начало КАЖДОЙ строки
n < 0 - удаляет до n пробелов в начале каждой строки
n = 0 - нормализует переводы строк
Пример:
Полезно, когда:
- генерируешь код или конфиги
- формируешь многострочные логи
- работаешь с шаблонами текста
- хочешь аккуратно выровнять вывод без костылей
Мелочь, но делает код чище и избавляет от ручной работы со строками.
#Java #JavaDev
@javatg
Метод работает очень просто:
n > 0 - добавляет n пробелов в начало КАЖДОЙ строки
n < 0 - удаляет до n пробелов в начале каждой строки
n = 0 - нормализует переводы строк
Пример:
String text = "Text\ncontent";
System.out.println(text.indent(4));
System.out.println(text.indent(-2));
Полезно, когда:
- генерируешь код или конфиги
- формируешь многострочные логи
- работаешь с шаблонами текста
- хочешь аккуратно выровнять вывод без костылей
Мелочь, но делает код чище и избавляет от ручной работы со строками.
#Java #JavaDev
@javatg
👍8❤1🔥1
🚀 Java 26 стала умнее — особенно в pattern matching
Теперь работа с pattern matching выражениями стала заметно стабильнее и предсказуемее
Что улучшили:
🟢 Более надёжный type inference
компилятор лучше понимает типы в сложных условиях
🟢 Меньше edge-case ошибок
меньше неожиданных падений и предупреждений
🟢 Консистентное поведение
одинаковая логика в if и switch
Что это даёт на практике:
раньше при усложнении условий
компилятор мог “теряться”
теперь:
- анализ потока стал умнее
- переменные из pattern matching корректно распознаются
- код становится чище и безопаснее
Java становится всё ближе к современным языкам
с удобным и предсказуемым контролем типов
#Java #JavaDev
⚡️ Полезные ресурсы по Java 🚀 Max
@javatg
Теперь работа с pattern matching выражениями стала заметно стабильнее и предсказуемее
Что улучшили:
🟢 Более надёжный type inference
компилятор лучше понимает типы в сложных условиях
🟢 Меньше edge-case ошибок
меньше неожиданных падений и предупреждений
🟢 Консистентное поведение
одинаковая логика в if и switch
Что это даёт на практике:
раньше при усложнении условий
компилятор мог “теряться”
теперь:
- анализ потока стал умнее
- переменные из pattern matching корректно распознаются
- код становится чище и безопаснее
Java становится всё ближе к современным языкам
с удобным и предсказуемым контролем типов
#Java #JavaDev
⚡️ Полезные ресурсы по Java 🚀 Max
@javatg
👍9❤7🔥3
☕ Java совет: сравнение времени без ловушек точности
Иногда при сравнении времени в Java проверки равенства могут неожиданно падать, потому что значения отличаются на миллисекунды или наносекунды.
Например:
Если сравнивать напрямую, они разные.
Но если вам важна точность до минуты, это можно легко исправить.
Используйте Instant.truncatedTo():
Метод truncatedTo() обрезает время до нужной точности:
• ChronoUnit.MINUTES
• ChronoUnit.HOURS
• ChronoUnit.DAYS
Это помогает избежать проблем, когда значения отличаются только в миллисекундах или наносекундах.
Полезно для:
• логов
• временных окон
• аналитики
• дедупликации событий
Маленький приём —
но часто спасает от неочевидных багов в time-логике.
#Java #JavaDev #Backend #Programming
Иногда при сравнении времени в Java проверки равенства могут неожиданно падать, потому что значения отличаются на миллисекунды или наносекунды.
Например:
Instant a = Instant.parse("2025-10-01T10:42:11Z");
Instant b = Instant.parse("2025-10-01T10:42:44Z");
Если сравнивать напрямую, они разные.
Но если вам важна точность до минуты, это можно легко исправить.
Используйте Instant.truncatedTo():
boolean sameMinute =
a.truncatedTo(ChronoUnit.MINUTES)
.equals(b.truncatedTo(ChronoUnit.MINUTES));
System.out.println(sameMinute); // true
Метод truncatedTo() обрезает время до нужной точности:
• ChronoUnit.MINUTES
• ChronoUnit.HOURS
• ChronoUnit.DAYS
Это помогает избежать проблем, когда значения отличаются только в миллисекундах или наносекундах.
Полезно для:
• логов
• временных окон
• аналитики
• дедупликации событий
Маленький приём —
но часто спасает от неочевидных багов в time-логике.
#Java #JavaDev #Backend #Programming
👍13
Если вы используете Hibernate, добавьте:
spring.jpa.hibernate.ddl-auto=validateЧто это даёт:
- Приложение проверяет, совпадает ли схема БД с entity
- Если есть расхождения — сервис не запустится
- Никаких случайных изменений структуры в продакшене
Идеальный сценарий - использовать вместе с Flyway или Liquibase:
spring.jpa.hibernate.ddl-auto=validate
spring.flyway.enabled=true
Что в итоге:
- Все изменения БД — только через migration-скрипты
- Fail fast, если схема и код не совпадают
- Меньше сюрпризов после деплоя
Это один из тех параметров, которые могут спасти продакшен от тихих и очень дорогих ошибок.
#SpringBoot #JavaDev
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15
☕ Java совет: рекурсивный обход файловой системы
В Java есть удобный способ рекурсивно обойти все файлы в директории - метод
Он возвращает Stream<Path>, что позволяет легко фильтровать и обрабатывать файлы через Stream API.
Пример - найти все
Что происходит:
• Files.walk(startPath) - рекурсивно проходит по всем папкам
• filter(Files::isRegularFile) - оставляет только файлы
• endsWith(".java") - фильтр по расширению
• forEach - обработка найденных файлов
Это намного чище, чем писать собственную рекурсивную функцию обхода директорий.
#Java #JavaDev #Programming
⚡️ Полезные ресурсы по Java 🚀 Max
@javatg
В Java есть удобный способ рекурсивно обойти все файлы в директории - метод
Files.walk().Он возвращает Stream<Path>, что позволяет легко фильтровать и обрабатывать файлы через Stream API.
Пример - найти все
.java файлы в папке src:
import java.io.IOException;
import java.nio.file.*;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
Path startPath = Paths.get("src");
try (Stream<Path> paths = Files.walk(startPath)) {
paths
.filter(Files::isRegularFile)
.filter(path -> path.toString().endsWith(".java"))
.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Что происходит:
• Files.walk(startPath) - рекурсивно проходит по всем папкам
• filter(Files::isRegularFile) - оставляет только файлы
• endsWith(".java") - фильтр по расширению
• forEach - обработка найденных файлов
Это намного чище, чем писать собственную рекурсивную функцию обхода директорий.
#Java #JavaDev #Programming
⚡️ Полезные ресурсы по Java 🚀 Max
@javatg
👍6❤2🔥2
🚀 Java: безопасное сравнение без NullPointerException
Как это работает:
• Если оба значения
• Если только одно
• Если оба не
Вместо:
Используй:
Мелочь, которая регулярно спасает от багов в проде.
#Java #JavaDev
Objects.equals(a, b) — простой способ сравнивать значения без риска словить NPE.Как это работает:
• Если оба значения
null → вернёт true • Если только одно
null → вернёт false • Если оба не
null → вызовет a.equals(b)Вместо:
a.equals(b) → может упасть с NullPointerExceptionИспользуй:
Objects.equals(a, b) → всегда безопасноМелочь, которая регулярно спасает от багов в проде.
#Java #JavaDev
👍22❤4🔥3
🚀 Java - regex без боли
Нашли интересную библиотеку - Sift. Она заменяет весь этот ад с регулярками на нормальный fluent API.
Теперь вместо нечитаемых строк вида:
^[0-9a-fA-F]{6}$
Пишешь код, который реально понимаешь:
.char('#')
.then()
.exactly(6)
.hexDigits()
📌 Что это дает:
- Читаемый и понятный код
- Меньше ошибок в regex
- Быстрее разработка и поддержка
По сути — это как “переводчик” с языка регулярных выражений на человеческий Java-код.
Если когда-нибудь ломал голову над regex -это прям must-have.
#Java #JavaDev
Нашли интересную библиотеку - Sift. Она заменяет весь этот ад с регулярками на нормальный fluent API.
Теперь вместо нечитаемых строк вида:
^[0-9a-fA-F]{6}$
Пишешь код, который реально понимаешь:
.char('#')
.then()
.exactly(6)
.hexDigits()
📌 Что это дает:
- Читаемый и понятный код
- Меньше ошибок в regex
- Быстрее разработка и поддержка
По сути — это как “переводчик” с языка регулярных выражений на человеческий Java-код.
Если когда-нибудь ломал голову над regex -это прям must-have.
#Java #JavaDev
🔥24👍6❤5😁1
В Spring Boot не стоит бездумно писать что-то вроде:
@ComponentScan("com.mycompany")
На первый взгляд удобно: фреймворк сам просканирует весь пакет и найдет нужные компоненты. Но проблема в том, что он может просканировать слишком много.
Это увеличивает время classpath scanning, замедляет старт приложения и иногда подтягивает классы, которые вообще не должны были становиться Spring-компонентами.
Лучший вариант - полагаться на дефолтное поведение:
@SpringBootApplication
public class MyApplication { }
По умолчанию Spring Boot сканирует только подпакеты того пакета, где лежит MyApplication.
Если нужно явно ограничить область сканирования, указывай конкретные подпакеты:
@ComponentScan({
"com.mycompany.myapp.product",
"com.mycompany.myapp.order"
})
Главная мысль простая: @ComponentScan должен быть точным. Чем шире границы сканирования, тем больше лишней работы делает приложение на старте.
#SpringBoot #JavaDev #Java #Backend
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥4❤2😁1
Java-совет, который кажется мелочью, пока кто-то не сломает вам состояние объекта.
Не возвращайте наружу изменяемые внутренние коллекции.
Плохой вариант:
```java
public List<String> getMembers() {
return members;
}
Так вызывающий код получает прямой доступ к вашему внутреннему списку. После этого он может сделать:
team.getMembers().clear();
И внезапно вся команда исчезла. Не через метод доменной модели, не через проверку прав, не через бизнес-логику, а просто потому что геттер отдал наружу ссылку на mutable state.
Нормальный вариант:
public List<String> getMembers() {
return Collections.unmodifiableList(members);
}
Или, если нужен безопасный снимок:
public List<String> getMembers() {
return List.copyOf(members);
}
Разница важная:
*
unmodifiableList даёт read-only view поверх текущей коллекции*
List.copyOf создаёт неизменяемую копию на момент вызоваЭто защищает инварианты объекта и оставляет вам свободу менять внутреннюю реализацию. Сегодня внутри может быть
ArrayList, завтра Set, послезавтра вообще другая структура. Внешний код не должен зависеть от того, как именно вы храните данные внутри.Это граница инкапсуляции. Если отдали mutable-ссылку наружу, объект уже не полностью контролирует своё состояние.
#java #javadev
❤9👍8🔥5