
- Главная
- Каталог
- Интернет технологии
- Java | Фишки и трюки
Java | Фишки и трюки
Аудитория канала - начинающие или опытные Java программисты. Канал о разработке приложений на Java, в том числе написание бэкенд и web-приложений. Рассматриваются фишки и трюки при программировании на Java.
Статистика канала
В этом видео автор подробно разбирает, что такое интерфейсы в Java и чем они похожи на абстрактные классы. Вы узнаете об их ключевых отличиях, научитесь применять интерфейсы на практике и поймёте, в каких задачах они становятся незаменимым инструментом для создания гибкой и понятной архитектуры кода.
LocalDate и DateTimeFormatter: вечная путаница с YYYY и yyyy
Каждый Новый год эта ошибка просыпается и незаметно портит данные в логах, отчётах и экспортах. Разница между YYYY и yyyy - всего одна буква, но она может сдвинуть дату на целый год вперёд или назад в первую неделю января.
Вот как не попасть в эту ловушку и почему это происходит
DateTimeFormatter wrongFormatter = DateTimeFormatter.ofPattern("dd.MM.YYYY");
DateTimeFormatter correctFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
LocalDate date = LocalDate.of(2024, 12, 31);
System.out.println("Неправильно (YYYY): " + date.format(wrongFormatter));
// 31.12.2025 ← вот он, сдвиг на год!
System.out.println("Правильно (yyyy): " + date.format(correctFormatter));
// 31.12.2024{}
YYYY используется вместе с номером недели (ww) и днём недели (E). Он нужен для отображения года, к которому относится неделя, а не календарная дата.
YYYY) — это год, к которому относится эта неделя.
// Пример: 1 января 2025 года — это среда
LocalDate jan1 = LocalDate.of(2025, 1, 1);
System.out.println("Год недели: " + jan1.format(DateTimeFormatter.ofPattern("YYYY")));
// 2025 — потому что неделя (30 дек - 5 янв) содержит первый четверг 2025 года (2 января)
// А 30 декабря 2024 года — это понедельник, начало недели 1 (2025 года!)
LocalDate dec30 = LocalDate.of(2024, 12, 30);
System.out.println("Год недели: " + dec30.format(DateTimeFormatter.ofPattern("YYYY")));
// 2025 — потому что эта неделя (30 дек - 5 янв) содержит первый четверг 2025 года{}
YYYY и yyyy чаще всего расходятся.
// Для отображения номера недели и года недели (отчёты, планирование)
DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern("'Неделя' ww, YYYY");
LocalDate date = LocalDate.of(2024, 12, 30);
System.out.println(date.format(weekFormatter));
// "Неделя 01, 2025" ← это правильно для систем, работающих по неделям{}
YYYY только если ты точно понимаешь, что такое год недели, и используешь его с ww (номер недели).
// ❌ Опасный парсинг (может сломаться)
String wrong = "31.12.2024";
LocalDate parsed = LocalDate.parse(wrong, DateTimeFormatter.ofPattern("dd.MM.YYYY"));
// Может выкинуть исключение или спарсить не ту дату{}
DateTimeFormatter.ISO_LOCAL_DATE; // yyyy-MM-dd
DateTimeFormatter.BASIC_ISO_DATE; // yyyyMMdd
{}
2. Пиши тесты на граничные даты:
@Test
void dateFormatting_aroundNewYear() {
LocalDate dec30 = LocalDate.of(2024, 12, 30);
LocalDate jan1 = LocalDate.of(2025, 1, 1);
assertThat(dec30.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")))
.isEqualTo("30/12/2024");
assertThat(jan1.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")))
.isEqualTo("01/01/2025");
}
{}
3. Включи в code review проверку всех DateTimeFormatter на наличие YYYY.
YYYY - это не опечатка, а отдельная концепция. Используй yyyy для всего, что связано с календарными датами. А YYYY оставь для отчётов по неделям.
import java.lang.reflect.Method;
public class Calculator {
private int superSecretFormula(int a, int b) {
return (a + b) * (a - b);
}
}
// В тесте:
Method method = Calculator.class.getDeclaredMethod("superSecretFormula", int.class, int.class);
method.setAccessible(true); // Взламываем приватность
int result = (int) method.invoke(new Calculator(), 5, 3);{}
1. Выполняет несколько задач (нарушает SRP). 2. Содержит логику, которая может пригодиться где-то ещё. 3. Слишком умный для своего класса.
public class ReportService {
public String generateReport() {
// ... подготовка данных
String cleaned = cleanData(rawData); // приватный метод
// ... формирование отчёта
}
private String cleanData(String data) {
// сложная логика очистки
}
}{}
// Новая публичная единица, которую легко тестировать
public class DataCleaner {
public String clean(String data) {
// та же логика, но теперь она публичная
}
}
// В ReportService:
public class ReportService {
private final DataCleaner cleaner;
public String generateReport() {
String cleaned = cleaner.clean(rawData);
// ...
}
}{}
DataCleaner можно и нужно тестировать напрямую. Это чистая архитектура.
// Было: private void helper() { ... }
// Стало (в том же пакете):
class Service {
void helper() { ... } // без модификатора = виден в пакете
}
// В тестах (которые лежат в том же test/java/... пакете):
@Test
void testHelper() {
Service service = new Service();
service.helper(); // Доступно!
}{}
@Test
void generateReport_usesCleanDataLogic() {
ReportService service = new ReportService();
String report = service.generateReport();
assertThat(report).contains("очищенные данные");
}{}
@SneakyThrows в Lombok: как она обманывает компилятор
Когда видишь @SneakyThrows, кажется, что нашёл волшебную палочку: checked-исключения больше не нужно объявлять в throws и ловить в try-catch. Но эта магия — не настоящее волшебство, а тонкая иллюзия, которая может сломать твой код в самый неподходящий момент.
Давай заглянем под капот и узнаем, как эта аннотация обманывает компилятор, и почему с ней нужно быть осторожным
// Без Lombok: нужно либо пробросить, либо поймать
public void readFile() throws IOException { // Объявляем throws
Files.readAllBytes(Paths.get("file.txt"));
}
// Или так:
public void readFile() {
try {
Files.readAllBytes(Paths.get("file.txt"));
} catch (IOException e) { // Ловим исключение
throw new RuntimeException(e);
}
}{}
import lombok.SneakyThrows;
public class FileReader {
@SneakyThrows
public byte[] readFile() {
return Files.readAllBytes(Paths.get("file.txt"));
}
}{}
throws, никакого try-catch! Код компилируется, и ты можешь вызывать метод, как будто исключений не существует. Но они никуда не делись.
public byte[] readFile() {
try {
return Files.readAllBytes(Paths.get("file.txt"));
} catch (IOException e) {
throw Lombok.sneakyThrow(e); // Вот этот метод — ключ!
}
}
// А метод sneakyThrow делает вот что:
public static RuntimeException sneakyThrow(Throwable t) {
throw Lombok.<RuntimeException>sneakyThrow0(t);
}
@SuppressWarnings("unchecked")
private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {
throw (T) t; // Кастование к unchecked-исключению!
}{}
@SneakyThrows
public void connect() {
Socket socket = new Socket("host", 9999); // Может кинуть IOException
// ... работа с сокетом
}
// Где-то в другом месте:
public void init() {
connect(); // Код не знает, что здесь возможен IOException!
// И поэтому не готов его обработать
}{}
// Попробуем использовать в лямбде (Consumer)
list.forEach(element -> {
@SneakyThrows
Thread.sleep(100); // Так не сработает!
});
// Нужно отдельно выносить:
list.forEach(this::sneakySleep);
@SneakyThrows
private void sneakySleep(Object element) {
Thread.sleep(100);
}{}
@SneakyThrows не работает прямо на лямбдах. Это ограничивает его применение.
Runnable).
3. Для избежания излишнего обертывания в RuntimeException, когда ты точно уверен в поведении метода.
// Пример с Runnable
public class Worker implements Runnable {
@SneakyThrows
@Override
public void run() {
Files.readAllBytes(Paths.get("config.json")); // IOException будет проброшен как unchecked
}
}{}
@SneakyThrows - это не решение, а побег из тюрьмы checked-исключений через подкоп.Отзывы канала
всего 11 отзывов
- Добавлен: Сначала новые
- Добавлен: Сначала старые
- Оценка: По убыванию
- Оценка: По возрастанию
Каталог Телеграм-каналов для нативных размещений
Java | Фишки и трюки — это Telegam канал в категории «Интернет технологии», который предлагает эффективные форматы для размещения рекламных постов в Телеграмме. Количество подписчиков канала в 7.0K и качественный контент помогают брендам привлекать внимание аудитории и увеличивать охват. Рейтинг канала составляет 19.5, количество отзывов – 11, со средней оценкой 5.0.
Вы можете запустить рекламную кампанию через сервис Telega.in, выбрав удобный формат размещения. Платформа обеспечивает прозрачные условия сотрудничества и предоставляет детальную аналитику. Стоимость размещения составляет 2237.76 ₽, а за 86 выполненных заявок канал зарекомендовал себя как надежный партнер для рекламы в TG. Размещайте интеграции уже сегодня и привлекайте новых клиентов вместе с Telega.in!
Вы снова сможете добавить каналы в корзину из каталога
Комментарий