Java for Beginner
871 subscribers
1.01K photos
275 videos
14 files
1.69K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
🤣6🔥1
История технологии сегодня — 12 апреля

🚀 Международный день полёта человека в космос (на других официальных языках ООН: англ. International Day of Human Space Flight, исп. Día Internacional de los Vuelos Espaciales Tripulados, фр. Journée internationale du vol spatial habité) — памятная дата международного уровня в ознаменование начала космической эры для человечества. Ежегодно отмечается 12 апреля.

На корабле «Восток» 12 апреля 1961 года лётчик-космонавт СССР майор ВВС Юрий Алексеевич Гагарин совершил первый в мире пилотируемый полёт в космическое пространство. Старт корабля состоялся с советского космодрома Байконур в 9 часов 7 минут по московскому времени (06:07:00 UTC). Корабль выполнил один оборот вокруг Земли и совершил посадку в 10 часов 53 минуты (07:53:00 UTC) в районе деревни Смеловка Саратовской области. Длительность полёта составила 106 минут. Корабль стал и первым в мире управляемым космическим аппаратом, позволившим совершить полёт в космос.


ℹ️ Кто родился в этот день

Станисла́в Никола́евич Ко́нюхов (12 апреля 1937, с. Бекренево, Лежский район, Вологодская область, РСФСР — 3 апреля 2011) — учёный, инженер и конструктор в аэрокосмической области. Автор свыше 240 научных работ в области статики и динамики стойкости, рациональных способов обеспечения пространственной ориентации, механики взаимодействия твёрдых тел с препятствиями при гиперзвуковых скоростях.


🌐 Знаковые события

1903 — в Лондоне на маршрут вышел первый в мире городской автобус с двигателем внутреннего сгорания.

1961 — Гражданин СССР Юрий Гагарин на корабле «Восток-1» стал первым человеком, совершившим космический полёт.

1981 — в день 20-летия первого полёта человека в космос стартовал американский корабль «Колумбия». Первый пилотируемый полёт в космос по программе «Спейс шаттл».

1995 — запущен каталог «Yahoo!», быстро ставший одним из самых популярных в мире.


#Biography #Birth_Date #Events #12апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Что случилось и почему сайт не работал или хронология одного хренового утра

Сразу к делу: сайт лежал намертво.

Не просто не открывалась страница, а вообще никакого признака жизни извне.

При этом я зашел через VNC (прямую консоль провайдера) и увидел, что сервер внутри работает. Файлы на месте, база цела, контейнеры Docker крутятся. Но снаружи — бетонная стена.

Ниже расскажу, что именно произошло, почему техподдержка трижды предлагала мне просто все переустановить и как в итоге удалось вытащить проект с того света без потери данных.


Часть 1. Симптомы, которые сбивали с толку

Первый звоночек: SSH не подключается. Таймаут. Первая мысль может порт сменился или фаервол взбесился. Захожу через VNC и вижу странную картину. Фаервол чистый. SSH демон запущен. Но соединения извне нет вообще.

Делаю пинг до гугловской восьмерки и вижу заветные слова: Destination Host Unreachable. Это уже совсем плохой звоночек. Он означает, что сервер не просто не видит интернет, он не видит даже собственный шлюз провайдера. Он как будто в вакууме.

Дальше больше. Проверяю сетевые настройки: IP на месте, маска правильная, шлюз прописан. Сбрасываю интерфейс, перезагружаю сервер, чищу ARP-таблицу. Ноль реакции.


Часть 2. Техподдержка и стадия отрицания

Пишу в техподдержку. Объясняю ситуацию: консоль есть, сервер жив, но сети нет. В ответ получаю классику: "Переустановите операционную систему".

Переустановка ОС при такой проблеме это как менять двигатель у машины, у которой просто отвалилось колесо. Данные бы улетели, все настройки nginx и docker пришлось бы поднимать с нуля, но связь бы не появилась, потому что проблема была глубже.

