Java for Beginner
870 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
Раздел 9. Исключения, логирование, отладка

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

try-with-resources (Java 7+) – автоматическое закрытие AutoCloseable

До Java 7 управление ресурсами в Java было многословным и подверженным ошибкам. Каждый ресурс требовал явного закрытия в блоке finally, что приводило к "pyramid of doom" — вложенным структурам, где бизнес-логика терялась среди шаблонного кода. Попытка закрыть ресурс в finally могла привести к подавлению исключений: если основной блок и finally выбрасывали исключения, вызывающий код получал только исключение из finally, а оригинальная ошибка терялась .

Java 7 представила конструкцию try-with-resources — синтаксический сахар, который автоматизирует закрытие ресурсов и решает проблему подавления исключений через механизм suppressed exceptions. Это изменение было частью более широкого проекта Project Coin, направленного на повышение производительности разработчика через небольшие, но значимые улучшения языка.


Интерфейс AutoCloseable: контракт для ресурсов

Центральным элементом try-with-resources является интерфейс java.lang.AutoCloseable, введенный в Java 7 специально для поддержки этой конструкции.

Интерфейс объявляет единственный метод:
void close() throws Exception;


Ключевое отличие от старого интерфейса java.io.Closeable (JDK 5) — тип выбрасываемого исключения. Closeable.close() ограничен IOException, что делает его непригодным для ресурсов, требующих выброса других checked-исключений, таких как java.sql.Connection с его SQLException . Чтобы сохранить обратную совместимость, Closeable был модифицирован для наследования от AutoCloseable, переопределяя close() с более специфичным IOException.

Важные различия между интерфейсами:
Идемпотентность: Closeable требует, чтобы повторный вызов close() не имел эффекта; AutoCloseable не гарантирует этого, хотя настоятельно рекомендует
Тип исключения: Closeable — только IOException, AutoCloseable — любое Exception
Предназначение: Closeable специфичен для I/O, AutoCloseable — универсальный механизм для любых ресурсов

Документация Oracle рекомендует реализациям AutoCloseable не выбрасывать InterruptedException из close(), так как это взаимодействует со статусом прерывания потока и может привести к runtime-проблемам при подавлении исключения.


Базовый синтаксис и семантика

Конструкция try-with-resources объявляет ресурсы в круглых скобках сразу после ключевого слова try. Каждый ресурс должен реализовывать AutoCloseable или Closeable:
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}


В этом примере BufferedReader автоматически закрывается при выходе из блока try, независимо от того, как завершилось выполнение — нормально или через исключение. Переменная br является неявно final и доступна только внутри блока try.

Компилятор генерирует байткод, эквивалентный следующей структуре:
// Псевдокод, демонстрирующий трансформацию компилятором
BufferedReader br = new BufferedReader(new FileReader(path));
Throwable primaryException = null;
try {
return br.readLine();
} catch (Throwable t) {
primaryException = t;
throw t;
} finally {
if (br != null) {
if (primaryException != null) {
try {
br.close();
} catch (Throwable suppressed) {
primaryException.addSuppressed(suppressed);
}
} else {
br.close();
}
}
}


Эта трансформация обеспечивает два ключевых свойства: гарантированное закрытие ресурса и сохранение оригинального исключения.


#Java #для_новичков #beginner #exception #try_with_resources
👍4
Механизм suppressed exceptions

Когда исключение возникает как в основном блоке try, так и при закрытии ресурса, try-with-resources сохраняет оба исключения. Исключение из основного блока становится primary exception, а исключение из close() — suppressed exception, добавляемое к primary через метод Throwable.addSuppressed().

Пример демонстрирует это поведение:

public class ExceptionalResource implements AutoCloseable {
public void process() {
throw new IllegalArgumentException("Error in process()");
}

@Override
public void close() {
throw new NullPointerException("Error in close()");
}
}

public static void demoSuppressedException() throws Exception {
try (ExceptionalResource resource = new ExceptionalResource()) {
resource.process();
}
}


При вызове demoSuppressedException() будет выброшено IllegalArgumentException из process(), а NullPointerException из close() будет доступно как подавленное исключение:
try {
demoSuppressedException();
} catch (Exception e) {
assert e instanceof IllegalArgumentException;
assert e.getMessage().equals("Error in process()");
assert e.getSuppressed().length == 1;
assert e.getSuppressed()[0] instanceof NullPointerException;
}


