fa
Feedback
Java | Фишки и трюки

Java | Фишки и трюки

رفتن به کانال در Telegram

Java: примеры кода, интересные фишки и полезные трюки Купить рекламу: https://telega.in/c/java_tips_and_tricks ✍️По всем вопросам: @Pascal4eg Менеджер по рекламе: @shmyzna

نمایش بیشتر
6 963
مشترکین
اطلاعاتی وجود ندارد24 ساعت
+537 روز
+1430 روز
آرشیو پست ها
JVM-инженеры, общий сбор: 28 марта Яндекс проведет Я.Субботник по JVM-языкам Это митап для разработчиков, которые работают с
JVM-инженеры, общий сбор: 28 марта Яндекс проведет Я.Субботник по JVM-языкам Это митап для разработчиков, которые работают с языками Java Virtual Machine. Встреча пройдет в московском офисе Яндекса и в онлайн. Будем обсуждать новые подходы, делиться практическим опытом и нетворкать в неформальной обстановке. В программе — доклады про ускорение Java-фреймворков на примере Quarkus, устройство трассирующего профайлера (Qubership Profiler), реальные подводные камни java.time и оптимизация GraphQL API на базе GraphQL Java и Spring Framework. А еще круглые столы, активность от Яндекс Вертикалей и афтерпати. Подать заявку на митап можно здесь.

🕳 NPE без номера строки: расследование анонимного убийства Бывает: приходит исключение, а в stacktrace — только имя класса и метода. Ни номера строки, ни намёка, где именно случился NullPointerException. Код молчит, логи не помогают, а прод падает. Это как найти труп без документов — придётся вызывать детектива. Почему так происходит и как вычислить убийцу — разбираемся 👇 📉 Почему пропадает номер строки? В Java номера строк хранятся в специальном атрибуте LineNumberTable внутри .class-файла. Если при компиляции отключить отладочную информацию (флаг -g:none), атрибут не создаётся. Также строки могут отсутствовать у динамически генерируемых классов — лямбд, прокси, байткод-библиотек.
// Пример с лямбдой (частая причина)
List<String> list = null;
list.stream().forEach(s -> System.out.println(s.length()));
// NPE здесь, но стек покажет lambda$... без строки
➡️ Код скомпилирован, лямбда превращена в анонимный класс — отладочной информации в нём нет. Получаем глухой стек. 🔍 Методы расследования 1. Изучи имя метода в stacktrace Если фрейм называется lambda$process$1, значит, беда в первой или второй лямбде внутри метода process. Посмотри на все лямбды в этом методе и проанализируй, что могло быть null. 2. Логируй входные данные перед подозрительным местом
log.debug("Processing order: order={}, customer={}", order, order.getCustomer());
order.getCustomer().applyDiscount(); // потенциальный NPE
➡️ Если после этого лога NPE повторится, ты увидишь последние успешные значения. 3. Используй `Objects.requireNonNull` для явной проверки
public void process(Order order) {
    Objects.requireNonNull(order, "order must not be null");
    Objects.requireNonNull(order.getCustomer(), "customer must not be null");
    // ...
}
➡️ Такой код кинет NPE с понятным сообщением и, если повезёт, с номером строки. А если нет — хотя бы будет текст. 4. Воспроизведи локально с дебагом Запусти приложение в IDE — скорее всего, локально номера строк появятся, потому что разработчик обычно компилирует с отладкой. Тогда точно определишь место. ⚡️ Профилактика: не доводи до убийств
🟡 Всегда компилируй с отладочной информацией (в Maven это <debug>true</debug>). 🟡 Используй Optional для явного обозначения возможного null. 🟡 Пиши тесты, которые проверяют граничные случаи (null, пустые коллекции). 🟡 Включай логирование ключевых параметров на входе в методы.
🗣️ Запомни: NPE без строки — не тупик, а вызов твоей дедукции. Ищи подсказки в именах методов, логируй входные данные, проверяй null явно.