Начинается битва аргументов. Привожу вывод команды ip neigh show, где напротив адреса шлюза красуется статус FAILED. Это железное доказательство того, что обрыв на канальном уровне, то есть на стороне виртуального коммутатора провайдера.


Часть 3. Смена IP и миграция

Чтобы отвязаться от настойчивых просьб переустановить систему, соглашаюсь на предложение сменить IP-адрес. Меняют. Прописываю новый адрес вручную в консоли. Результат тот же — Destination Host Unreachable. Это окончательно подтверждает: проблема не в софте, а в виртуальном железе, к которому прицеплен VPS.

Только после этого неожиданно сервер мигрируют на другую физическую ноду.

И о чудо. Пинг до восьмерки пошел. Сеть ожила.


Часть 4. Оживление пациента

Казалось бы, победа. Но это был только начало.

После миграции сайт все равно не открывался, а SSH валился с ошибкой Connection refused.

Выяснилось, что после миграции демон SSH просто отключился и не встал в автозагрузку.

Дальше пошла борьба с Nginx. Конфиги, которые прекрасно работали на старом месте, здесь встали колом. Оказалось, что запросы улетали в неправильный блок сервера и рвались с ошибкой Empty reply from server. Пришлось перелопатить конфиги, убрать лишние редиректы и явно прописать, что сайт должен слушаться не только по домену, но и просто по IP.

Затем всплыла история с сертификатами. Let's Encrypt честно выдал новые ключи, но браузер упорно не хотел показывать сайт по HTTPS.


Часть 5. Финальный босс — кэш браузера

Тут началась настоящая мистика. По IP через HTTP все грузилось идеально. А по домену devforge.ru — белый экран. Ни ошибок в консоли, ни проблем с сетью.

Оказалось, что это HSTS. Механизм безопасности браузера, который намертво запомнил старые настройки еще с прошлого IP. Браузер тупо блокировал загрузку ресурсов, считая, что сайт подменили.

Открываю то же самое в режиме инкогнито — и все работает как часы.

Выяснилось: сервер был полностью исправен уже несколько часов, а проблема сидела в кэше на стороне клиента (я ебалай).


Итог

Сервер перенесен на новую ноду. Связка Nginx, Docker и API работает стабильно. DNS обновлены. SSL сертификаты свежие.
Если у вас вдруг сейчас сайт не грузится или выглядит странно — просто почистите кэш браузера или откройте страницу в режиме инкогнито. Это уберет остатки старых редиректов.
Если кто пытался зайти на Devforge.ru, но не мог, спасибо за терпение.

Проект снова в строю и стал немного надежнее.

А я маленько вахуе 🤪
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🤯4
История технологии сегодня — 13 апреля

ℹ️ Кто родился в этот день

Джеремайя Пол (Джерри) Острайкер (англ. Jeremiah Paul «Jerry» Ostriker; 13 апреля 1937, Нью-Йорк — 6 апреля 2025, там же) — американский теоретик-астрофизик и космолог, основоположник теории тёмного вещества. Автор более 500 научных публикаций в сфере космологии, особо уделял внимание темам, в которых применяются сложные математические вычисления. Основными темами исследований Острайкера были тёмное вещество и тёмная энергия, тепло-горячая межгалактическая среда, формирование галактик, рост чёрных дыр и взаимодействие квазаров с окружающим пространством.

Ро́берт Алекса́ндр Уо́тсон-Уотт (англ. Robert Alexander Watson-Watt; 13 апреля 1892 — 5 декабря 1973) — шотландский физик, один из пионеров в области работ по радиолокации. Сконструировал одно из первых устройств, предназначенных для радиолокации воздушных объектов и получил первый патент на изобретение подобной системы в 1934 году, а 26 февраля 1935 года успешно продемонстрировал своё изобретение, которое могло обнаружить самолёт на расстоянии 64 км.

