С 18.04 по 24.04
Предыдущий пост(с 11.04 по 17.04)
Запись встреч/видео:
11. Fallback и graceful degradation — когда всё сломалось, но пользователь этого не заметил
Обучающие статьи:
Раздел 9. Исключения, логирование, отладка
Глава 1. Иерархия исключений (Exceptions)
throws в сигнатуре метода – проброс исключений наверх. Когда это оправдано
Создание своих исключений: наследование от Exception или RuntimeException. Когда кастомное исключение оправдано
Несколько ресурсов в try-with-resources: порядок закрытия и effectively final переменные (Java 9+)
[Совет по Java #028]
Тема: static-методы не переопределяются.
[Совет по Java #029]
Тема: Class.forName() загружает класс и инициализирует статические блоки.
Полезные статьи и видео:
Circuit Breaker в микросервисах: как защитить систему от каскадных отказов
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
Предыдущий пост(с 11.04 по 17.04)
Запись встреч/видео:
11. Fallback и graceful degradation — когда всё сломалось, но пользователь этого не заметил
Обучающие статьи:
Раздел 9. Исключения, логирование, отладка
Глава 1. Иерархия исключений (Exceptions)
throws в сигнатуре метода – проброс исключений наверх. Когда это оправдано
Создание своих исключений: наследование от Exception или RuntimeException. Когда кастомное исключение оправдано
Несколько ресурсов в try-with-resources: порядок закрытия и effectively final переменные (Java 9+)
[Совет по Java #028]
Тема: static-методы не переопределяются.
[Совет по Java #029]
Тема: Class.forName() загружает класс и инициализирует статические блоки.
Полезные статьи и видео:
Circuit Breaker в микросервисах: как защитить систему от каскадных отказов
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
👍3🔥1
Вакансия.
Я вот чего-то в этой жизни не понимаю.
Как у джуна может быть 2-3 года опыта с высоконагруженными приложениями?
Kafka/RabbitMQ....
предстоит заниматься: Проводить перекрестный в code review; - это издёвка такая? Как джун может проводить перекрестное code review?
"ЧТО У ВАС ТУТ ПРОИСХОДИТ ?!" - спрашиваю как герой смешного мема.
Но мне бл не смешно как то.
Я по приколу откликнулся - уверен что получу ботовский отказ))))
Я вот чего-то в этой жизни не понимаю.
Как у джуна может быть 2-3 года опыта с высоконагруженными приложениями?
Kafka/RabbitMQ....
предстоит заниматься: Проводить перекрестный в code review; - это издёвка такая? Как джун может проводить перекрестное code review?
"ЧТО У ВАС ТУТ ПРОИСХОДИТ ?!" - спрашиваю как герой смешного мема.
Но мне бл не смешно как то.
Я по приколу откликнулся - уверен что получу ботовский отказ))))
😱8
This media is not supported in your browser
VIEW IN TELEGRAM
Вот оно будущее...☺️
Please open Telegram to view this post
VIEW IN TELEGRAM
😱2
История технологии сегодня — 26 апреля
ℹ️ Кто родился в этот день
Арно Аллан Пе́нзиас (англ. Arno Allan Penzias; 26 апреля 1933, Мюнхен — 22 января 2024, Сан-Франциско) — американский астрофизик, профессор, лауреат Нобелевской премии по физике (1978) за открытие космического микроволнового фонового излучения. Построив приёмник, способный детектировать излучение с длиной волны порядка миллиметра и присоединив его к 36-футовому радиотелескопу, Пензиас и Вильсон обнаружили в 1970 году спектральную линию окиси углерода в области туманности Ориона, а затем ещё шесть межзвёздных молекул. Открытие и исследование межзвёздных молекулярных облаков способствовало прогрессу в понимании образования и эволюции звёзд и галактик.
🌐 Знаковые события
1986 — авария на Чернобыльской АЭС, одна из крупнейших техногенных катастроф в истории человечества.
1994 — американские учёные из Национальной лаборатории им. Ферми представили доказательства того, что ими обнаружен последний, шестой кварк (Top или t-кварк), поиск которого вёлся в течение 20 лет.
1999 — компьютерный вирус «Чернобыль» поразил, по разным оценкам, до полумиллиона компьютеров по всему миру.
#Biography #Birth_Date #Events #26апреля
Арно Аллан Пе́нзиас (англ. Arno Allan Penzias; 26 апреля 1933, Мюнхен — 22 января 2024, Сан-Франциско) — американский астрофизик, профессор, лауреат Нобелевской премии по физике (1978) за открытие космического микроволнового фонового излучения. Построив приёмник, способный детектировать излучение с длиной волны порядка миллиметра и присоединив его к 36-футовому радиотелескопу, Пензиас и Вильсон обнаружили в 1970 году спектральную линию окиси углерода в области туманности Ориона, а затем ещё шесть межзвёздных молекул. Открытие и исследование межзвёздных молекулярных облаков способствовало прогрессу в понимании образования и эволюции звёзд и галактик.
1986 — авария на Чернобыльской АЭС, одна из крупнейших техногенных катастроф в истории человечества.
1994 — американские учёные из Национальной лаборатории им. Ферми представили доказательства того, что ими обнаружен последний, шестой кварк (Top или t-кварк), поиск которого вёлся в течение 20 лет.
1999 — компьютерный вирус «Чернобыль» поразил, по разным оценкам, до полумиллиона компьютеров по всему миру.
#Biography #Birth_Date #Events #26апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
This media is not supported in your browser
VIEW IN TELEGRAM
Ребят, у меня к вам вопрос - что еще реализовать на нашем сайте devforge.ru, чтобы Вам хотелось постоянно им пользоваться?
Общение? Обучающий курс? Кладовка с мемами?
Пишите, не стесняйтесь, давайте обсудим?
Общение? Обучающий курс? Кладовка с мемами?
Пишите, не стесняйтесь, давайте обсудим?
👍4
История технологии сегодня — 27 апреля
ℹ️ Кто родился в этот день
Сэ́мюэл Фи́нли Бриз Мо́рзе (англ. Samuel Finley Breese Morse [mɔːrs]; 27 апреля 1791, Чарльзтаун в штате Массачусетс — 2 апреля 1872, Нью-Йорк) — американский изобретатель и художник. Наиболее известные изобретения — электромагнитный пишущий телеграф («аппарат Морзе», 1836) и код (азбука) Морзе.
Филип Хауге Абельсон (27 апреля 1913 — 1 августа 2004) — американский физик , научный редактор и научный писатель . Получив образование в области ядерной физики , он стал одним из первооткрывателей элемента нептуния , работал над разделением изотопов в рамках Манхэттенского проекта и написал первое исследование ядерных морских двигателей для подводных лодок.
Фрэнк Уильям Абагнейл-младший ( / ˈ æ b ə ɡ n eɪ l / ; родился 27 апреля 1948 г.) — американо-французский консультант по безопасности, писатель и осужденный преступник, чьи задокументированные преступления в основном заключаются в мошенничестве с чеками и мелком воровстве, направленном против частных лиц и малых предприятий.
Начиная с конца 1970-х годов, Абагнейл утверждал, что его криминальное прошлое было гораздо более драматичным, включая длительные выдачи себя за пилота Pan American World Airways, врача больницы в Джорджии и помощника генерального прокурора Луизианы, среди прочих ролей. Эти утверждения легли в основу его автобиографии 1980 года «Поймай меня, если сможешь», написанной в соавторстве со Стэном Реддингом. Книга вдохновила на создание одноименного фильма, снятого Стивеном Спилбергом в 2002 году, в котором Абагнейла сыграл Леонардо Ди Каприо.
//Мне просто фильм нравится)
🌐 Знаковые события
2005 — первый полёт совершил авиалайнер Airbus А380.
#Biography #Birth_Date #Events #27апреля
Сэ́мюэл Фи́нли Бриз Мо́рзе (англ. Samuel Finley Breese Morse [mɔːrs]; 27 апреля 1791, Чарльзтаун в штате Массачусетс — 2 апреля 1872, Нью-Йорк) — американский изобретатель и художник. Наиболее известные изобретения — электромагнитный пишущий телеграф («аппарат Морзе», 1836) и код (азбука) Морзе.
Филип Хауге Абельсон (27 апреля 1913 — 1 августа 2004) — американский физик , научный редактор и научный писатель . Получив образование в области ядерной физики , он стал одним из первооткрывателей элемента нептуния , работал над разделением изотопов в рамках Манхэттенского проекта и написал первое исследование ядерных морских двигателей для подводных лодок.
Фрэнк Уильям Абагнейл-младший ( / ˈ æ b ə ɡ n eɪ l / ; родился 27 апреля 1948 г.) — американо-французский консультант по безопасности, писатель и осужденный преступник, чьи задокументированные преступления в основном заключаются в мошенничестве с чеками и мелком воровстве, направленном против частных лиц и малых предприятий.
Начиная с конца 1970-х годов, Абагнейл утверждал, что его криминальное прошлое было гораздо более драматичным, включая длительные выдачи себя за пилота Pan American World Airways, врача больницы в Джорджии и помощника генерального прокурора Луизианы, среди прочих ролей. Эти утверждения легли в основу его автобиографии 1980 года «Поймай меня, если сможешь», написанной в соавторстве со Стэном Реддингом. Книга вдохновила на создание одноименного фильма, снятого Стивеном Спилбергом в 2002 году, в котором Абагнейла сыграл Леонардо Ди Каприо.
//Мне просто фильм нравится)
2005 — первый полёт совершил авиалайнер Airbus А380.
#Biography #Birth_Date #Events #27апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
[Совет по Java #030]
Тема: try-with-resources закрывает ресурсы в обратном порядке объявления.
Проблема: Конструкция try-with-resources автоматически закрывает ресурсы в порядке, обратном их объявлению.
Если ресурсы имеют зависимости (например, один ресурс создан на основе другого), закрытие в неправильном порядке может привести к исключениям или некорректному состоянию.
Классический пример: PrintWriter оборачивает FileOutputStream — если сначала закрыть FileOutputStream, то PrintWriter не сможет сбросить буфер при своем закрытии, и данные будут потеряны.
Решение: Всегда объявляйте ресурсы в порядке их создания (от внешнего к внутреннему). try-with-resources сам гарантирует корректный порядок закрытия: последний объявленный ресурс будет закрыт первым. Если ресурсы не зависят друг от друга, порядок не критичен, но хорошей практикой является объявление их в логическом порядке. Для сложных сценариев используйте вложенные try-with-resources или ручное управление.
Объяснение: try-with-resources генерирует код, который закрывает ресурсы в обратном порядке объявления.
Это соответствует принципу "последний пришел — первый ушел" (LIFO). Для вложенных ресурсов (когда один оборачивает другой) правильный порядок закрытия — сначала обертка, затем базовый ресурс, чтобы дать обертке возможность сбросить буферы или выполнить финальные операции.
#Java #советы
Тема: try-with-resources закрывает ресурсы в обратном порядке объявления.
Проблема: Конструкция try-with-resources автоматически закрывает ресурсы в порядке, обратном их объявлению.
Если ресурсы имеют зависимости (например, один ресурс создан на основе другого), закрытие в неправильном порядке может привести к исключениям или некорректному состоянию.
Классический пример: PrintWriter оборачивает FileOutputStream — если сначала закрыть FileOutputStream, то PrintWriter не сможет сбросить буфер при своем закрытии, и данные будут потеряны.
Решение: Всегда объявляйте ресурсы в порядке их создания (от внешнего к внутреннему). try-with-resources сам гарантирует корректный порядок закрытия: последний объявленный ресурс будет закрыт первым. Если ресурсы не зависят друг от друга, порядок не критичен, но хорошей практикой является объявление их в логическом порядке. Для сложных сценариев используйте вложенные try-with-resources или ручное управление.
public class TryWithResourcesOrder {
//Антипаттерн: ресурсы объявлены в неправильном порядке
public static void badOrder() throws IOException {
// Сначала создается FileOutputStream, потом BufferedOutputStream
// Но объявлены наоборот!
try (BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("file.txt"));
FileOutputStream fos = new FileOutputStream("file.txt")) {
// Ошибка: FileOutputStream будет закрыт ПОСЛЕ BufferedOutputStream?
// Нет, порядок закрытия: fos -> bos (обратный объявлению)
// Но bos обертывает fos — проблема!
bos.write("Hello".getBytes());
} // При закрытии bos попытается сбросить буфер в уже закрытый fos
}
//Правильно: порядок объявления соответствует вложению
public static void goodOrder() throws IOException {
// Внешний ресурс объявлен первым, внутренний — последним
try (FileOutputStream fos = new FileOutputStream("file.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
PrintWriter writer = new PrintWriter(bos)) {
writer.println("Hello, World!");
writer.flush();
// Порядок закрытия: writer -> bos -> fos (обратный объявлению)
// Корректно: сначала буферы сбрасываются, потом закрываются потоки
}
}
// Демонстрация порядка закрытия
static class ResourceA implements AutoCloseable {
ResourceA() { System.out.println("ResourceA created"); }
@Override public void close() { System.out.println("ResourceA closed"); }
}
static class ResourceB implements AutoCloseable {
private final ResourceA dependsOn;
ResourceB(ResourceA a) {
this.dependsOn = a;
System.out.println("ResourceB created (depends on A)");
}
@Override public void close() {
System.out.println("ResourceB closed (using A)");
}
}
public static void demonstrateOrder() {
try (ResourceA a = new ResourceA();
ResourceB b = new ResourceB(a)) {
System.out.println("Inside try block");
}
// Вывод:
// ResourceA created
// ResourceB created (depends on A)
// Inside try block
// ResourceB closed (using A)
// ResourceA closed
// B закрывается первым, хотя может зависеть от A — это безопасно
}
public static void main(String[] args) throws Exception {
demonstrateOrder();
goodOrder();
jdbcExample();
}
}Объяснение: try-with-resources генерирует код, который закрывает ресурсы в обратном порядке объявления.
Это соответствует принципу "последний пришел — первый ушел" (LIFO). Для вложенных ресурсов (когда один оборачивает другой) правильный порядок закрытия — сначала обертка, затем базовый ресурс, чтобы дать обертке возможность сбросить буферы или выполнить финальные операции.
#Java #советы
👍5
Что выведет код?
#Tasks
public class Task270426 {
static class ResourceA270426 implements AutoCloseable {
void use() { System.out.print("A"); }
public void close() { System.out.print("closeA"); }
}
static class ResourceB270426 implements AutoCloseable {
ResourceB270426(ResourceA270426 a) { a.use(); }
public void close() { System.out.print("closeB"); }
}
public static void main(String[] args) {
try (ResourceA270426 a = new ResourceA270426();
ResourceB270426 b = new ResourceB270426(a)) {
System.out.print("use");
}
}
}#Tasks
👍2
Варианты ответа:
Anonymous Quiz
33%
AusecloseAcloseB
50%
useAcloseBcloseA
0%
AusecloseBcloseA
17%
useAcloseAcloseB
👍2
Что такое package в Java? Зачем они нужны? 🤓
Ответ:
package — это механизм группировки классов и интерфейсов.
Назначение:
1) избежание конфликтов имен (классы с одинаковым именем могут существовать в разных пакетах).
2) управление доступом (модификатор default виден внутри пакета).
3) логическая структуризация проекта. Соглашение об именах: используется перевернутое доменное имя компании (например, com.company.project.module).
Физически пакет соответствует структуре директорий.
#собеседование
Ответ:
Назначение:
1) избежание конфликтов имен (классы с одинаковым именем могут существовать в разных пакетах).
2) управление доступом (модификатор default виден внутри пакета).
3) логическая структуризация проекта. Соглашение об именах: используется перевернутое доменное имя компании (например, com.company.project.module).
Физически пакет соответствует структуре директорий.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История технологии сегодня — 28 апреля
ℹ️ Кто родился в этот день
Дми́трий Бори́сович Зими́н (28 апреля 1933, Москва, РСФСР, СССР — 22 декабря 2021, Швейцария) — российский предприниматель, основатель и почётный президент компании «Вымпел-Коммуникации» (торговая марка — «Билайн»), учёный-радиотехник, доктор технических наук.
И́ан Э́шли Мёрдок (англ. Ian Ashley Murdock; 28 апреля 1973, Констанц — 28 декабря 2015, Сан-Франциско, Калифорния) — основатель проекта Debian и коммерческого дистрибутива Progeny Debian.
Курт Фри́дрих Гёдель (нем. Kurt Friedrich Gödel; 28 апреля 1906, Брюнн, Австро-Венгрия — 14 января 1978, Принстон, Нью-Джерси) — австрийский логик, математик и философ математики. Наиболее известен сформулированными и доказанными им теоремами о неполноте, которые оказали огромное влияние на представление об основаниях математики. Считается одним из наиболее выдающихся мыслителей XX века.
Никола́й Алекса́ндрович А́стров (1906—1992) — советский инженер-конструктор бронетехники. На военной службе с 1945 года. Герой Социалистического Труда (1976). До ухода на пенсию в 1985 году в должности главного конструктора ММЗ возглавлял разработку авиадесантных самоходных установок АСУ-57 и АСУ-85, самоходной установки ЗСУ-23-4 зенитного артиллерийского комплекса «Шилка», артиллерийского тягача АТП, шасси под зенитные ракетные комплексы «Куб», «Бук», «Тор» и «Тунгуска».
Ферру́ччо Ламборги́ни (итал. Ferruccio Lamborghini; 28 апреля 1916 года, Ченто, Феррара, Италия — 20 февраля 1993 года, Перуджа, Италия) — итальянский промышленник и бизнесмен, основатель Lamborghini Trattori, Automobili Lamborghini и ещё ряда компаний.
🌐 Знаковые события
2001 — полёт первого космического туриста — американца Денниса Тито.
#Biography #Birth_Date #Events #28апреля
Дми́трий Бори́сович Зими́н (28 апреля 1933, Москва, РСФСР, СССР — 22 декабря 2021, Швейцария) — российский предприниматель, основатель и почётный президент компании «Вымпел-Коммуникации» (торговая марка — «Билайн»), учёный-радиотехник, доктор технических наук.
И́ан Э́шли Мёрдок (англ. Ian Ashley Murdock; 28 апреля 1973, Констанц — 28 декабря 2015, Сан-Франциско, Калифорния) — основатель проекта Debian и коммерческого дистрибутива Progeny Debian.
Курт Фри́дрих Гёдель (нем. Kurt Friedrich Gödel; 28 апреля 1906, Брюнн, Австро-Венгрия — 14 января 1978, Принстон, Нью-Джерси) — австрийский логик, математик и философ математики. Наиболее известен сформулированными и доказанными им теоремами о неполноте, которые оказали огромное влияние на представление об основаниях математики. Считается одним из наиболее выдающихся мыслителей XX века.
Никола́й Алекса́ндрович А́стров (1906—1992) — советский инженер-конструктор бронетехники. На военной службе с 1945 года. Герой Социалистического Труда (1976). До ухода на пенсию в 1985 году в должности главного конструктора ММЗ возглавлял разработку авиадесантных самоходных установок АСУ-57 и АСУ-85, самоходной установки ЗСУ-23-4 зенитного артиллерийского комплекса «Шилка», артиллерийского тягача АТП, шасси под зенитные ракетные комплексы «Куб», «Бук», «Тор» и «Тунгуска».
Ферру́ччо Ламборги́ни (итал. Ferruccio Lamborghini; 28 апреля 1916 года, Ченто, Феррара, Италия — 20 февраля 1993 года, Перуджа, Италия) — итальянский промышленник и бизнесмен, основатель Lamborghini Trattori, Automobili Lamborghini и ещё ряда компаний.
2001 — полёт первого космического туриста — американца Денниса Тито.
#Biography #Birth_Date #Events #28апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Раздел 9. Исключения, логирование, отладка
Глава 1. Иерархия исключений (Exceptions)
Исключения в лямбдах, Stream API, конструкторах и статических блоках
Java предоставляет единый механизм исключений на базе класса Throwable, но поведение этого механизма существенно различается в зависимости от контекста выполнения. Лямбда-выражения и Stream API, появившиеся в Java 8, наложили архитектурные ограничения на использование checked-исключений, требуя от разработчиков поиска обходных стратегий. Конструкторы и статические блоки инициализации представляют собой особые точки жизненного цикла класса, где исключения ведут себя нестандартно и требуют специфического подхода к управлению ресурсами и обработке ошибок.
Часть первая. Исключения в лямбдах и Stream API
Функциональные интерфейсы Java 8 — Function<T,R>, Consumer<T>, Supplier<T>, Predicate<T> и другие — объявляют свои абстрактные методы без throws. Это означает, что любой метод, выбрасывающий checked-исключение, не может быть использован напрямую как лямбда-выражение или method reference в контексте Stream API.
Это ограничение не является oversight в дизайне языка, а отражает фундаментальную несовместимость checked-исключений с функциональным программированием. В функциональном стиле функции рассматриваются как значения, которые можно передавать, комбинировать и композировать. Checked-исключения нарушают эту композицию, требуя явной обработки на каждом уровне трансформации.
Стратегия первая: обёртка в try-catch внутри лямбды
Наиболее прямолинейный подход — обернуть вызов метода с checked-исключением в try-catch блок внутри лямбды и транслировать checked в unchecked:
Этот подход работает, но имеет серьезные недостатки. Во-первых, он загромождает код шаблонной обработкой исключений, разрушая лаконичность функционального стиля. Во-вторых, выброс RuntimeException из лямбды в Stream API прерывает весь конвейер — невозможно обработать ошибку для одного элемента и продолжить обработку остальных. В-третьих, исключение теряет семантику checked, и вызывающий код может не осознавать возможность сбоя.
Для сценариев, где требуется игнорировать ошибки и продолжить обработку, можно возвращать значение по умолчанию:
Здесь NumberFormatException — unchecked-исключение, но паттерн применим и к checked. Фильтрация Objects::nonNull удаляет null-значения, соответствующие ошибкам парсинга. Однако этот подход имеет побочный эффект: информация об ошибках теряется без логирования.
Улучшенная версия с логированием:
#Java #для_новичков #beginner #exception
Глава 1. Иерархия исключений (Exceptions)
Исключения в лямбдах, Stream API, конструкторах и статических блоках
Java предоставляет единый механизм исключений на базе класса Throwable, но поведение этого механизма существенно различается в зависимости от контекста выполнения. Лямбда-выражения и Stream API, появившиеся в Java 8, наложили архитектурные ограничения на использование checked-исключений, требуя от разработчиков поиска обходных стратегий. Конструкторы и статические блоки инициализации представляют собой особые точки жизненного цикла класса, где исключения ведут себя нестандартно и требуют специфического подхода к управлению ресурсами и обработке ошибок.
Часть первая. Исключения в лямбдах и Stream API
Функциональные интерфейсы Java 8 — Function<T,R>, Consumer<T>, Supplier<T>, Predicate<T> и другие — объявляют свои абстрактные методы без throws. Это означает, что любой метод, выбрасывающий checked-исключение, не может быть использован напрямую как лямбда-выражение или method reference в контексте Stream API.
// Метод с checked-исключением
public String fetchUrl(String url) throws IOException {
return httpClient.fetch(url);
}
// Ошибка компиляции: unreported exception IOException
List<String> urls = List.of("http://api1.com", "http://api2.com");
List<String> results = urls.stream()
.map(this::fetchUrl) // Не компилируется
.collect(Collectors.toList());
Это ограничение не является oversight в дизайне языка, а отражает фундаментальную несовместимость checked-исключений с функциональным программированием. В функциональном стиле функции рассматриваются как значения, которые можно передавать, комбинировать и композировать. Checked-исключения нарушают эту композицию, требуя явной обработки на каждом уровне трансформации.
Стратегия первая: обёртка в try-catch внутри лямбды
Наиболее прямолинейный подход — обернуть вызов метода с checked-исключением в try-catch блок внутри лямбды и транслировать checked в unchecked:
List<String> results = urls.stream()
.map(url -> {
try {
return fetchUrl(url);
} catch (IOException e) {
throw new RuntimeException("Failed to fetch: " + url, e);
}
})
.collect(Collectors.toList());
Этот подход работает, но имеет серьезные недостатки. Во-первых, он загромождает код шаблонной обработкой исключений, разрушая лаконичность функционального стиля. Во-вторых, выброс RuntimeException из лямбды в Stream API прерывает весь конвейер — невозможно обработать ошибку для одного элемента и продолжить обработку остальных. В-третьих, исключение теряет семантику checked, и вызывающий код может не осознавать возможность сбоя.
Для сценариев, где требуется игнорировать ошибки и продолжить обработку, можно возвращать значение по умолчанию:
// Парсинг чисел из списка строк с игнорированием ошибок
List<String> rawValues = List.of("42", "invalid", "17", "3.14", "100");
List<Integer> parsedNumbers = rawValues.stream()
.map(s -> {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
// Возвращаем null для невалидных значений
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
// Результат: [42, 17, 100]
Здесь NumberFormatException — unchecked-исключение, но паттерн применим и к checked. Фильтрация Objects::nonNull удаляет null-значения, соответствующие ошибкам парсинга. Однако этот подход имеет побочный эффект: информация об ошибках теряется без логирования.
Улучшенная версия с логированием:
List<Integer> parsedNumbers = rawValues.stream()
.map(s -> {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
logger.warn("Failed to parse integer from '{}'", s);
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
#Java #для_новичков #beginner #exception
👍2
Стратегия вторая: кастомный функциональный интерфейс с throws
Для сохранения семантики checked-исключений и повторного использования обработки можно создать собственные функциональные интерфейсы, объявляющие throws:
Однако эти интерфейсы несовместимы со стандартным Stream API. Для интеграции требуется обёртка, транслирующая кастомный интерфейс в стандартный:
Этот подход сохраняет чистоту вызова, но по-прежнему теряет checked-семантику на границе обёртки.
#Java #для_новичков #beginner #exception
Для сохранения семантики checked-исключений и повторного использования обработки можно создать собственные функциональные интерфейсы, объявляющие throws:
@FunctionalInterface
public interface ThrowingFunction<T, R, E extends Exception> {
R apply(T t) throws E;
}
@FunctionalInterface
public interface ThrowingConsumer<T, E extends Exception> {
void accept(T t) throws E;
}
@FunctionalInterface
public interface ThrowingSupplier<T, E extends Exception> {
T get() throws E;
}
Эти интерфейсы позволяют объявлять методы, принимающие функциональные объекты с checked-исключениями:
java
Copy
public <T, R, E extends Exception> List<R> mapWithException(
List<T> list,
ThrowingFunction<T, R, E> function) throws E {
List<R> result = new ArrayList<>();
for (T item : list) {
result.add(function.apply(item));
}
return result;
}
// Использование
List<String> urls = List.of("http://api1.com", "http://api2.com");
try {
List<String> contents = mapWithException(urls, this::fetchUrl);
} catch (IOException e) {
// Обработка ошибки
}
Однако эти интерфейсы несовместимы со стандартным Stream API. Для интеграции требуется обёртка, транслирующая кастомный интерфейс в стандартный:
public static <T, E extends Exception> Consumer<T> throwingConsumerWrapper(
ThrowingConsumer<T, E> throwingConsumer) {
return item -> {
try {
throwingConsumer.accept(item);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
};
}
// Использование
urls.forEach(throwingConsumerWrapper(url -> {
writeToFile(url); // Метод, объявляющий throws IOException
}));
Этот подход сохраняет чистоту вызова, но по-прежнему теряет checked-семантику на границе обёртки.
#Java #для_новичков #beginner #exception
👍2
Стратегия третья: sneaky throws
Sneaky throws — техника, позволяющая выбросить checked-исключение без объявления его в сигнатуре метода, используя особенности generics и стирания типов в Java:
Механизм работает благодаря стиранию типов: компилятор не может проверить, что E не является RuntimeException, поэтому разрешает выброс без throws. Однако это крайне опасная практика. Вызывающий код не знает о возможности checked-исключения и не обрабатывает его. JVM вынуждена обрабатывать исключение как unchecked, что нарушает контракт типов и может привести к непредсказуемому поведению при межпроцессном взаимодействии или сериализации.
Sneaky throws оправдан только в крайне специфических сценариях: библиотечный код, полностью контролирующий контекст выполнения, или временный рефакторинг legacy-систем. В production-коде этот паттерн следует избегать.
Стратегия четвертая: Either и Try из функциональных библиотек
Наиболее элегантный подход для функциональной обработки ошибок — использование типов-результатов из библиотек вроде Vavr или самостоятельная реализация. Вместо выброса исключений метод возвращает объект, явно моделирующий два состояния: успех или ошибку.
Применение для парсинга с сохранением ошибок:
Этот подход полностью устраняет исключения из потока управления, превращая их в значения. Клиентский код вынужден обрабатывать оба случая, что устраняет риск "забытого catch". Библиотека Vavr предоставляет готовую реализацию io.vavr.control.Either и io.vavr.control.Try с богатым API для композиции и обработки результатов.
#Java #для_новичков #beginner #exception
Sneaky throws — техника, позволяющая выбросить checked-исключение без объявления его в сигнатуре метода, используя особенности generics и стирания типов в Java:
@SuppressWarnings("unchecked")
public static <E extends Throwable> void sneakyThrow(Throwable e) throws E {
throw (E) e;
}
// Использование в лямбде
List<String> results = urls.stream()
.map(url -> {
try {
return fetchUrl(url);
} catch (IOException e) {
sneakyThrow(e); // Компилятор не требует throws
return null; // Недостижимый код, необходим для компиляции
}
})
.collect(Collectors.toList());Механизм работает благодаря стиранию типов: компилятор не может проверить, что E не является RuntimeException, поэтому разрешает выброс без throws. Однако это крайне опасная практика. Вызывающий код не знает о возможности checked-исключения и не обрабатывает его. JVM вынуждена обрабатывать исключение как unchecked, что нарушает контракт типов и может привести к непредсказуемому поведению при межпроцессном взаимодействии или сериализации.
Sneaky throws оправдан только в крайне специфических сценариях: библиотечный код, полностью контролирующий контекст выполнения, или временный рефакторинг legacy-систем. В production-коде этот паттерн следует избегать.
Стратегия четвертая: Either и Try из функциональных библиотек
Наиболее элегантный подход для функциональной обработки ошибок — использование типов-результатов из библиотек вроде Vavr или самостоятельная реализация. Вместо выброса исключений метод возвращает объект, явно моделирующий два состояния: успех или ошибку.
// Упрощенная реализация Either (левая сторона — ошибка, правая — успех)
public class Either<L, R> {
private final L left;
private final R right;
private final boolean isLeft;
private Either(L left, R right, boolean isLeft) {
this.left = left;
this.right = right;
this.isLeft = isLeft;
}
public static <L, R> Either<L, R> left(L value) {
return new Either<>(value, null, true);
}
public static <L, R> Either<L, R> right(R value) {
return new Either<>(null, value, false);
}
public boolean isLeft() { return isLeft; }
public boolean isRight() { return !isLeft; }
public L getLeft() { return left; }
public R getRight() { return right; }
}
Применение для парсинга с сохранением ошибок:
public Either<String, Integer> parseInteger(String input) {
try {
return Either.right(Integer.parseInt(input));
} catch (NumberFormatException e) {
return Either.left("Invalid number format: " + input);
}
}
// Обработка в Stream API
List<String> rawValues = List.of("42", "invalid", "17", "not_a_number", "100");
List<Either<String, Integer>> results = rawValues.stream()
.map(this::parseInteger)
.collect(Collectors.toList());
List<Integer> successes = results.stream()
.filter(Either::isRight)
.map(Either::getRight)
.collect(Collectors.toList());
List<String> failures = results.stream()
.filter(Either::isLeft)
.map(Either::getLeft)
.collect(Collectors.toList());Этот подход полностью устраняет исключения из потока управления, превращая их в значения. Клиентский код вынужден обрабатывать оба случая, что устраняет риск "забытого catch". Библиотека Vavr предоставляет готовую реализацию io.vavr.control.Either и io.vavr.control.Try с богатым API для композиции и обработки результатов.
#Java #для_новичков #beginner #exception
👍2
Практический пример: парсинг чисел с игнорированием ошибок
Объединим подходы в комплексном примере. Задача: преобразовать список строк в список целых чисел, игнорируя невалидные значения и логируя ошибки.
Первый метод parseAllIgnoringErrors использует Optional для фильтрации ошибок — подход, нативно поддерживаемый Java. Второй метод parseAllWithDetails сохраняет информацию о неудачах для последующего анализа или отчетности.
Часть вторая. Исключения в конструкторах и статических блоках
Конструктор в Java — это специальный метод, вызываемый при создании объекта оператором new. Если конструктор выбрасывает исключение, объект не создается. Это фундаментальное свойство имеет важное следствие: ресурсы, выделенные внутри конструктора до момента исключения, не требуют закрытия через try-finally или try-with-resources, потому что объект не существует и не будет существовать.
#Java #для_новичков #beginner #exception
Объединим подходы в комплексном примере. Задача: преобразовать список строк в список целых чисел, игнорируя невалидные значения и логируя ошибки.
public class NumberParser {
private static final Logger logger = LoggerFactory.getLogger(NumberParser.class);
// Стратегия: обёртка с возвратом Optional
public List<Integer> parseAllIgnoringErrors(List<String> inputs) {
return inputs.stream()
.map(this::safeParse)
.flatMap(Optional::stream) // Java 9+: фильтрация пустых Optional
.collect(Collectors.toList());
}
private Optional<Integer> safeParse(String input) {
try {
return Optional.of(Integer.parseInt(input.trim()));
} catch (NumberFormatException e) {
logger.warn("Skipping invalid number: '{}'", input);
return Optional.empty();
}
}
// Стратегия: разделение на успешные и неуспешные
public ParseResult parseAllWithDetails(List<String> inputs) {
Map<Boolean, List<Either<String, Integer>>> partitioned = inputs.stream()
.map(this::parseWithError)
.collect(Collectors.partitioningBy(Either::isRight));
List<Integer> numbers = partitioned.get(true).stream()
.map(Either::getRight)
.collect(Collectors.toList());
List<String> errors = partitioned.get(false).stream()
.map(Either::getLeft)
.collect(Collectors.toList());
return new ParseResult(numbers, errors);
}
private Either<String, Integer> parseWithError(String input) {
try {
return Either.right(Integer.parseInt(input.trim()));
} catch (NumberFormatException e) {
return Either.left(input);
}
}
public record ParseResult(List<Integer> numbers, List<String> failedInputs) {}
}Первый метод parseAllIgnoringErrors использует Optional для фильтрации ошибок — подход, нативно поддерживаемый Java. Второй метод parseAllWithDetails сохраняет информацию о неудачах для последующего анализа или отчетности.
Часть вторая. Исключения в конструкторах и статических блоках
Конструктор в Java — это специальный метод, вызываемый при создании объекта оператором new. Если конструктор выбрасывает исключение, объект не создается. Это фундаментальное свойство имеет важное следствие: ресурсы, выделенные внутри конструктора до момента исключения, не требуют закрытия через try-finally или try-with-resources, потому что объект не существует и не будет существовать.
public class FileProcessor {
private final FileInputStream inputStream;
private final BufferedReader reader;
public FileProcessor(String path) throws FileNotFoundException {
// Если new FileInputStream выбросит исключение,
// объект FileProcessor не будет создан
this.inputStream = new FileInputStream(path);
// Эта строка выполнится только если FileInputStream создан успешно
this.reader = new BufferedReader(new InputStreamReader(inputStream));
}
}#Java #для_новичков #beginner #exception
👍2
В этом примере, если new FileInputStream(path) выбросит FileNotFoundException, конструктор прервется, объект FileProcessor не будет инстанцирован, и reader не будет создан. Никаких утечек ресурсов не происходит, так как FileInputStream сам не был создан.
Однако если конструктор выделяет несколько ресурсов последовательно, ситуация усложняется:
Если statement.executeQuery(query) выбросит SQLException, объект MultiResourceProcessor не будет создан, но connection и statement уже были созданы и останутся незакрытыми. Это классический сценарий утечки ресурсов в конструкторе.
Решение — использование локальных переменных и try для гарантии закрытия частично созданных ресурсов:
Этот паттерн гарантирует, что любые ресурсы, созданные до возникновения исключения, будут закрыты. Однако он чрезвычайно многословен. Современный подход — отказ от сложной инициализации в конструкторе и использование фабричных методов:
Важное ограничение: try-with-resources закроет ресурсы при выходе из блока, поэтому возврат ResultSet из фабричного метода требует отказа от автоматического закрытия или использования специальных оберток. В большинстве случаев лучше отложить создание ресурсов до момента фактического использования, а не выполнять их в конструкторе.
#Java #для_новичков #beginner #exception
Однако если конструктор выделяет несколько ресурсов последовательно, ситуация усложняется:
public class MultiResourceProcessor {
private final Connection connection;
private final Statement statement;
private final ResultSet resultSet;
public MultiResourceProcessor(String query) throws SQLException {
this.connection = DriverManager.getConnection(DB_URL);
this.statement = connection.createStatement();
this.resultSet = statement.executeQuery(query);
}
}Если statement.executeQuery(query) выбросит SQLException, объект MultiResourceProcessor не будет создан, но connection и statement уже были созданы и останутся незакрытыми. Это классический сценарий утечки ресурсов в конструкторе.
Решение — использование локальных переменных и try для гарантии закрытия частично созданных ресурсов:
public MultiResourceProcessor(String query) throws SQLException {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(DB_URL);
stmt = conn.createStatement();
rs = stmt.executeQuery(query);
// Все ресурсы созданы успешно — присваиваем полям
this.connection = conn;
this.statement = stmt;
this.resultSet = rs;
} catch (SQLException e) {
// Закрытие частично созданных ресурсов
if (rs != null) try { rs.close(); } catch (SQLException ignored) {}
if (stmt != null) try { stmt.close(); } catch (SQLException ignored) {}
if (conn != null) try { conn.close(); } catch (SQLException ignored) {}
throw e;
}
}Этот паттерн гарантирует, что любые ресурсы, созданные до возникновения исключения, будут закрыты. Однако он чрезвычайно многословен. Современный подход — отказ от сложной инициализации в конструкторе и использование фабричных методов:
public class MultiResourceProcessor {
private final Connection connection;
private final Statement statement;
private final ResultSet resultSet;
private MultiResourceProcessor(Connection connection, Statement statement, ResultSet resultSet) {
this.connection = connection;
this.statement = statement;
this.resultSet = resultSet;
}
public static MultiResourceProcessor create(String query) throws SQLException {
try (Connection conn = DriverManager.getConnection(DB_URL);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query)) {
// ResultSet не закроется при выходе из try, так как мы его возвращаем
// Это требует специальной обработки — см. ниже
return new MultiResourceProcessor(conn, stmt, rs);
}
}
}Важное ограничение: try-with-resources закроет ресурсы при выходе из блока, поэтому возврат ResultSet из фабричного метода требует отказа от автоматического закрытия или использования специальных оберток. В большинстве случаев лучше отложить создание ресурсов до момента фактического использования, а не выполнять их в конструкторе.
#Java #для_новичков #beginner #exception
👍2