☕️ Java с нуля. Классы
В этом видео автор продолжает знакомство с классами в Java. Вы узнаете, что классы могут быть не только обычными, но и вложенными, локальными и даже анонимными. Главная задача урока — понять, что класс — это просто шаблон для будущих объектов, и описывать их можно совершенно по-разному в зависимости от задачи.
➡️ Ссылка на первоисточник 🗣️Запомни: не пытайтесь объять необъятное в одном уроке. Сосредоточьтесь на главном — класс — это шаблон, а способы его описания — лишь инструменты для разных ситуаций. 🤩 Java Фишки и трюки || #Видео

⌨️ В чём разница между TreeSet и HashSet? TreeSet и HashSet — это два класса, реализующих интерфейс Set, но они имеют разные внутренние механизмы и свойства. Структура данных ✔️ HashSet использует хеш-таблицу для хранения элементов. Это позволяет быстро добавлять, удалять и искать элементы, не обеспечивая никакого порядка их хранения. ✔️ TreeSet использует красно-черное дерево (Red-Black Tree), что позволяет хранить элементы в отсортированном порядке (естественном порядке элементов или порядке, определённом компаратором). Порядок элементов ✔️ HashSet не гарантирует какого-либо порядка элементов. Порядок может быть случайным, и он не сохраняется при добавлении/удалении элементов. ✔️ TreeSet хранит элементы в отсортированном порядке. Если элементы реализуют интерфейс Comparable, то сортировка будет основана на их естественном порядке (например, для чисел — по возрастанию). Также можно задать пользовательский порядок с помощью объекта Comparator. Скорость операций ✔️ HashSet обеспечивает O(1) для операций добавления, удаления и поиска (в среднем, если хеш-функция работает эффективно и коллизий мало). ✔️ TreeSet обеспечивает O(log n) для операций добавления, удаления и поиска из-за использования сбалансированного дерева. Поддержка дополнительных операций ✔️ HashSet не поддерживает дополнительные методы для работы с диапазонами или порядком элементов. ✔️ TreeSet предоставляет такие методы, как subSet(), headSet(), tailSet(), которые позволяют работать с диапазонами элементов в отсортированном множестве. Null-значения ✔️ HashSet может хранить одно null значение. ✔️ TreeSet не позволяет хранить null значения, так как при добавлении null неясно, как его сравнивать с другими элементами. Когда использовать ✔️ Используйте HashSet, если вам не важен порядок элементов и вам нужна максимальная производительность. ✔️ Используйте TreeSet, если нужно поддерживать элементы в отсортированном порядке. #java #HashSet #TreeSet

⌨️ Суть лямбда-выражений Лямбда-выражения на первый взгляд могут показаться чем-то сложным и загадочным, но на самом деле они просты и интуитивно понятны. Лямбда-выражение — это лаконичный способ описания анонимной функции, которую можно передать в качестве параметра или сохранить в переменной для последующего использования. Если говорить ещё проще, лямбда-выражение — это просто другой способ создания и реализации объекта определённого типа. Рассмотрим это на примере создания нового потока. У класса Thread есть конструктор:

public Thread(Runnable target) {
    ...
}
То есть в конструктор нужно передать объект типа Runnable. До лямбда-выражений мы сделали бы так:

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello World");
    }
}).start();
Здесь мы создаём анонимный класс, реализующий интерфейс Runnable, с определённым методом run. Если использовать лямбда-выражение, тот же код будет выглядеть следующим образом:

Runnable r = () -> System.out.println("Hello World");
new Thread(r).start();
Или проще:

new Thread(() -> System.out.println("Hello World")).start();
Лямбда-выражение заменяет собой анонимный класс, который раньше был бы необходим для реализации Runnable. Лямбда-выражение может использоваться только там, где ожидается реализация функционального интерфейса — интерфейса с единственным абстрактным методом. А интерфейс Runnable именно такой:

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
Функциональный интерфейс должен содержать только один абстрактный метод, чтобы компилятор мог точно определить, какой метод реализует лямбда-выражение. В противном случае возникли бы неоднозначности и ошибки. #java #lambda #Runnable

Бесплатно: 5 дней Python для новичков → 4 мини-проекта 🐍 Телеграм-боты, парсер данных в таблицу и простой сайт. Без математики, только практика. Запись до 15 марта → тут Реклама. ЧОУ ДПО "ОБРАЗОВАТЕЛЬНЫЕ ТЕХНОЛОГИИ "СКИЛБОКС (КОРОБКА НАВЫКОВ)". ИНН 9704088880.