Антонио Санти Джузеппе Меуччи (итал. Antonio Santi Giuseppe Meucci; 13 апреля 1808 — 18 октября 1889) — итальянский учёный, являющийся изобретателем телефона. Именно он в 1860 году пришёл к выводу о возможности превращения звуковых колебаний в электрические импульсы, что позволяет передавать голос на расстояние с помощью проводов.


🌐 Знаковые события

1960 — Соединенные Штаты запускают Transit 1-B, первую в мире спутниковую навигационную систему.


#Biography #Birth_Date #Events #13апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
[Совет по Java #025]

Тема: ThreadLocal может вызвать утечку в серверах приложений.

Проблема: В серверах приложений (Tomcat, Jetty, WildFly) потоки из пула переиспользуются между запросами.

ThreadLocal хранит данные, привязанные к конкретному потоку. Если после обработки запроса не вызвать remove(), данные останутся в потоке навсегда. При следующем запросе, который получит тот же поток, код увидит "грязные" данные от предыдущего запроса, что приводит к непредсказуемому поведению — утечке контекста безопасности, некорректным настройкам локали, перемешиванию данных разных пользователей.

Более того, если загруженный класс (например, из веб-приложения) хранится в ThreadLocal, а поток продолжает жить, это создает классическую утечку памяти ClassLoader — приложение не может быть выгружено.

Решение: Всегда вызывайте ThreadLocal.remove() после использования, особенно в веб-среде.

Лучшая практика — оборачивать использование ThreadLocal в блок try-finally. Для фильтров и перехватчиков используйте один централизованный механизм очистки. Рассмотрите альтернативы: передача контекста явно через параметры методов, использование ScopedValue (Java 20+ incubator, Java 21+ preview), которое автоматически очищается.

public class ThreadLocalLeak {

//Антипаттерн: ThreadLocal без очистки
private static final ThreadLocal<UserContext> CURRENT_USER = new ThreadLocal<>();

public static void processRequestBad(User user) {
CURRENT_USER.set(new UserContext(user)); // Установили
// ... обработка запроса
// Забыли remove() — данные останутся в потоке навсегда
}

//Решение: try-finally с remove()
public static void processRequestGood(User user) {
try {
CURRENT_USER.set(new UserContext(user));
// ... обработка запроса
} finally {
CURRENT_USER.remove(); // Гарантированная очистка
}
}

// Демонстрация утечки
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(2);

// Плохой вариант
for (int i = 0; i < 10; i++) {
final int requestId = i;
executor.submit(() -> {
processRequestBad(new User("User" + requestId));
});
}

Thread.sleep(1000);

// Теперь в потоках пула остались старые данные
executor.submit(() -> {
UserContext context = CURRENT_USER.get(); // Может вернуть данные от старого запроса!
System.out.println("Остались данные: " + context);
});

executor.shutdown();
}

// Для веб-фильтра (Spring-стиль)
public static class WebFilter {
public void doFilter(Request request, FilterChain chain) {
try {
// Установка контекста из запроса
UserContext.setCurrent(request.getUser());
chain.proceed();
} finally {
UserContext.clear(); // Обязательная очистка после каждого запроса
}
}
}
}


Объяснение: Пул потоков в серверах приложений создает ограниченное количество потоков, которые обрабатывают тысячи запросов последовательно.

ThreadLocal хранит значение в массиве ThreadLocalMap внутри объекта Thread. Если не вызвать remove(), ссылка на значение остается в этом массиве. При следующем использовании того же потока get() вернет старое значение. Даже если ссылка на объект в ThreadLocal станет слабой (как у ThreadLocal по умолчанию), она все равно будет достижима через Thread.currentThread(), пока поток жив.

Это приводит к двум проблемам: логическая утечка (неправильные данные) и физическая утечка (классы из веб-приложения не выгружаются).

Правило простое: для каждого set() должен быть соответствующий remove() в том же потоке. Java 21 предлагает ScopedValue как иммутабельную и автоматически очищаемую альтернативу.