Это поведение противоположно классическому try-finally, где исключение из finally подавляет исключение из try. Методы Throwable.getSuppressed() и addSuppressed() были добавлены в Java 7 специально для поддержки этой функциональности.


Множественные ресурсы и порядок закрытия

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


Ресурсы закрываются в обратном порядке их объявления: сначала fos, затем fis . Этот порядок критичен для корректного освобождения зависимых ресурсов — например, BufferedReader должен быть закрыт до закрытия underlying FileReader.

Если при закрытии нескольких ресурсов возникают исключения, все они добавляются как suppressed к primary exception:
try (Resource r1 = new Resource(); 
Resource r2 = new Resource()) {
throw new PrimaryException();
}
// Если r1.close() и r2.close() оба выбрасывают исключения,
// PrimaryException будет иметь два suppressed исключения



#Java #для_новичков #beginner #exception #try_with_resources
👍3
Интеграция с catch и finally

try-with-resources может сочетаться с традиционными catch и finally блоками. В этом случае ресурсы закрываются перед выполнением catch, а finally выполняется после закрытия всех ресурсов:
try (Resource resource = new Resource()) {
resource.process();
} catch (ProcessingException e) {
// Выполняется после закрытия resource
logger.error("Processing failed", e);
// Доступны suppressed исключения из resource.close()
for (Throwable suppressed : e.getSuppressed()) {
logger.warn("Suppressed during close", suppressed);
}
} finally {
// Выполняется после catch, ресурсы уже закрыты
metrics.incrementOperationCounter();
}


Важный нюанс: если явный finally блок выбрасывает исключение, оно подавляет все предыдущие исключения, включая primary и suppressed из try-with-resources . Это сохраняет семантику finally как последней инстанции.


Создание кастомных ресурсов

Любой класс, требующий явного cleanup, может реализовать AutoCloseable для интеграции с try-with-resources:
public class DatabaseConnectionPool implements AutoCloseable {
private final List<Connection> availableConnections;
private final List<Connection> inUseConnections;
private boolean closed = false;

public DatabaseConnectionPool(int size) {
this.availableConnections = new ArrayList<>(size);
this.inUseConnections = new ArrayList<>();
// Инициализация пула
}

public Connection acquireConnection() {
ensureOpen();
// Логика выдачи соединения
}

public void releaseConnection(Connection conn) {
ensureOpen();
// Логика возврата соединения
}

@Override
public void close() {
if (closed) {
return; // Идемпотентность рекомендуется
}
closed = true;

// Закрытие всех соединений
for (Connection conn : availableConnections) {
silentlyClose(conn);
}
for (Connection conn : inUseConnections) {
silentlyClose(conn);
}
}

private void ensureOpen() {
if (closed) {
throw new IllegalStateException("Pool is closed");
}
}

private void silentlyClose(Connection conn) {
try {
conn.close();
} catch (SQLException e) {
// Логирование, но не выброс — не блокируем закрытие остальных
logger.warn("Failed to close connection", e);
}
}
}


Использование:
public void processBatch(List<String> queries) {
try (DatabaseConnectionPool pool = new DatabaseConnectionPool(10)) {
for (String query : queries) {
Connection conn = pool.acquireConnection();
try {
executeQuery(conn, query);
} finally {
pool.releaseConnection(conn);
}
}
} // pool автоматически закрывается, все соединения освобождаются
}


Ограничения и особые случаи

Ресурсы, объявленные в try-with-resources, являются неявно final и не могут быть переназначены внутри блока . Это предотвращает случайную потерю ссылки на ресурс до его автоматического закрытия.
Если конструктор ресурса выбрасывает исключение, ресурс не добавляется в список для закрытия, и исключение распространяется как обычно. Это безопасно, так как ресурс не был создан.


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

