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
Здесь важен порядок закрытия: ресурсы должны освобождаться в обратном порядке их создания. Вложенные 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
История технологии сегодня — 16 апреля

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

Алекса́ндр Ива́нович Макаре́вский (3 [16] апреля 1904, село Мушковичи, Смоленская губерния — 11 мая 1979, Москва) советский учёный в области прочности и аэроупругости летательных аппаратов. Свыше тридцати лет он руководил исследованиями ЦАГИ в области прочности. Под его руководством по существу сформировались основные разделы науки о прочности самолётов: статическая прочность, нормы прочности, оценка долговечности конструкций или ресурса, аэроупругость. Будучи учёным широкого профиля, внёс личный вклад во все эти разделы.

Уилбер Райт (англ. Wilbur Wright (1867—1912) американский изобретатель, авиаконструктор, лётчик, старший из братьев — пионеров воздухоплавания. Фундаментальное достижение братьев Райт — практичные системы управления и устойчивости по трём осям вращения самолёта, чтобы эффективно управлять самолётом и поддерживать его равновесие во время полёта. Их подход стал основой для конструирования и постройки самолётов. Братья Райт сосредоточились на изучении вопросов управления летящим аппаратом, вместо того, чтобы находить возможность устанавливать более мощные двигатели, как это делали другие экспериментаторы. Их эксперименты в аэродинамической трубе оказались плодотворнее, чем эксперименты других пионеров авиации, для создания эффективного крыла и пропеллеров.

Джон Хэдли (англ. John Hadley, рус. Гадле́й; 16 апреля 1682 — 14 февраля 1744) — английский математик, более всего известный изобретением октанта, предшественника секстанта, около 1730 года. Американец Томас Годфри изобрёл октант примерно в то же время и независимо от него.

Алексе́й Леони́дович Па́житнов (род. 16 апреля 1955, Москва, РСФСР, СССР)
— советский и американский программист и геймдизайнер. Наиболее известен тем, что в 1984 году, работая в Вычислительном центре им. Дородницына при Академии наук СССР, спроектировал и разработал игру «Тетрис».


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

1863 — во Франции спущена на воду Plongeur (с фр. — «Ныряльщик») — самая большая подводная лодка XIX века.

1906 — завершена прокладка подводного телеграфного кабеля между США и Китаем.

1972 — стартовала пятая экспедиция по программе «Аполлон» с высадкой на поверхность Луны (состоявшейся 20 апреля); командир — астронавт Джон Янг.



#Biography #Birth_Date #Events #16апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Раздел 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