#Java #советы
👍5
Что выведет код?

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Task130426 {
static class UserContext130426 {
String userId;
UserContext130426(String userId) { this.userId = userId; }
}

static ThreadLocal<UserContext130426> currentUser = new ThreadLocal<>();

public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();

executor.submit(() -> {
currentUser.set(new UserContext130426("user1"));
System.out.print(currentUser.get().userId + " ");
});

executor.submit(() -> {
UserContext130426 ctx = currentUser.get();
System.out.println(ctx == null ? "null" : ctx.userId);
});

executor.shutdown();
}
}


#Tasks
👍1
👍2
Что такое Semaphore? 🤓

Ответ:

Semaphore (семафор)
— это средство синхронизации, которое ограничивает количество потоков, имеющих доступ к определенному ресурсу или участку кода.

Семафор поддерживает счетчик разрешений. Поток запрашивает разрешение методом acquire() (счетчик уменьшается) и освобождает методом release() (счетчик увеличивается).

Если разрешений нет, поток блокируется. Битовый семафор (счетчик 1) работает как мьютекс (lock). Семафоры часто используются для ограничения нагрузки (throttling).


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологии сегодня — 14 апреля

ℹ️ Кто родился в этот день

Серге́й Ива́нович Мо́син (2 [14] апреля 1849, Рамонь — 26 января [8 февраля] 1902, Сестрорецк) — русский конструктор и организатор производства стрелкового оружия. Генерал-майор Русской императорской армии.

В 1883 году Мосин разработал свои первые магазинные винтовки. Так, он усовершенствовал винтовку Бердана, приделав к ней магазин на восемь патронов. 16 апреля 1891 года был утверждён образец «повторительной» четырёхтактной винтовки со серединным магазином калибра 3 линии (7,62 мм), основу которой разработал Мосин. Она получила название «Трёхлинейная винтовка образца 1891 года». В 1900 году на Всемирной выставке в Париже российская «малокалиберная» трёхлинейная штатная винтовка получила Гран-При. Винтовки и карабины системы Мосина нескольких модификаций производилась в России и СССР до 1947 года и находились на вооружении до середины 1970-х годов. После Второй мировой войны винтовки и карабины Мосина производились по лицензии в ПНР, ВНР, РНР.


Юкихиро Мацумо́то (яп. 松本行弘, чаще яп. まつもとゆきひろ, также известный как Matz, род. 14 апреля 1965) — японский разработчик свободного ПО, создатель языка программирования Ruby.

В интервью «Japan Inc.» он говорил, что сам учился программировать ещё до окончания школы. Он окончил университет города Цукуба, где он занимался исследованиями языков программирования и компиляторов. С 2006 года возглавляет отдел исследований и разработок Network Applied Communication Laboratory, японский системный интегратор свободного ПО.


Христиа́н Гю́йгенс ван Зёйлихем (нид. Christiaan Huygens МФА: [ˈkrɪstijaːn ˈɦœyɣə(n)s]о файле; 14 апреля 1629, Гаага — 8 июля 1695, там же) — голландский механик, физик, математик, астроном и изобретатель. Первый иностранный член Лондонского королевского общества (1663), член Французской академии наук с момента её основания (1666) и её первый президент (1666—1681).

Один из основоположников теоретической механики и теории вероятностей. Внёс значительный вклад в оптику, молекулярную физику, астрономию, геометрию, часовое дело. Открыл кольца Сатурна и Титан (спутник Сатурна). Изобрёл первую практически применимую модель часов с маятником. Положил начало волновой оптике.


🌐 Знаковые события

1932 — в кембриджской лаборатории Резерфорда физики Кокрофт и Уолтон впервые добились искусственной ядерной реакции.

1983 — первый радиотелефон начал продаваться в Великобритании.

2003 — учёные объявили о завершении основных работ по расшифровке
генома человека.


#Biography #Birth_Date #Events #14апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Раздел 9. Исключения, логирование, отладка

Глава 1. Иерархия исключений (Exceptions)

try-catch-finally – правильная обработка и освобождение ресурсов