public class Task160426 {
static class CloseableCounter160426 implements AutoCloseable {
private String id;
public CloseableCounter160426(String id) { this.id = id; }
public void close() throws Exception {
System.out.print(id);
throw new RuntimeException("close error: " + id);
}
}

public static void main(String[] args) {
try (CloseableCounter160426 c1 = new CloseableCounter160426("A");
CloseableCounter160426 c2 = new CloseableCounter160426("B")) {
throw new RuntimeException("body error");
} catch (Exception e) {
System.out.print(e.getMessage());
for (Throwable suppressed : e.getSuppressed()) {
System.out.print(suppressed.getMessage());
}
}
}
}


#Tasks
👍1
Что такое invokedynamic и зачем он нужен? 🤓

Ответ:

invokedynamic
(появился в Java 7) — это новая инструкция байт-кода, которая позволяет динамически связывать вызов метода в рантайме, а не на этапе компиляции.

Это ключевой механизм для реализации динамических языков на JVM.

В Java 8+ invokedynamic используется для реализации лямбда-выражений — вместо генерации анонимных классов на этапе компиляции, лямбды связываются динамически, что улучшает производительность и гибкость.


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

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

Джованни Баттиста Риччоли (итал. Giovanni Battista Riccioli; 17 апреля 1598, Феррара — 25 июня 1671, Болонья) — итальянский астроном и теолог, автор труда «Новый Альмагест» (Almagestum Novum) — свода астрономических знаний своего времени. Вместе с Франческо Гримальди составил карту Луны и ввёл в практику обозначение лунных кратеров именами учёных.


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

2014 – космический телескоп НАСА « Кеплер» подтвердил открытие первой планеты размером с Землю в обитаемой зоне другой звезды.


#Biography #Birth_Date #Events #17апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
This media is not supported in your browser
VIEW IN TELEGRAM
Обновил devforge.ru

Наладил работу рефреш токенов.