🎯 try-with-resources: закрывать за собой — признак взрослого программиста Все мы знаем, что ресурсы (файлы, сокеты, соединения с БД) нужно закрывать. Но сколько раз ты видел код, где close() забыт, а ресурсы текут? Java 7 придумала try-with-resources, чтобы мы не зависели от человеческой памяти. Но даже в этой конструкции есть нюансы, о которых нужно знать. Вот как правильно закрывать за собой и не оставлять следов 👇 🟢 Шаг 1: Древний способ (как делали пещерные люди)
InputStream input = null;
try {
    input = new FileInputStream("file.txt");
    // читаем данные
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (input != null) {
        try {
            input.close(); // ещё один try-catch внутри finally!
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
➡️ Проблемы: 🟢 Кода больше, чем логики. 🟢 Легко забыть close(). 🟢 Если и в try, и в finally летят исключения — одно подавляется. 🟢 В реальном проекте таких конструкций могут быть сотни. 🟢 Шаг 2: try-with-resources (современный подход)
try (InputStream input = new FileInputStream("file.txt")) {
    // читаем данные
} catch (IOException e) {
    e.printStackTrace();
}
// input автоматически закрыт
➡️ Всё! Ресурс закрывается автоматически, даже если вылетело исключение. Кода в 5 раз меньше, а надёжность — 100%. 🟢 Шаг 3: Не только файлы — любые ресурсы Любой класс, реализующий AutoCloseable (или старый Closeable), можно использовать в try-with-resources:
class DatabaseConnection implements AutoCloseable {
    public void query(String sql) { /* ... */ }
    
    @Override
    public void close() {
        System.out.println("Закрываем соединение с БД");
    }
}

// Использование:
try (DatabaseConnection conn = new DatabaseConnection()) {
    conn.query("SELECT * FROM users");
} // close() вызовется автоматически
➡️ Создавай свои ресурсы, которые нужно закрывать, и просто реализуй AutoCloseable. Всё будет работать как часы. 🟢 Шаг 4: Несколько ресурсов — порядок закрытия
try (
    FileInputStream fis = new FileInputStream("in.txt");
    FileOutputStream fos = new FileOutputStream("out.txt")
) {
    // копирование
}
➡️ Важно: ресурсы закрываются в обратном порядке создания. Сначала fos, потом fis. Как стопка тарелок — последний положил, первый забрал. 🟢 Шаг 5: Скрытая ловушка — подавленные исключения Что если и в блоке try, и при закрытии ресурса летят исключения?
class ExplosiveResource implements AutoCloseable {
    public void work() { throw new RuntimeException("Ошибка в работе"); }
    @Override
    public void close() { throw new RuntimeException("Ошибка при закрытии"); }
}

try (ExplosiveResource r = new ExplosiveResource()) {
    r.work();
} catch (RuntimeException e) {
    System.out.println(e.getMessage()); // "Ошибка в работе"
    Throwable[] suppressed = e.getSuppressed();
    System.out.println(suppressed[0].getMessage()); // "Ошибка при закрытии"
}
➡️ Исключение из close() не теряется! Оно становится подавленным (suppressed) и прикрепляется к основному исключению. Получить их можно через e.getSuppressed(). 🟢 Шаг 6: Можно и без catch — просто закрытие
try (Resource r = new Resource()) {
    // используем
}
// catch не обязателен! Ресурс закроется в любом случае
➡️ Если тебя не интересуют исключения в работе (например, при записи в лог), можно опустить catch. Ресурс всё равно закроется. 🟢 Шаг 7: Ресурс, объявленный до try (final variable)
Resource r = new Resource();
try (r) { // Работает с Java 9+
    r.use();
}
➡️ Если переменная эффективно final (не меняется после инициализации), можно использовать её в try-with-resources. Удобно, когда ресурс создаётся заранее. 🗣️ Запомни: Используй try-with-resources всегда, когда есть что закрывать. Если пишешь свой класс с ресурсами — реализуй AutoCloseable.

🔴 КАК ИДЕАЛЬНО ПРОЙТИ СОБЕС? ПОКАЖЕМ ЗАВТРА! Каждый, проходя интервью, думал: «Ну что они хотят услышать? Я же правильно отв
🔴 КАК ИДЕАЛЬНО ПРОЙТИ СОБЕС? ПОКАЖЕМ ЗАВТРА! Каждый, проходя интервью, думал: «Ну что они хотят услышать? Я же правильно ответил! Почему меня не взяли?» 4 марта(уже завтра!) в 19:00 по мск приходи онлайн на открытое интервью, где будут собеседовать МЕНТОРА ШОРТКАТ Как это будет: 📂 Виктор Анохин, старший разработчик из WildBerries, будет задавать реальные вопросы и задачи старшему разработчику Сергею Чамкину 📂 Сергей будет отвечать на каждый вопрос так, как это ожидает сам от вас на собеседованиях 📂 В конце можно будет задать любой вопрос Сергею и Виктору Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot Реклама. О рекламодателе.

🧵 ThreadLocal: как не устроить коммунальную квартиру в потоках Кажется, что ThreadLocal — идеальный способ хранить данные, принадлежащие конкретному потоку: контекст пользователя, соединение с БД, ID запроса. Но когда ты используешь пул потоков (как в любом серьёзном веб-приложении), твои переменные могут внезапно переехать к соседям. Ты думал, у каждого клиента своя уютная комната, а они живут в коммуналке, где всё общее. Вот почему это происходит и как не пустить посторонних в свои данны👇 🟢 Шаг 1: Что такое ThreadLocal и как он работает
public class UserContext {
    private static ThreadLocal<String> currentUser = new ThreadLocal<>();

    public static void set(String user) { currentUser.set(user); }
    public static String get() { return currentUser.get(); }
    public static void clear() { currentUser.remove(); }
}

// В потоке A:
UserContext.set("Алиса");
System.out.println(UserContext.get()); // Алиса

// В потоке B:
System.out.println(UserContext.get()); // null (свой контекст)
➡️ ThreadLocal хранит значение в самом объекте потока. У каждого потока свой «ящичек», и другие потоки в него не заглядывают. 🟢 Шаг 2: Пулы потоков — когда начинается коммуналка Веб-серверы (Tomcat, Jetty) используют пул потоков: один поток обрабатывает много запросов последовательно.
// Контроллер
@GetMapping("/user")
public String getUser() {
    // Предположим, middleware установил UserContext.set(...)
    String user = UserContext.get();
    // ... логика ...
    return user;
}
➡️ Проблема: если ты не очистил ThreadLocal после обработки запроса, при следующем запросе (который пойдёт через тот же поток) в get() вернётся старый пользователь! Чужой пользователь получит данные предыдущего. Это называется утечка контекста. 🟢 Шаг 3: Визуализация проблемы
ExecutorService pool = Executors.newFixedThreadPool(1);

// Запрос 1 (Алиса)
pool.submit(() -> {
    UserContext.set("Алиса");
    System.out.println(UserContext.get()); // Алиса
    // Забыли очистить!
});

// Запрос 2 (Боб) — тот же поток!
pool.submit(() -> {
    System.out.println(UserContext.get()); // Алиса?! Вот и коммуналка
});
➡️ Поток переиспользовался, а данные остались. Боб получил контекст Алисы. Это критично для безопасности и корректности. 🟢 Шаг 4: Правильный паттерн — очистка в finally
@GetMapping("/user")
public String getUser() {
    try {
        // Установили (например, из фильтра)
        UserContext.set(getCurrentUserFromRequest());
        return process();
    } finally {
        UserContext.clear(); // Гарантированно чистим
    }
}
➡️ finally гарантирует очистку даже если вылетело исключение. Никаких чужих данных следующему запросу. 🟢 Шаг 5: Элегантный способ — try-with-resources (AutoCloseable) Можно сделать ThreadLocal обёртку, которая чистит автоматически:
public class ThreadLocalScope implements AutoCloseable {
    private static ThreadLocal<String> current = new ThreadLocal<>();

    public ThreadLocalScope(String value) {
        current.set(value);
    }

    public static String get() { return current.get(); }

    @Override
    public void close() {
        current.remove();
    }
}

// Использование:
try (ThreadLocalScope scope = new ThreadLocalScope("Алиса")) {
    String user = ThreadLocalScope.get(); // Алиса
    // ...
} // автоматически удалится
➡️ Не надо думать о finally. Java сама вызовет close(). 🟢 Шаг 6: Проверка на утечки в тестах Можно добавить тест, который после выполнения проверяет, что ThreadLocal пуст:
@Test
void testCleanup() {
    // Выполняем запрос
    userController.getUser();
    // В том же потоке проверяем:
    assertThat(UserContext.get()).isNull();
}
➡️ Помогает отловить забытые очистки. 🗣️ Запомни: ThreadLocal в пуле потоков без очистки — это как не закрыть кран: рано или поздно затопишь соседей. Всегда чисти за собой, иначе чужой пользователь увидит данные твоего клиента. А в коммуналке и так тесно.

Бесплатная конференция по PostgreSQL Регистрируйся на бесплатную конференцию по PostgreSQL — 19.03.2026.📅 Эксперты расскажут о разработке, администрировании и новинках мира Postgres. ✅ Бесплатное участие ✅ Опытные спикеры ✅ 25+ тематических докладов ✅ Рабочие кейсы Каждый участник получает именной Сертификат участника мероприятия. Одни из немногих спикеров конференции: — Андрей Бородин PostgreSQL Major contributor, руководитель подразделения разработки РСУБД с открытым исходным кодом Yandex Cloud — Родион Хабибов DevOps-инженер «СберСервис» — Андрей Овчаренко Руководитель отдела Java-разработки Московской биржи ... и многие другие. Регистрируйся, будет интересно! И бесплатно! Зарегистрироваться #реклама 16+ pgbootcamp.ru О рекламодателе

🗑 ConcurrentModificationException: удалять на ходу — как менять колесо у едущей машины Всё работает, коллекция полна данных, ты решил почистить её во время обхода... и получаешь ConcurrentModificationException. Знакомая боль? Это Java кричит: «Нельзя менять колесо, пока машина едет!». Давай разберём, почему так происходит и как делать правильно, чтобы не попадать в аварию 👇 🟢 Шаг 1: Типичная ошибка (как НЕ надо)
List<String> fruits = new ArrayList<>(List.of("яблоко", "банан", "апельсин", "груша"));

// Пытаемся удалить все фрукты короче 6 букв
for (String fruit : fruits) { // for-each использует итератор
    if (fruit.length() < 6) {
        fruits.remove(fruit); // 🚨 ConcurrentModificationException!
    }
}
➡️ Код падает с исключением. Почему? Потому что for-each создаёт итератор, а ты напрямую вызываешь remove() у самой коллекции. Итератор теряет ориентацию и бунтует. 🟢 Шаг 2: Что происходит под капотом (fail-fast итератор)
// Упрощённая логика итератора ArrayList:
class Itr implements Iterator<E> {
    int expectedModCount = modCount; // запоминаем версию коллекции

    public E next() {
        checkForComodification(); // проверяем, не изменилась ли коллекция
        // ...
    }

    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}
➡️ Каждая модификация коллекции (add, remove) увеличивает счётчик modCount. Итератор при создании запоминает это число, а при каждом вызове next() проверяет, не изменилось ли оно. Если да — вылетает исключение. Это защита от непредсказуемого поведения. 🟢 Шаг 3: Правильный способ №1 — через итератор
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
    String fruit = iterator.next();
    if (fruit.length() < 6) {
        iterator.remove(); // ✅ Безопасно! Итератор сам обновляет счётчик
    }
}
System.out.println(fruits); // [апельсин]
➡️ У итератора есть свой метод remove(), который удаляет последний возвращённый элемент и корректирует внутренний expectedModCount. Итератор остаётся валидным. 🟢 Шаг 4: Современный способ №2 — Collection.removeIf() (Java 8+)
fruits.removeIf(fruit -> fruit.length() < 6);
System.out.println(fruits); // [апельсин]
➡️ removeIf — встроенный метод коллекций, который делает то же самое, но в одну строку. Под капотом он использует итератор, но ты не видишь этой возни. Самый чистый и читаемый вариант. 🟢 Шаг 5: Альтернативы — копирование или стримы Если нужно не удалять, а создать новую коллекцию (иммутабельность):
// Через стримы
List<String> filtered = fruits.stream()
    .filter(fruit -> fruit.length() >= 6)
    .collect(Collectors.toList());

// Или через новый список
List<String> result = new ArrayList<>();
for (String fruit : fruits) {
    if (fruit.length() >= 6) result.add(fruit);
}
➡️ Иногда проще собрать новую коллекцию, чем мутировать старую. Особенно если исходная коллекция потом не нужна. 🗣️ Запомни: Удалять элементы из коллекции во время for-each — это как менять колесо на полном ходу.

🔠 Слили 4 ТБ по IT, хакингу и разработке. ⚪️ Все лучшие инструкции, гайды, книги и инструменты — без воды. 🖥 Курсы & GitHub
🔠 Слили 4 ТБ по IT, хакингу и разработке. ⚪️ Все лучшие инструкции, гайды, книги и инструменты — без воды. 🖥 Курсы & GitHub — 579GB ☁️ Хакинг & ИБ — 756GB 🤒 OSINT — 315GB ⌨️ Python — 955GB 🙃 Linux & Bash — 459GB 😦 Работа в IT — 278GB 🖥 Общий архив — 946GB ➡️ Присоединяйтесь и скачивайте. Пост будет удален через 48 часов.

☕️ Java с нуля. Введение в ООП
В этом видео автор предлагает нестандартный взгляд на объектно-ориентированное программирование. Он честно признаёт, что будет учить «неправильному» ООП, но именно с таким подходом вы столкнётесь в реальной индустрии — от работы с фреймворками до корпоративных проектов. Это прикладное введение, которое подготовит вас к реалиям разработки, а не к академической теории.
➡️ Ссылка на первоисточник 🗣️Запомни: в программировании важно не только знать, «как правильно», но и понимать, «как работает» в реальных проектах. Готовьтесь к индустрии, а не к идеальному миру. 🤩 Java Фишки и трюки || #Видео

🔀 Stream.peek: подсматривать в замочную скважину опасно Кажется, что peek() — идеальный способ заглянуть внутрь стрима, посмотреть, что там происходит на каждом этапе, и ничего не сломать. Но Java — язык хитрый: иногда простое подсматривание меняет результат. Заглянул — и сломал. Разбираемся, когда peek() безобиден, а когда начинает колдовать 👇 🟢 Шаг 1: Что такое peek()?
Stream.of("яблоко", "банан", "апельсин")
    .peek(s -> System.out.println("Обрабатываем: " + s))
    .map(String::toUpperCase)
    .forEach(System.out::println);
➡️ peek() принимает Consumer и выполняет его для каждого элемента, не меняя элемент. Создан для отладки — чтобы смотреть, что течёт по трубе. 🟢 Шаг 2: Когда peek() работает (и это полезно)
List<String> result = Stream.of("one", "two", "three")
    .peek(System.out::println) // видим все элементы
    .filter(s -> s.length() > 3)
    .collect(Collectors.toList());
// Вывод: one, two, three
// Результат: ["three"]
➡️ Пока стрим заканчивается терминальной операцией (здесь collect), peek() выполняется для каждого элемента, проходящего через него. Идеально для быстрой отладки. 🟢 Шаг 3: Ловушка №1 — ленивость стримов
Stream.of("один", "два", "три")
    .peek(System.out::println)
    .map(String::length);
// Ничего не выведется! Терминальной операции нет.
➡️ Стримы ленивы. Промежуточные операции (включая peek) не выполняются, пока не вызвана терминальная операция. Если забыть collect или forEach, твой peek молчит — и ты не понимаешь, почему. 🟢 Шаг 4: Ловушка №2 — peek() может изменить состояние (и сломать результат)
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
List<String> result = list.stream()
    .peek(s -> list.add(s.toUpperCase())) // МОДИФИЦИРУЕМ ИСХОДНЫЙ СПИСОК
    .collect(Collectors.toList());
System.out.println(result); // ??
➡️ В зависимости от реализации стрима (последовательный/параллельный) это может привести к ConcurrentModificationException или просто к непредсказуемому результату. peek не предназначен для изменения данных — только для чтения. 🟢 Шаг 5: Ловушка №3 — оптимизации стримов
Stream.of("a", "bb", "ccc")
    .peek(System.out::println) // ожидаем увидеть все?
    .filter(s -> s.length() > 2)
    .findFirst(); // терминальная операция, но...
➡️ Вывод: "a", "bb", "ccc"? Нет! Стрим оптимизирует: findFirst() может перестать перебирать элементы, как только найдет подходящий. peek выполняется только для тех, кто реально проходит через него до момента остановки. Здесь: "a" (не прошла фильтр), "bb" (не прошла), "ccc" (прошла — выведется, потом стрим останавливается). Итого вывод только "a", "bb", "ccc". Но если изменить порядок — может быть меньше. 🟢 Шаг 6: Когда peek() безопасен и полезен 🟢 Только для отладки во время разработки. 🟢 Только с терминальной операцией, которая обрабатывает все элементы (например, forEach, collect в список). 🟢 Без изменения внешнего состояния (только чтение, логирование). 🟢 Шаг 7: Чем заменить peek() для реальных действий
// Если нужно логировать + модифицировать — используй map и верни тот же объект
.map(s -> { System.out.println(s); return s; })
➡️ Но это костыль. Лучше использовать полноценный отладчик или логирование вне стрима. 🗣️ Запомни: peek() это замочная скважина: подсматривать можно, но дверь открывать нельзя. Если нужно что-то сделать с элементами, делай это в map или в терминальной операции.

⌨️ Какой хеш-код имеет null? null не имеет хеш-кода, потому что null не является объектом. Однако, при использовании null в структурах данных, таких как HashMap или HashSet, применяется специальная логика: ➡️ Что происходит с null в HashMap и HashSet? ✔️ В HashMap ключ null всегда попадает в первый бакет (bucket 0). ✔️ В HashSet (который использует HashMap внутри) null также хранится в этом же бакете. ✔️ Проверки выполняются в Objects.hashCode(), который для null всегда возвращает 0. ➡️ Пример:

System.out.println(Objects.hashCode(null)); // 0
📌 Вывод: null не имеет собственного хеш-кода, но в хеш-структурах ему назначается 0.

👩‍💻 Программирование — В С Ё В 2026 году на кодинге уже не вывезешь, перспектива года - Информационная Безопасность. Ловите
👩‍💻 Программирование — В С Ё В 2026 году на кодинге уже не вывезешь, перспектива года - Информационная Безопасность. Ловите полезные каналы, которые помогут ворваться в новое направление. 👍 ZeroDay — Уроки, эксплуатация уязвимостей с нуля 👍 Белый Хакер — Свежие новости из мира ИБ 😎 Бункер Хакера — Статьи, книги, шпаргалки и хакинг 👨‍💻 Серверная Админа — Настройка и уроки по компьютерным сетям 📂 Вступай и изучай новое направление!

☕️ Интерфейсы в Java
В этом видео автор подробно разбирает, что такое интерфейсы в Java и чем они похожи на абстрактные классы. Вы узнаете об их ключевых отличиях, научитесь применять интерфейсы на практике и поймёте, в каких задачах они становятся незаменимым инструментом для создания гибкой и понятной архитектуры кода.
👉 Ссылка на первоисточник 🗣Запомни: интерфейсы — это контракты, которые определяют что должен делать класс, а не как. Это основа для написания слабосвязанного и тестируемого кода. 🤩 Java Фишки и трюки || #Видео

👩‍💻 Хватит учить только синтаксис, начинай делать реальные проекты! Python Ready — авторский канал, где Python перестаёт бы
+4
👩‍💻 Хватит учить только синтаксис, начинай делать реальные проекты! Python Ready — авторский канал, где Python перестаёт быть только теорией и становится рабочим инструментом. Мини-проекты, боты, советы, разборы задач, гайды и шпаргалки для каждого программиста. 🔥 Советую подписаться: @python_ready

📅 LocalDate и DateTimeFormatter: вечная путаница с YYYY и yyyy Каждый Новый год эта ошибка просыпается и незаметно портит данные в логах, отчётах и экспортах. Разница между YYYY и yyyy - всего одна буква, но она может сдвинуть дату на целый год вперёд или назад в первую неделю января. Вот как не попасть в эту ловушку и почему это происходит 👇 📁 Шаг 1: Наглядный пример ошибки (31 декабря 2024 года)
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
➡️ Да, 31 декабря 2024 года форматируется как... 2025 год. Это не баг, а фича, о которой мало кто знает. 📁 Шаг 2: В чём разница? (Год vs Год недели) - `yyyy` — это обычный календарный год (year-of-era). То, что мы все понимаем под годом. - `YYYY` — это год недели (week-based-year) по стандарту ISO 8601. ➡️ YYYY используется вместе с номером недели (ww) и днём недели (E). Он нужен для отображения года, к которому относится неделя, а не календарная дата. 📁 Шаг 3: Почему происходит сдвиг? (Магия первой недели года) По ISO 8601: 1. Неделя начинается с понедельника. 2. Первая неделя года — это неделя, содержащая первый четверг года. 3. Год недели (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 года
➡️ Критические периоды: последние 3-4 дня декабря и первые 3-4 дня января. Именно здесь YYYY и yyyy чаще всего расходятся. 📁 Шаг 4: Где используется `YYYY` (правильно) Только вместе с номером недели!
// Для отображения номера недели и года недели (отчёты, планирование)
DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern("'Неделя' ww, YYYY");
LocalDate date = LocalDate.of(2024, 12, 30);

System.out.println(date.format(weekFormatter));
// "Неделя 01, 2025" ← это правильно для систем, работающих по неделям
➡️ Используй YYYY только если ты точно понимаешь, что такое год недели, и используешь его с ww (номер недели). 📁 Шаг 5: Где НЕЛЬЗЯ использовать `YYYY` (опасные случаи) 1. Логирование — дата в логах внезапно станет 2025 годом 30 декабря. 2. Экспорт в CSV/Excel для отчётности. 3. Формирование имён файлов с датами. 4. Любые даты, которые потом будут парситься обратно.
// ❌ Опасный парсинг (может сломаться)
String wrong = "31.12.2024";
LocalDate parsed = LocalDate.parse(wrong, DateTimeFormatter.ofPattern("dd.MM.YYYY"));
// Может выкинуть исключение или спарсить не ту дату
📁 Шаг 6: Как избежать ошибки навсегда 1. Используй готовые форматеры вместо ручных паттернов:
   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 оставь для отчётов по неделям.

Docker и Kubernetes: основы разработки под облачную инфраструктуру Курс для тех, кто хочет держать свой стэк и знания актуаль
Docker и Kubernetes: основы разработки под облачную инфраструктуру Курс для тех, кто хочет держать свой стэк и знания актуальными и глубоко разбираться, как устроены Docker, Kubernetes, и современная облачная инфраструктура в целом. 🌐 Чему вы научитесь: 🤩 Создавать облачную инфраструктуру «с нуля» управление и конфигурация серверов с Terraform, Ansible, cloud‑init 🤩 Уверенно работать с Docker: Dockerfile, слои, кэш, многоступенчатые сборки, реестры, безопасность, air‑gapped 🤩 Проектировать многоконтейнерные приложения: паттерны Sidecar, Ambassador, Adapter, проверки (liveness/readiness), DaemonSet и поды 🤩 Настраивать сеть и балансировку в Kubernetes ClusterIP, Services, Ingress, MetalLB, TLS/SNI, сервис‑меши (Istio) 🤩 Организовывать хранение данных: PersistentVolumes / PVC, StorageClasses, резервное копирование. Упаковка в Helm и поддержка через Operator 🥸 Кто мы: R&D-центр Devhands. Автор курса — Николай Ихалайнен, эксперт по СУБД и бекенду (ex-Percona), со-основатель MyDB, энтузиаст открытого ПО. 🗓 Старт курса: 25 февраля, 6 недель обучения. Изучить программу и записаться можно здесь. Ждем вас! Реклама. ИП Рыбак А.А. ИНН 771407709607 Erid: 2Vtzqvh26Qk