Исторический контекст: до Java 7


До появления Java 7 в 2011 году механизм try-catch-finally был единственным способом гарантировать выполнение cleanup-кода независимо от того, как завершился основной блок операций. Этот паттерн применялся для закрытия файловых потоков, сетевых соединений, освобождения блокировок и любых других ресурсов, требующих явного освобождения.

Однако этот подход был чрезвычайно многословным и подверженным ошибкам. Каждый ресурс требовал отдельной переменной, объявленной вне блока try, проверки на null в finally, и вложенных try-catch блоков для обработки исключений при самом закрытии ресурса. Это создавало "pyramid of doom" — визуально громоздкую структуру кода, где бизнес-логика терялась среди шаблонного кода управления ресурсами.


Механика выполнения: как JVM обрабатывает finally

На уровне байткода JVM блок finally реализован не как отдельная конструкция языка, а через механизм инлайнинга и таблиц исключений. Компилятор Java дублирует байткод finally-блока в каждой точке выхода из try и связанных catch-блоков, а также добавляет специальные записи в exception table для гарантии выполнения даже при неперехваченных исключениях.

Рассмотрим простой пример и его байткод-представление:
public void simpleTryFinally() {
try {
processData();
} finally {
cleanup();
}
}


Компилятор генерирует байткод, где инструкции cleanup() дублируются в трех местах: при нормальном завершении try, при выходе через return, и в специальном catch-all обработчике для неперехваченных исключений. Exception table метода содержит запись from: 0, to: 4, target: 8, type: any, которая перехватывает любое исключение, выполняет cleanup, и перевыбрасывает исходное исключение .

В современных версиях Java (начиная с Java 6) компилятор использует полный инлайнинг байткода finally-блока. Ранее, до Java 6, применялись мини-подпрограммы (mini-subroutines) с инструкциями jsr (jump subroutine) и ret (return from subroutine), которые вызывали общий блок кода из разных точек . Этот подход был отменен из-за сложностей верификации байткода и ограничений на оптимизацию.


Паттерн управления ресурсами: классический подход

Классический паттерн освобождения ресурсов через try-finally требовал строгой дисциплины.

Рассмотрим корректную реализацию для одного ресурса:
public String readFile(String path) throws IOException {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(path));
return reader.readLine();
} finally {
if (reader != null) {
reader.close();
}
}
}


Этот код содержит несколько критически важных элементов. Переменная reader объявлена вне блока try для доступности в finally. Проверка на null обязательна, так как если конструктор FileReader выбросит исключение (например, файл не найден), переменная reader останется неинициализированной. Блок finally выполняется всегда, даже если readLine() выбросит исключение или метод выполнит ранний return.

Сложность экспоненциально растет с количеством ресурсов. Для двух ресурсов требуется уже четыре уровня вложенности:
public void copyFile(String sourcePath, String destPath) throws IOException {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(sourcePath);
try {
fos = new FileOutputStream(destPath);
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
}
} finally {
if (fos != null) {
fos.close();
}
}
} finally {
if (fis != null) {
fis.close();
}
}
}


#Java #для_новичков #beginner #exception #try_catch_finally
👍4
Здесь важен порядок закрытия: ресурсы должны освобождаться в обратном порядке их создания. Вложенные try-finally обеспечивают, что fis будет закрыт даже если fos.close() выбросит исключение. Однако этот код все еще уязвим: если fis.close() выбросит исключение, оно замаскирует любое исключение из основного блока, что делает отладку чрезвычайно сложной.


Опасные взаимодействия: finally и return


Одна из наиболее коварных особенностей finally — его взаимодействие с оператором return. Блок finally выполняется после вычисления возвращаемого значения, но фактически до выхода из метода, что создает возможность для подавления или модификации результата.

Рассмотрим классический пример подавления исключения:
public int problematicMethod() {
try {
throw new RuntimeException("Critical error");
} finally {
return 42; // Исключение будет подавлено!
}
}