Заходите тестить - чат доступен и работает. 👋
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
[Совет по Java #027]

Тема: double и float не подходят для циклов с условием на равенство.

Проблема: Числа с плавающей запятой (float, double) не могут быть точно представлены в двоичной системе.

Значение 0.1 в двоичном виде — это бесконечная периодическая дробь, поэтому в памяти хранится его приближение. При многократном прибавлении 0.1 к 0.0 накопленная погрешность приводит к тому, что переменная никогда не станет точно равной 1.0. В результате условие d != 1.0 остается истинным всегда, и цикл становится бесконечным.

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

Решение: Никогда не используйте операторы равенства (==, !=) с числами с плавающей запятой в условиях циклов.

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

Для проверки близости используйте Math.abs(a - b) < epsilon.

public class FloatLoopProblem {

//Антипаттерн: бесконечный цикл
public static void badLoop() {
int iterations = 0;
for (double d = 0.0; d != 1.0; d += 0.1) {
iterations++;
System.out.printf("Итерация %d: %.20f%n", iterations, d);
if (iterations > 20) break; // защита от вечности
}
// Реальный вывод: d проходит через 0.0, 0.1, 0.2, ..., 0.9, 1.0000000000000002, ...
// Никогда не равно 1.0
}

//Ошибка с float
public static void badFloatLoop() {
for (float f = 0.0f; f != 1.0f; f += 0.1f) {
// Тоже бесконечный
}
}

//Решение 1: целочисленный счетчик
public static void goodLoopWithCounter() {
for (int i = 0; i <= 10; i++) {
double d = i * 0.1; // Вычисляем на каждой итерации
System.out.println("d = " + d);
}
}

//Решение 2: сравнение с эпсилон (допуском)
public static void goodLoopWithEpsilon() {
double d = 0.0;
final double EPSILON = 1e-10;
while (Math.abs(d - 1.0) > EPSILON) {
System.out.println("d = " + d);
d += 0.1;
}
System.out.println("Достигнуто: " + d);
}

//Решение 3: фиксированное количество итераций
public static void goodFixedIterations() {
int steps = 10;
for (int step = 0; step <= steps; step++) {
double ratio = (double) step / steps; // От 0.0 до 1.0
System.out.println(ratio);
}
}

// Демонстрация погрешности
public static void demonstratePrecision() {
double sum = 0.0;
for (int i = 0; i < 10; i++) {
sum += 0.1;
}
System.out.println("Сумма десяти 0.1: " + sum); // 0.9999999999999999
System.out.println("Сравнение с 1.0: " + (sum == 1.0)); // false
}

public static void main(String[] args) {
demonstratePrecision();
goodLoopWithCounter();
}
}


Объяснение:
Стандарт IEEE 754 определяет двоичное представление чисел с плавающей запятой. Десятичные дроби, не являющиеся суммой степеней двойки (например, 0.1 = 1/16 + 1/32 + 1/256 + ...), представляются бесконечным рядом, который обрезается до 53 бит мантиссы для double. Из-за этого ошибка округления накапливается.

В примере с циклом после десяти сложений получается не 1.0, а 0.9999999999999999. Условие d != 1.0 остается истинным, и цикл продолжается до бесконечности (точнее, до достижения бесконечности или переполнения).

Корректные подходы: использовать целочисленный счетчик (погрешность не накапливается, так как каждый раз вычисляется заново), применять сравнение с допустимой абсолютной погрешностью (epsilon), либо использовать BigDecimal для точных десятичных расчетов.

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

public class Task170426 {
public static void main(String[] args) {
double sum = 0;
for (double d = 0.0; d != 1.0; d += 0.1) {
sum += d;
}
System.out.println(sum);
}
}


#Tasks
👍2
Варианты ответа:
Anonymous Quiz
5%
4.5
16%
5.0
5%
45.0
74%
Бесконечный цикл
👍2
Что такое JMX (Java Management Extensions)? 🤓

Ответ:

JMX
— это технология для мониторинга и управления Java-приложениями.

Она позволяет в рантайме получать информацию о состоянии приложения (метрики, счетчики) и даже изменять параметры, не перезапуская приложение.

Основные понятия:
MBean (Managed Bean) — управляемый ресурс, который вы хотите мониторить;
MBean Server — реестр MBean'ов; адаптеры и коннекторы — для удаленного доступа (например, JConsole, VisualVM используют JMX).


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

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

Не нашел(


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

1953 — в Англии совершил первый коммерческий полёт первый в мире турбовинтовой самолёт.


#Biography #Birth_Date #Events #18апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
С 11.04 по 17.04
Предыдущий пост(с 04.04 по 10.04)

Воскресный мотивационный пост:
Что случилось и почему сайт не работал или хронология одного хренового утра

Запись встреч/видео:
В процессе подготовки...

Обучающие статьи:
Раздел 9. Исключения, логирование, отладка

Глава 1. Иерархия исключений (Exceptions)
try-catch-finally – правильная обработка и освобождение ресурсов
try-with-resources (Java 7+) – автоматическое закрытие AutoCloseable

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

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

[Совет по Java #027]
Тема: double и float не подходят для циклов с условием на равенство.

Полезные статьи и видео:
Где хранить код? Сравнение GitHub, GitLab и Bitbucket

Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
🔥3👍2
This media is not supported in your browser
VIEW IN TELEGRAM
Тестировщики они такие, да 😁
Please open Telegram to view this post
VIEW IN TELEGRAM
🤣3🤓1
🤣5
🗿3🤣1
🤓4🤣1
История технологии сегодня — 19 апреля

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

Андре́й Петро́вич Ершо́в (19 апреля 1931, Рубежное, Рубежанский район, Старобельский округ, УССР, Советский Союз — 8 декабря 1988, Новосибирск, Новосибирская область, Советский Союз)советский учёный, один из пионеров теоретического и системного программирования, создатель Сибирской школы информатики, академик АН СССР (1980). Его работы оказали влияние на формирование и развитие вычислительной техники не только в СССР, но и во всём мире.

Фредери́к Фи́ллипс Брукс-младший (англ. Frederick Phillips Brooks, Jr.; 19 апреля 1931, Дарем, Северная Каролина — 17 ноября 2022, Чапел-Хилл, Северная Каролина) — американский учёный в области теории вычислительных систем, автор книги «Мифический человеко-месяц». Управлял разработкой OS/360 в IBM. Награждён Премией Тьюринга в 1999 году.


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

1965 — Гордоном Муром сформулирован так называемый «закон Мура», согласно которому количество транзисторов в кристалле микропроцессора удваивается каждые два года.

2021 — вертолёт НАСА Ingenuity стал первым летательным аппаратом землян, совершившим полёт на другой планете.



#Biography #Birth_Date #Events #19апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1