В этом коде исключение из try-блока никогда не достигнет вызывающего метода. JVM выполняет finally, встречает return, и завершает метод со значением 42. Это не просто плохая практика — это семантически некорректное поведение, которое нарушает контракт метода и делает невозможным обнаружение ошибок .

Другой вариант той же проблемы — модификация возвращаемого значения:
public int confusingMethod() {
int result = 0;
try {
result = 10;
return result;
} finally {
result = 20; // Это изменение проигнорируется!
}
}


Здесь метод вернет 10, а не 20. JVM сохраняет значение 10 в отдельной локальной переменной перед входом в finally, и восстанавливает его после завершения finally.

Однако если finally содержит собственный return, он переопределяет сохраненное значение:
public int anotherConfusingMethod() {
try {
return 10;
} finally {
return 20; // Теперь вернет 20
}
}


Эти примеры демонстрируют, что return в finally — это не просто code smell, а активно вредная практика, которую следует категорически запрещать в code style guidelines.


Обработка исключений при закрытии ресурсов

При закрытии ресурсов в finally возникает дополнительная проблема: сам метод close() может выбросить исключение. В классическом подходе это приводит к подавлению исходного исключения:
public void readAndProcess(String path) throws IOException {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(path));
process(reader);
} finally {
if (reader != null) {
reader.close(); // Если здесь IOException, исходное исключение потеряно
}
}
}


Если process(reader) выбросит DataFormatException, а reader.close() выбросит IOException, вызывающий метод получит только IOException. Информация о реальной причине ошибки (некорректный формат данных) будет утрачена. Это критично для диагностики проблем в production.

Для сохранения исходного исключения требовался изощренный паттерн:
public void readAndProcessSafe(String path) throws IOException {
BufferedReader reader = null;
IOException originalException = null;
try {
reader = new BufferedReader(new FileReader(path));
process(reader);
} catch (IOException e) {
originalException = e;
throw e;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException closeException) {
if (originalException != null) {
originalException.addSuppressed(closeException);
} else {
throw closeException;
}
}
}
}
}


Этот код использует механизм suppressed exceptions, появившийся в Java 7, но реализованный вручную. Он сохраняет ссылку на исходное исключение, и при возникновении исключения при закрытии добавляет его как "подавленное" к исходному. Это сохраняет полную картину ошибки, но ценой чрезвычайной сложности кода.


#Java #для_новичков #beginner #exception #try_catch_finally
👍3
Статические инициализаторы: особый случай

В статических блоках инициализации классов try-finally применяется редко, но имеет особую семантику. Если в статическом блоке возникает исключение, JVM оборачивает его в ExceptionInInitializerError, и класс помечается как неинициализированный. Последующие попытки использовать класс приводят к NoClassDefFoundError с причиной "initialization error".
public class ResourceHolder {
private static final Connection connection;

static {
Connection temp = null;
try {
temp = createConnection();
initializeSchema(temp);
} finally {
if (temp != null) {
try {
temp.close();
} catch (SQLException e) {
// Логирование, но исключение не пробрасывается
// Иначе класс станет непригодным к использованию
logger.error("Failed to close connection during initialization", e);
}
}
}
connection = temp; // Этот код никогда не выполнится, если finally выбросит исключение
}
}


В этом примере finally используется для гарантии закрытия соединения при ошибке инициализации схемы. Однако важно не допускать выброса исключений из finally, иначе инициализация класса завершится ошибкой, и класс станет непригодным к использованию на протяжении всей жизни JVM.


Практические рекомендации по использованию

Несмотря на появление try-with-resources, понимание try-finally остается необходимым для работы с legacy-кодом, кастомными ресурсами без AutoCloseable, и сценариями, требующими сложной логики cleanup.
Правило первое: никогда не используйте return в finally. Это подавляет исключения и создает непредсказуемое поведение. Если cleanup должен влиять на возвращаемое значение, пересмотрите архитектуру метода — возможно, логика cleanup должна быть вынесена в вызывающий код.
Правило второе: проверяйте переменные на null перед использованием в finally. Ресурс может не быть создан, если конструктор выбросил исключение, но finally выполнится в любом случае.
Правило третье: сохраняйте исходные исключения при cleanup. Если finally может выбросить исключение, используйте механизм suppressed exceptions (в Java 7+) или логируйте исходное исключение перед повторным выбросом.
Правило четвертое: минимизируйте код в finally. Блок finally должен содержать только cleanup-операции, критичные для корректности системы. Никакой бизнес-логики, никаких операций, которые могут fail — только освобождение ресурсов.
Правило пятое: предпочитайте специфичные catch-блоки общим. Перехват Exception или Throwable в catch перед finally может привести к непреднамеренному подавлению ошибок. Будьте максимально конкретны в типах перехватываемых исключений.


#Java #для_новичков #beginner #exception #try_catch_finally
👍5
Что выведет код?

public class Task140426 {
public static void main(String[] args) {
System.out.println(test());
}

static int test() {
try {
return 1;
} catch (Exception e) {
return 2;
} finally {
return 3;
}
}
}


#Tasks
👍3🤯3
Варианты ответа:
Anonymous Quiz
38%
1
0%
2
57%
3
5%
Ошибка компиляции
4👍2
Какие виды исключений в Java вы знаете (иерархия)? 🤓

Ответ:

Все исключения являются наследниками класса Throwable.

Он делится на два основных подкласса:
Error — критические ошибки JVM, которые обычно не обрабатывают (OutOfMemoryError, StackOverflowError).

Exception — исключения, которые важны для приложения. Exception делится на checked (проверяемые) — обязаны быть обработаны или объявлены в throws (IOException, SQLException), и unchecked (runtime) — наследники RuntimeException, могут не обрабатываться (NullPointerException, IllegalArgumentException).


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологии сегодня — 15 апреля

ℹ️ Кто родился в этот день

Васи́лий Я́ковлевич Стру́ве (нем. Friedrich Georg Wilhelm Struve; 15 апреля 1793, Альтона, Германия — 11 [23] ноября 1864, Санкт-Петербург) — русско-немецкий астроном, один из основоположников звёздной астрономии в России. В области звёздной астрономии Струве открыл реальное сгущение звёзд к центральным частям Галактики и обосновал вывод о существовании и величине межзвёздного поглощения света. Много времени уделял Струве изучению двойных звёзд. Составленные им два каталога двойных звёзд были опубликованы в 1827 и 1852 годах. Струве принадлежит одно из первых в истории (1837) успешное измерение годичного параллакса звезды (Веги в созвездии Лиры). В середине XIX века участвовал в создании Лиссабонской астрономической обсерватории.


🌐 Знаковые события

1998 — на одном из заводов Intel изготовлен последний кристалл для процессора класса Pentium. Intel окончательно переходит с производства процессоров с архитектурой P5 под разъём Socket 7 на выпуск процессоров с архитектурой P6 для разъёма Slot 1. Официально объявлен новый процессор для «массовых» пользователей — Celeron.

2005 — с космодрома Байконур запущен космический корабль «Союз ТМА-6».


#Biography #Birth_Date #Events #15апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
[Совет по Java #026]

Тема: Синхронизация (synchronized) по строковой константе опасна.

Проблема: Строковые литералы и строки, полученные через intern(), попадают в пул строк (String Pool) и могут быть переиспользованы по всей JVM.

Если синхронизироваться на строковой константе, например synchronized("LOCK"), то блокировка становится глобальной для всего приложения. Любая другая часть кода, синхронизирующаяся на той же строке (даже по ошибке), будет конкурировать за один и тот же монитор.

Это приводит к неожиданным взаимоблокировкам, серьезным проблемам с производительностью и труднодиагностируемым багам, особенно в крупных проектах с множеством модулей.

Решение: Никогда не используйте строки в качестве объектов блокировки.

Всегда создавайте выделенный private final Object для синхронизации. Если требуется блокировка по имени ресурса, используйте ConcurrentHashMap с созданием уникальных объектов блокировки под каждое имя.

public class StringLockExample {

//Антипаттерн: синхронизация по строковой константе
private static final String LOCK = "LOCK"; // Попадает в пул строк

public void badMethod() {
synchronized (LOCK) { // Опасно! Другие модули могут использовать LOCK
// критическая секция
}
}

//Еще хуже: синхронизация по литералу
public void evenWorse() {
synchronized ("LOCK") { // Каждый раз один и тот же объект из пула
// Эта блокировка глобальна для всей JVM
}
}

//Решение 1: выделенный объект для блокировки
private final Object lock = new Object(); // Уникальный объект

public void goodMethod() {
synchronized (lock) {
// Только этот класс использует эту блокировку
}
}

//Решение 2: блокировка по имени с уникальными объектами
private final ConcurrentHashMap<String, ReentrantLock> lockMap = new ConcurrentHashMap<>();

public void lockByName(String resourceId) {
ReentrantLock lock = lockMap.computeIfAbsent(resourceId, k -> new ReentrantLock());
lock.lock();
try {
// работа с ресурсом resourceId
} finally {
lock.unlock();
}
}

//Решение 3: использование ReentrantLock с выделенным объектом
private final ReentrantLock reentrantLock = new ReentrantLock();

public void withReentrantLock() {
reentrantLock.lock();
try {
} finally {
reentrantLock.unlock();
}
}

// Демонстрация проблемы
public static void main(String[] args) {
// Модуль A
Thread t1 = new Thread(() -> {
synchronized ("SHARED") {
System.out.println("Модуль A захватил блокировку");
try { Thread.sleep(1000); } catch (InterruptedException e) {}
}
});

// Модуль B (совершенно другой класс, другая команда)
Thread t2 = new Thread(() -> {
synchronized ("SHARED") { // Та же строка из пула!
System.out.println("Модуль B захватил блокировку");
}
});

t1.start();
t2.start(); // Будет ждать, пока t1 не отпустит блокировку
// Два несвязанных модуля блокируют друг друга!
}
}


Объяснение: Строковые литералы интернируются автоматически. Это означает, что "LOCK" в одном месте и "LOCK" в другом — это один и тот же объект в памяти. Синхронизация по такому объекту создает глобальную блокировку на всю JVM, что может вызвать неожиданные взаимоблокировки между абсолютно несвязанными компонентами. Даже строки, созданные через new String("LOCK") без вызова intern(), могут быть проблемой, если где-то используется литерал.

Пул строк предназначен для экономии памяти, а не для синхронизации. Правильная практика — создавать приватные финальные объекты-заглушки private final Object lock = new Object(). Для блокировки по ключу используйте ConcurrentHashMap с ReentrantLock или synchronized(lockMap.computeIfAbsent(...)).

#Java #советы
👍5
Что выведет код?

public class Task150426 {
private static final String LOCK = "LOCK";

public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
synchronized (LOCK) {
System.out.print("A");
try { Thread.sleep(100); } catch (InterruptedException e) {}
System.out.print("B");
}
});

Thread t2 = new Thread(() -> {
synchronized ("LOCK") {
System.out.print("C");
System.out.print("D");
}
});

t1.start();
t2.start();
}
}


#Tasks
👍2
👍2
Как создать свой класс исключения? 🤓

Ответ:

Чтобы создать свое исключение, нужно унаследоваться от соответствующего класса в иерархии Throwable.

Для проверяемого (checked) исключения — расширять Exception (или его подкласс).

Для непроверяемого (unchecked) — расширять RuntimeException.

Рекомендуется создать несколько конструкторов (по умолчанию, с сообщением, с причиной — Throwable cause, комбинированный) и переиспользовать конструкторы суперкласса. Хорошая практика — делать класс исключения финальным или, по крайней мере, правильно документировать.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5