Раздел 8. Stream API и функциональный стиль в Java
Глава 3: Чистые преобразования и борьба с исключениями
filter, map, flatMap — кирпичи декларативности
Stream API предоставляет минимальный, но выразительный набор операций для декларативной обработки данных. Если императивный код строится из циклов, условий и временных переменных, то потоковый код компонуется из трёх фундаментальных примитивов: фильтрации, отображения и свёртки. Рассмотрим первые два и их мощное обобщение — flatMap.
filter: селекция по предикату
Операция filter принимает Predicate<T> — функцию, возвращающую boolean — и возвращает поток, содержащий только элементы, удовлетворяющие условию. Это декларативный аналог условного оператора в цикле, но без видимого управления состоянием.
Важно понимать, что filter — операция без состояния (stateless). Она не требует памяти, пропорциональной количеству элементов, и не изменяет порядок. Каждый элемент проверяется независимо, в изоляции от других. Это делает filter идеальным для распараллеливания: элементы можно проверять в любом порядке и в любых потоках без синхронизации.
Стоимость filter — O(1) на элемент плюс стоимость выполнения предиката. Предикат должен быть чистой функцией: детерминированной, без побочных эффектов, зависящей только от входного элемента.
Нарушение этого правила — распространённый источник багов:
При параллельном выполнении счётчик будет инкрементироваться из нескольких потоков без синхронизации, давая непредсказуемый результат.
#Java #для_новичков #beginner #stream_api #filter
Глава 3: Чистые преобразования и борьба с исключениями
filter, map, flatMap — кирпичи декларативности
Stream API предоставляет минимальный, но выразительный набор операций для декларативной обработки данных. Если императивный код строится из циклов, условий и временных переменных, то потоковый код компонуется из трёх фундаментальных примитивов: фильтрации, отображения и свёртки. Рассмотрим первые два и их мощное обобщение — flatMap.
filter: селекция по предикату
Операция filter принимает Predicate<T> — функцию, возвращающую boolean — и возвращает поток, содержащий только элементы, удовлетворяющие условию. Это декларативный аналог условного оператора в цикле, но без видимого управления состоянием.
Stream<Book> classics = library.stream()
.filter(book -> book.year() < 1980);
Важно понимать, что filter — операция без состояния (stateless). Она не требует памяти, пропорциональной количеству элементов, и не изменяет порядок. Каждый элемент проверяется независимо, в изоляции от других. Это делает filter идеальным для распараллеливания: элементы можно проверять в любом порядке и в любых потоках без синхронизации.
Стоимость filter — O(1) на элемент плюс стоимость выполнения предиката. Предикат должен быть чистой функцией: детерминированной, без побочных эффектов, зависящей только от входного элемента.
Нарушение этого правила — распространённый источник багов:
// Антипаттерн: предикат с побочным эффектом
AtomicInteger counter = new AtomicInteger(0);
Stream<Book> everyThird = library.stream()
.filter(b -> counter.incrementAndGet() % 3 == 0); // Недетерминировано при parallel()
При параллельном выполнении счётчик будет инкрементироваться из нескольких потоков без синхронизации, давая непредсказуемый результат.
#Java #для_новичков #beginner #stream_api #filter
👍4
map: структурная трансформация
Операция map принимает Function<T, R> и применяет её к каждому элементу, заменяя его результатом функции. Это преобразование типа: из потока книг делаем поток названий, из потока строк — поток их длин, из потока заказов — поток сумм.
map также stateless и ленив. Функция вызывается только при запросе элемента терминальной операцией. Стоимость — O(1) на элемент плюс стоимость функции. Функция должна быть чистой: один и тот же вход всегда даёт один и тот же выход, без модификации внешнего состояния.
Композиция map позволяет выстраивать цепочки преобразований, читаемые справа налево или через method reference:
Каждый map — отдельный узел конвейера, отдельный объект в памяти. Для простых преобразований это приемлемо, но для тяжёлых операций композиция нескольких map может быть менее эффективна, чем одно комплексное преобразование, из-за накладных расходов на вызовы лямбд и промежуточные объекты.
flatMap: разворачивание иерархий
flatMap — наиболее мощный и наиболее сложный из трёх примитивов. Он решает проблему, которую map решить не может: когда один элемент источника порождает ноль, один или множество элементов результата.
Сигнатура flatMap требует функцию, возвращающую Stream<R> вместо R. Операция применяет эту функцию к каждому элементу, получает потоки результатов и сливает их в единый выходной поток. Это аналог вложенных циклов или операции "расплющивания" (flattening) в функциональных языках.
Классический сценарий: коллекция внутри коллекции
Предположим, у нас есть список заказов, каждый содержит список позиций.
Нужно получить поток всех позиций всех заказов:
Здесь order -> order.getItems().stream() — функция, превращающая один Order в Stream<OrderItem>. flatMap выполняет слияние этих потоков, устраняя уровень вложенности. Результат — плоский поток всех элементов.
Нулевое и единичное отображение
flatMap универсален: он обрабатывает все случаи количества выходных элементов на входной:
Ноль элементов: возвращаем Stream.empty(), элемент исключается из результата
Один элемент: возвращаем Stream.of(element), эквивалентно map с последующим filter(Objects::nonNull)
Множество элементов: возвращаем collection.stream(), все элементы включаются в результат
#Java #для_новичков #beginner #stream_api #filter #flatMap #map
Операция map принимает Function<T, R> и применяет её к каждому элементу, заменяя его результатом функции. Это преобразование типа: из потока книг делаем поток названий, из потока строк — поток их длин, из потока заказов — поток сумм.
Stream<String> titles = library.stream()
.map(Book::title);
Stream<Integer> lengths = titles.map(String::length);
map также stateless и ленив. Функция вызывается только при запросе элемента терминальной операцией. Стоимость — O(1) на элемент плюс стоимость функции. Функция должна быть чистой: один и тот же вход всегда даёт один и тот же выход, без модификации внешнего состояния.
Композиция map позволяет выстраивать цепочки преобразований, читаемые справа налево или через method reference:
// Цепочка преобразований: Book -> String -> Integer -> String
String summary = book.stream()
.map(Book::author) // Book -> String
.map(String::toUpperCase) // String -> String
.map(author -> author.substring(0, 3)) // String -> String
.map(prefix -> "Author: " + prefix) // String -> String
.findFirst()
.orElse("Unknown");
Каждый map — отдельный узел конвейера, отдельный объект в памяти. Для простых преобразований это приемлемо, но для тяжёлых операций композиция нескольких map может быть менее эффективна, чем одно комплексное преобразование, из-за накладных расходов на вызовы лямбд и промежуточные объекты.
flatMap: разворачивание иерархий
flatMap — наиболее мощный и наиболее сложный из трёх примитивов. Он решает проблему, которую map решить не может: когда один элемент источника порождает ноль, один или множество элементов результата.
Сигнатура flatMap требует функцию, возвращающую Stream<R> вместо R. Операция применяет эту функцию к каждому элементу, получает потоки результатов и сливает их в единый выходной поток. Это аналог вложенных циклов или операции "расплющивания" (flattening) в функциональных языках.
Классический сценарий: коллекция внутри коллекции
Предположим, у нас есть список заказов, каждый содержит список позиций.
Нужно получить поток всех позиций всех заказов:
List<Order> orders = fetchOrders();
// Императивный подход: вложенные циклы, временная коллекция
List<OrderItem> allItems = new ArrayList<>();
for (Order order : orders) {
for (OrderItem item : order.getItems()) {
allItems.add(item);
}
}
// Декларативный подход: flatMap
Stream<OrderItem> itemStream = orders.stream()
.flatMap(order -> order.getItems().stream());
Здесь order -> order.getItems().stream() — функция, превращающая один Order в Stream<OrderItem>. flatMap выполняет слияние этих потоков, устраняя уровень вложенности. Результат — плоский поток всех элементов.
Нулевое и единичное отображение
flatMap универсален: он обрабатывает все случаи количества выходных элементов на входной:
Ноль элементов: возвращаем Stream.empty(), элемент исключается из результата
Один элемент: возвращаем Stream.of(element), эквивалентно map с последующим filter(Objects::nonNull)
Множество элементов: возвращаем collection.stream(), все элементы включаются в результат
// Фильтрация через flatMap: ноль или один элемент
Stream<Book> validBooks = rawData.stream()
.flatMap(data -> {
try {
Book book = parseBook(data); // Может бросить исключение
return Stream.of(book); // Один элемент при успехе
} catch (ParseException e) {
return Stream.empty(); // Ноль элементов при ошибке
}
});
#Java #для_новичков #beginner #stream_api #filter #flatMap #map
👍5
Сложность и читаемость
Мощь flatMap оборачивается риском чрезмерной сложности.
Вложенные flatMap создают "лестницу" преобразований, сложную для восприятия:
Этот код эквивалентен четырём вложенным циклам. Он работает, но его трудно читать и отлаживать. Каждый уровень вложенности добавляет лексический контекст, и переменные верхних уровней (order, shipment) доступны во вложенных лямбдах, создавая неявные зависимости.
Рефакторинг через промежуточные методы улучшает читаемость:
Или использование mapMulti (Java 16+) — операции, комбинирующей map и flatMap с более эффективной реализацией для множественного вывода:
mapMulti избегает создания промежуточных объектов Stream для каждого элемента, что снижает нагрузку на GC при глубокой вложенности.
Анализ стоимости
filter: O(1) на элемент. Память: O(1). Параллелизм: отличный, нет синхронизации.
map: O(1) на элемент плюс стоимость функции. Память: O(1) для примитивов, O(1) для ссылок (создаётся новый объект результата). Параллелизм: отличный.
flatMap: O(1) на элемент плюс стоимость создания выходного потока плюс стоимость его обхода. Память: зависит от размера выходных потоков. Параллелизм: сложный — слияние множественных потоков требует координации.
Скрытая стоимость flatMap — в аллокациях. Каждый вызов функции создаёт новый объект Stream (обычно через Collection.stream() или Stream.of()). Для больших коллекций это давит на Young Generation. Оптимизация через mapMulti или специализированные сплитераторы уместна в критичных секциях.
Композиция как язык запросов
Комбинация filter, map, flatMap образует внутренний DSL (domain-specific language) для преобразования данных.
Хорошо спроектированный конвейер читается как предложение на естественном языке:
Каждая операция — глагол, каждый метод reference или лямбда — дополнение. Порядок операций отражает логику обработки: сначала сужаем (filter), затем расплющиваем (flatMap), затем нормализуем (distinct, sorted).
#Java #для_новичков #beginner #stream_api #filter #flatMap #map
Мощь flatMap оборачивается риском чрезмерной сложности.
Вложенные flatMap создают "лестницу" преобразований, сложную для восприятия:
// Антипаттерн: глубокая вложенность flatMap
Stream<String> deepStream = orders.stream()
.flatMap(order -> order.getShipments().stream()
.flatMap(shipment -> shipment.getPackages().stream()
.flatMap(pkg -> pkg.getItems().stream()
.flatMap(item -> item.getTags().stream()))));
Этот код эквивалентен четырём вложенным циклам. Он работает, но его трудно читать и отлаживать. Каждый уровень вложенности добавляет лексический контекст, и переменные верхних уровней (order, shipment) доступны во вложенных лямбдах, создавая неявные зависимости.
Рефакторинг через промежуточные методы улучшает читаемость:
// Лучше: именованные методы с ясной семантикой
Stream<String> tags = orders.stream()
.flatMap(this::extractShipments)
.flatMap(this::extractPackages)
.flatMap(this::extractItems)
.flatMap(this::extractTags);
private Stream<Shipment> extractShipments(Order order) {
return order.getShipments().stream();
}
// ... и так далее
Или использование mapMulti (Java 16+) — операции, комбинирующей map и flatMap с более эффективной реализацией для множественного вывода:
// mapMulti: более эффективен, чем flatMap, для множественных элементов
Stream<String> tags = orders.stream()
.<String>mapMulti((order, consumer) -> {
for (Shipment s : order.getShipments()) {
for (Package p : s.getPackages()) {
for (Item i : p.getItems()) {
for (String tag : i.getTags()) {
consumer.accept(tag); // Прямая передача без создания Stream
}
}
}
}
});
mapMulti избегает создания промежуточных объектов Stream для каждого элемента, что снижает нагрузку на GC при глубокой вложенности.
Анализ стоимости
filter: O(1) на элемент. Память: O(1). Параллелизм: отличный, нет синхронизации.
map: O(1) на элемент плюс стоимость функции. Память: O(1) для примитивов, O(1) для ссылок (создаётся новый объект результата). Параллелизм: отличный.
flatMap: O(1) на элемент плюс стоимость создания выходного потока плюс стоимость его обхода. Память: зависит от размера выходных потоков. Параллелизм: сложный — слияние множественных потоков требует координации.
Скрытая стоимость flatMap — в аллокациях. Каждый вызов функции создаёт новый объект Stream (обычно через Collection.stream() или Stream.of()). Для больших коллекций это давит на Young Generation. Оптимизация через mapMulti или специализированные сплитераторы уместна в критичных секциях.
Композиция как язык запросов
Комбинация filter, map, flatMap образует внутренний DSL (domain-specific language) для преобразования данных.
Хорошо спроектированный конвейер читается как предложение на естественном языке:
// "Найти все уникальные теги из активных заказов, отсортированные по алфавиту"
List<String> sortedUniqueTags = orders.stream()
.filter(Order::isActive) // которые активны
.flatMap(o -> o.getTags().stream()) // извлечь все теги
.distinct() // уникальные
.sorted() // отсортированные
.collect(toList()); // собрать в список
Каждая операция — глагол, каждый метод reference или лямбда — дополнение. Порядок операций отражает логику обработки: сначала сужаем (filter), затем расплющиваем (flatMap), затем нормализуем (distinct, sorted).
#Java #для_новичков #beginner #stream_api #filter #flatMap #map
👍3
Что выведет код?
#Tasks
import java.util.stream.Stream;
public class Task200226 {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4, 5)
.filter(i -> {
System.out.print(i + " ");
return i % 2 == 0;
})
.map(i -> i * 10)
.findFirst()
.ifPresent(i -> System.out.print("result: " + i));
}
}
#Tasks
👍2
Варианты ответа:
Anonymous Quiz
23%
2 result: 20
9%
1 2 result: 20
59%
1 2 3 4 5 result: 20
9%
result: 20
Чем отличается throw от throws? 🤓
Ответ:
Оба ключевых слова связаны с обработкой исключений, но выполняют разные функции.
throws используется в сигнатуре метода, чтобы объявить, что метод может выбросить указанные исключения (обычно проверяемые). Это предупреждение для вызывающего кода.
throw — это оператор, который фактически создает и выбрасывает объект исключения (например, throw new IOException("Ошибка")).
throw используется внутри тела метода.
#собеседование
Ответ:
throws используется в сигнатуре метода, чтобы объявить, что метод может выбросить указанные исключения (обычно проверяемые). Это предупреждение для вызывающего кода.
throw — это оператор, который фактически создает и выбрасывает объект исключения (например, throw new IOException("Ошибка")).
throw используется внутри тела метода.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологий сегодня — 21 Февраля
ℹ️ Кто родился в этот день
Михаи́л Алекса́ндрович Бонч-Бруе́вич (9 (21) февраля 1888, Орёл — 7 марта 1940, Ленинград) — русский и советский радиотехник, основатель российской радиоламповой промышленности. Член-корреспондент АН СССР (1931). Профессор Московского высшего технического училища (1922), Ленинградского института инженеров связи (1932), доктор технических наук, один из основателей и руководителей Нижегородской радиолаборатории. Внёс значительный вклад в развитие советской радиофизики, разработку новых типов радиоламп, аппаратуры радиовещания и радиосвязи. Автор учебников, научных работ, а также около 60 патентов на изобретения в области радиотехники.
🌐 Знаковые события
2006 — космическим телескопом «Хаббл» открыт астрономический объект неизвестного типа SCP 06F6, природу которого астрономы не могут объяснить до сих пор.
#Biography #Birth_Date #Events #21февраля
Михаи́л Алекса́ндрович Бонч-Бруе́вич (9 (21) февраля 1888, Орёл — 7 марта 1940, Ленинград) — русский и советский радиотехник, основатель российской радиоламповой промышленности. Член-корреспондент АН СССР (1931). Профессор Московского высшего технического училища (1922), Ленинградского института инженеров связи (1932), доктор технических наук, один из основателей и руководителей Нижегородской радиолаборатории. Внёс значительный вклад в развитие советской радиофизики, разработку новых типов радиоламп, аппаратуры радиовещания и радиосвязи. Автор учебников, научных работ, а также около 60 патентов на изобретения в области радиотехники.
2006 — космическим телескопом «Хаббл» открыт астрономический объект неизвестного типа SCP 06F6, природу которого астрономы не могут объяснить до сих пор.
#Biography #Birth_Date #Events #21февраля
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
С 14.02 по 20.02
Предыдущий пост(с 07.02 по 13.02)
Воскресный мотивационный пост:
Не было мотивации
Запись встреч/видео:
6. От сырых метрик к production-мониторингу: Prometheus и Grafana
Обучающие статьи:
Раздел 8. Stream API и функциональный стиль
Глава 2: Анатомия Stream API. Ленивость и стоимость операций
Ленивость и Short-Circuit — ключ к эффективности
(Практика): Диссекция конвейера в «Библиотеке»
Глава 3: Чистые преобразования и борьба с исключениями
filter, map, flatMap — кирпичи декларативности
Советы по Java:
[Совет по Java #006]
Используйте Enum вместо строковых констант для ограниченного набора значений
[Совет по Java #007]
System.currentTimeMillis() для замеров производительности ненадежен. Всегда используйте System.nanoTime().
Полезные статьи и видео:
Hot reload секретов под нагрузкой в Java-сервисах на Spring
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
Предыдущий пост(с 07.02 по 13.02)
Воскресный мотивационный пост:
Не было мотивации
Запись встреч/видео:
6. От сырых метрик к production-мониторингу: Prometheus и Grafana
Обучающие статьи:
Раздел 8. Stream API и функциональный стиль
Глава 2: Анатомия Stream API. Ленивость и стоимость операций
Ленивость и Short-Circuit — ключ к эффективности
(Практика): Диссекция конвейера в «Библиотеке»
Глава 3: Чистые преобразования и борьба с исключениями
filter, map, flatMap — кирпичи декларативности
Советы по Java:
[Совет по Java #006]
Используйте Enum вместо строковых констант для ограниченного набора значений
[Совет по Java #007]
System.currentTimeMillis() для замеров производительности ненадежен. Всегда используйте System.nanoTime().
Полезные статьи и видео:
Hot reload секретов под нагрузкой в Java-сервисах на Spring
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
👍3🔥2 2
А давайте сегодня, часиков в 17 по мск встретимся и поболтаем? ☺️
Что-то давно Вас всех не видел)))
Расскажете как у вас дела😉
Придете?📞
Что-то давно Вас всех не видел)))
Расскажете как у вас дела
Придете?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
История технологий сегодня — 22 Февраля
ℹ️ Кто родился в этот день
Томас Курц (англ. Thomas Eugene Kurtz; 22 февраля 1928, Ок-Парк — 12 ноября 2024, Лебанон[англ.]) — американский учёный в области информатики, один из разработчиков языка программирования Бейсик. В начале — середине 1960-х годов совместно с Джоном Кемени разработал Бейсик и DTTS (англ. Dartmouth Time Sharing System) — операционную систему для PDP-1, отмечаемую как первую успешную крупномасштабную реализацию концепции разделения времени.
Ирвинг «Эл» Гросс (/ɡroʊs/; 22 февраля 1918 — 21 декабря 2000) — был пионером мобильной беспроводной связи. Он создал и запатентовал множество коммуникационных устройств, в частности, раннюю версию рации, радиостанции гражданского диапазона, пейджер и беспроводной телефон.
🌐 Знаковые события
1966 — запущен спутник «Космос-110» с собаками Ветерком и Угольком на борту.
#Biography #Birth_Date #Events #22февраля
Томас Курц (англ. Thomas Eugene Kurtz; 22 февраля 1928, Ок-Парк — 12 ноября 2024, Лебанон[англ.]) — американский учёный в области информатики, один из разработчиков языка программирования Бейсик. В начале — середине 1960-х годов совместно с Джоном Кемени разработал Бейсик и DTTS (англ. Dartmouth Time Sharing System) — операционную систему для PDP-1, отмечаемую как первую успешную крупномасштабную реализацию концепции разделения времени.
Ирвинг «Эл» Гросс (/ɡroʊs/; 22 февраля 1918 — 21 декабря 2000) — был пионером мобильной беспроводной связи. Он создал и запатентовал множество коммуникационных устройств, в частности, раннюю версию рации, радиостанции гражданского диапазона, пейджер и беспроводной телефон.
1966 — запущен спутник «Космос-110» с собаками Ветерком и Угольком на борту.
#Biography #Birth_Date #Events #22февраля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
ГЛОБАЛИЗАЦИЯ ЗАКАНЧИВАЕТСЯ
Помните эту картинку, нарисованную влажной рекламой?
Айтишник на лежаке у океана. В одной руке — «Пина колада». А другой — пуш в гит. Проект в России. Жизнь в Таиланде. Зарплата в долларах.
Многие пошли в айти из-за этого. Многие сорвались в далёкие страны за убегающей картинкой-мечтой.
И да, некоторые добились желаемого.
Но мне всегда хотелось понять: ценой чего?
Жить там, где тебя терпят, пока есть деньги?
Бросить родных, друзей, свой двор — чтобы пожить красиво?
Быть вечным чужим и никогда не почувствовать, что ты на своей земле?
ЭТО НЕ КРИЗИС. ЭТО ЗАКАТ ГЛОБАЛИЗАЦИИ.
Если вы следите за миром, вы уже видели: торговые войны, санкции, запреты на чипы и облака, требования локализовать данные. Каждая страна строит свои цифровые стены.
Но многие всё ещё думают: потерпим, переждём, все вернётся к прежнему и привычному.
Нифига ребят.
Санкционные режимы — не временные проблемы. Это новые правила. Тем более в России, где большинство из нас родилось и живет. И даже в соседних странах, которые подмахивают в сторону запада - ничего не останется прежним.
Ограничения на полупроводники, ИИ, облака — долгосрочная политика ведущих держав. Данные больше не текут свободно — они стали стратегическим ресурсом, как нефть или уран.
И речь не о паре проблемных лет. Речь о том, что мир перестраивается навсегда.
IT ВНЕ ПОЛИТИКИ? ЗАБУДЬТЕ.
Раньше можно было прятаться за мантру: код — вне политики. GitHub — глобален. Мы — граждане интернета.
Как же сейчас это звучит смешно. Китай и США, Россия и Европейский союз - полностью расходятся бортами.
Код — теперь инфраструктура государства. Облака — суверенитет. Чипы — оборона. Разработчик больше не "фрилансер". Он встроен в геоэкономическую систему конкретной страны.
И выбраться из этого нельзя — можно только осознать и принять или начать бороться с ветряной мельницей.
Вы думаете, вас не коснётся? Посмотрите на карту, компании разделяются на региональные экосистемы. Доступы к сервисам обрываются.
Вчерашние «глобальные» инструменты завтра потребуют лицензию, которой у вас нет и не будет потому что цифровая стена отгородила Вас.
ПОЧЕМУ ЭТО ПРОИСХОДИТ ИМЕННО СЕЙЧАС?
Раньше границы были физическими. Теперь они стали цифровыми. И конфликты уходят туда же — в кремний, в протоколы, в исходный код. Борьба идёт не за территории, а за данные и контроль над ними.
Кто первым станет владеть цифрой - будет у руля будущего.
Поэтому сейчас вкладывают триллионы в ИИ, в надежде, что он решит все проблемы своих создателей.
Поэтому мир меняется. И не только в нашей стране.
ЧТО ЭТО ЗНАЧИТ ДЛЯ НАС?
Мир меняется. И вместе с ним меняются правила игры.
Раньше наши ребята писали код для стартапов из Кремниевой долины, делали фичи для европейских финтех-проектов, грезили офферами в FAANG. И успех измерялся тем, как далеко они уехали от дома.
Это была эпоха потребителей глобализации.
Теперь наступает эпоха строителей.
Посмотрите на карту: огромные рынки — Россия, Китай, Иран, многие страны Африки и Латинской Америки — выпадают из западной цифровой орбиты. Но люди там не перестали пользоваться приложениями, не перестали платить, не перестали общаться.
Кто закроет эти потребности?
Вспомните историю: когда Америка ввела эмбарго на технологии для СССР, мы не перестали летать в космос. Мы построили свою космонавтику.
Сейчас перед нами стоит точно такая же задача: построить свой цифровой мир. Не догоняющий и не копирующий, а свой.
Да, это сложно. Да, придется переучиваться. Придется забыть про "просто вставить готовую библиотеку с гитхаба" — потому что завтра её могут отозвать. Да и гитхаб заблокировать для пользователей "недружественной страны".
Придется научиться делать глубокие, безопасные, суверенные продукты с нуля.
И да, нас ждут горы ошибок и тонны недальновидных, "топорных" решений. Но без этого, в мире гигантов мы останемся карликами.
Глобализация заканчивается. Начинается эра мастеров. И она уже идёт, прямо здесь и сейчас.
😎 @Oleborn
Помните эту картинку, нарисованную влажной рекламой?
Айтишник на лежаке у океана. В одной руке — «Пина колада». А другой — пуш в гит. Проект в России. Жизнь в Таиланде. Зарплата в долларах.
Многие пошли в айти из-за этого. Многие сорвались в далёкие страны за убегающей картинкой-мечтой.
И да, некоторые добились желаемого.
Но мне всегда хотелось понять: ценой чего?
Жить там, где тебя терпят, пока есть деньги?
Бросить родных, друзей, свой двор — чтобы пожить красиво?
Быть вечным чужим и никогда не почувствовать, что ты на своей земле?
ЭТО НЕ КРИЗИС. ЭТО ЗАКАТ ГЛОБАЛИЗАЦИИ.
Если вы следите за миром, вы уже видели: торговые войны, санкции, запреты на чипы и облака, требования локализовать данные. Каждая страна строит свои цифровые стены.
Но многие всё ещё думают: потерпим, переждём, все вернётся к прежнему и привычному.
Нифига ребят.
Санкционные режимы — не временные проблемы. Это новые правила. Тем более в России, где большинство из нас родилось и живет. И даже в соседних странах, которые подмахивают в сторону запада - ничего не останется прежним.
Ограничения на полупроводники, ИИ, облака — долгосрочная политика ведущих держав. Данные больше не текут свободно — они стали стратегическим ресурсом, как нефть или уран.
И речь не о паре проблемных лет. Речь о том, что мир перестраивается навсегда.
IT ВНЕ ПОЛИТИКИ? ЗАБУДЬТЕ.
Раньше можно было прятаться за мантру: код — вне политики. GitHub — глобален. Мы — граждане интернета.
Как же сейчас это звучит смешно. Китай и США, Россия и Европейский союз - полностью расходятся бортами.
Код — теперь инфраструктура государства. Облака — суверенитет. Чипы — оборона. Разработчик больше не "фрилансер". Он встроен в геоэкономическую систему конкретной страны.
И выбраться из этого нельзя — можно только осознать и принять или начать бороться с ветряной мельницей.
Вы думаете, вас не коснётся? Посмотрите на карту, компании разделяются на региональные экосистемы. Доступы к сервисам обрываются.
Вчерашние «глобальные» инструменты завтра потребуют лицензию, которой у вас нет и не будет потому что цифровая стена отгородила Вас.
ПОЧЕМУ ЭТО ПРОИСХОДИТ ИМЕННО СЕЙЧАС?
Раньше границы были физическими. Теперь они стали цифровыми. И конфликты уходят туда же — в кремний, в протоколы, в исходный код. Борьба идёт не за территории, а за данные и контроль над ними.
Кто первым станет владеть цифрой - будет у руля будущего.
Поэтому сейчас вкладывают триллионы в ИИ, в надежде, что он решит все проблемы своих создателей.
Поэтому мир меняется. И не только в нашей стране.
ЧТО ЭТО ЗНАЧИТ ДЛЯ НАС?
Мир меняется. И вместе с ним меняются правила игры.
Раньше наши ребята писали код для стартапов из Кремниевой долины, делали фичи для европейских финтех-проектов, грезили офферами в FAANG. И успех измерялся тем, как далеко они уехали от дома.
Это была эпоха потребителей глобализации.
Теперь наступает эпоха строителей.
Посмотрите на карту: огромные рынки — Россия, Китай, Иран, многие страны Африки и Латинской Америки — выпадают из западной цифровой орбиты. Но люди там не перестали пользоваться приложениями, не перестали платить, не перестали общаться.
Кто закроет эти потребности?
Вспомните историю: когда Америка ввела эмбарго на технологии для СССР, мы не перестали летать в космос. Мы построили свою космонавтику.
Сейчас перед нами стоит точно такая же задача: построить свой цифровой мир. Не догоняющий и не копирующий, а свой.
Да, это сложно. Да, придется переучиваться. Придется забыть про "просто вставить готовую библиотеку с гитхаба" — потому что завтра её могут отозвать. Да и гитхаб заблокировать для пользователей "недружественной страны".
Придется научиться делать глубокие, безопасные, суверенные продукты с нуля.
И да, нас ждут горы ошибок и тонны недальновидных, "топорных" решений. Но без этого, в мире гигантов мы останемся карликами.
Глобализация заканчивается. Начинается эра мастеров. И она уже идёт, прямо здесь и сейчас.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥3
История технологий сегодня — 23 Февраля
🇷🇺Россия — День защитника Отечества🫡
День защитника Отечества — праздник, отмечаемый ежегодно 23 февраля в России, Беларуси, Казахстане, Кыргызстане, Таджикистане, а также в частично признанных Абхазии, Южной Осетии и непризнанной Приднестровской Молдавской Республике (ПМР).
23 февраля (н. ст.) 1918 года было опубликовано воззвание СНК от 21 февраля «Социалистическое отечество в опасности!», а также «Воззвание Военного главнокомандующего» Н. В. Крыленко.
Этот день был объявлен праздником в РСФСР 27 января 1922 года, когда Президиум ВЦИК РСФСР опубликовал постановление о четвёртой годовщине Красной армии, в котором говорилось: «В соответствии с постановлением IX Всероссийского съезда Советов о Красной армии Президиум ВЦИК обращает внимание исполкомов на наступающую годовщину создания Красной армии (23 февраля)».
С 1922 года в СССР эта дата ежегодно традиционно отмечалась как «День Красной армии», с 1946 года — «День Советской армии», с 1949 по 1992 годы — «День Советской армии и Военно-морского флота».
ℹ️ Кто родился в этот день
Деррик Генри «Дик» Лемер (англ. Derrick Henry Lehmer; 23 февраля 1905, Беркли (Калифорния) — 22 мая 1991, Беркли (Калифорния)) — американский математик, усовершенствовавший работу Эдуарда Люка в 1930-е годы и разработавший Тест Люка — Лемера для простых чисел Мерсенна. Карьера Лемера развивалась в области теории чисел. Во время Великой Депрессии он со своей женой был вынужден сменить множество профессий как в Соединённых Штатах, так и за рубежом, что в конечном итоге случайно привело его в центр исследований в области ранней электронной вычислительной техники.
Роберт Николас Кристиан Топала (англ. Robert Nicholas Christian Topala; род. 23 февраля 1987, Уппландс Весбю, Швеция), более известный как RobTop, — независимый шведский разработчик видеоигр, аниматор и музыкант, прославившийся платформером Geometry Dash.
Аллан Маклауд Кормак (англ. Allan McLeod Cormack; 23 февраля 1924, Йоханнесбург, Южная Африка — 7 мая 1998, Уинчестер, штат Массачусетс, США) — южноафриканский и американский физик, лауреат Нобелевской премии по физиологии и медицине 1979 года «за разработку компьютерной томографии», которую он получил с Годфри Хаунсфилдом.
🌐 Знаковые события
1987 — вспышка сверхновой SN 1987A достигла Земли. Это самая близкая сверхновая со времён изобретения телескопа.
1993 — создан язык программирования Ruby.
#Biography #Birth_Date #Events #23февраля
🇷🇺Россия — День защитника Отечества
День защитника Отечества — праздник, отмечаемый ежегодно 23 февраля в России, Беларуси, Казахстане, Кыргызстане, Таджикистане, а также в частично признанных Абхазии, Южной Осетии и непризнанной Приднестровской Молдавской Республике (ПМР).
23 февраля (н. ст.) 1918 года было опубликовано воззвание СНК от 21 февраля «Социалистическое отечество в опасности!», а также «Воззвание Военного главнокомандующего» Н. В. Крыленко.
Этот день был объявлен праздником в РСФСР 27 января 1922 года, когда Президиум ВЦИК РСФСР опубликовал постановление о четвёртой годовщине Красной армии, в котором говорилось: «В соответствии с постановлением IX Всероссийского съезда Советов о Красной армии Президиум ВЦИК обращает внимание исполкомов на наступающую годовщину создания Красной армии (23 февраля)».
С 1922 года в СССР эта дата ежегодно традиционно отмечалась как «День Красной армии», с 1946 года — «День Советской армии», с 1949 по 1992 годы — «День Советской армии и Военно-морского флота».
Деррик Генри «Дик» Лемер (англ. Derrick Henry Lehmer; 23 февраля 1905, Беркли (Калифорния) — 22 мая 1991, Беркли (Калифорния)) — американский математик, усовершенствовавший работу Эдуарда Люка в 1930-е годы и разработавший Тест Люка — Лемера для простых чисел Мерсенна. Карьера Лемера развивалась в области теории чисел. Во время Великой Депрессии он со своей женой был вынужден сменить множество профессий как в Соединённых Штатах, так и за рубежом, что в конечном итоге случайно привело его в центр исследований в области ранней электронной вычислительной техники.
Роберт Николас Кристиан Топала (англ. Robert Nicholas Christian Topala; род. 23 февраля 1987, Уппландс Весбю, Швеция), более известный как RobTop, — независимый шведский разработчик видеоигр, аниматор и музыкант, прославившийся платформером Geometry Dash.
Аллан Маклауд Кормак (англ. Allan McLeod Cormack; 23 февраля 1924, Йоханнесбург, Южная Африка — 7 мая 1998, Уинчестер, штат Массачусетс, США) — южноафриканский и американский физик, лауреат Нобелевской премии по физиологии и медицине 1979 года «за разработку компьютерной томографии», которую он получил с Годфри Хаунсфилдом.
1987 — вспышка сверхновой SN 1987A достигла Земли. Это самая близкая сверхновая со времён изобретения телескопа.
1993 — создан язык программирования Ruby.
#Biography #Birth_Date #Events #23февраля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
[Совет по Java #008]
Тема: Не ловите Exception или Throwable без крайней необходимости. Ловите максимально конкретные исключения.
Проблема: Перехват общих типов исключений, таких как Exception или Throwable, является грубой ошибкой, нарушающей принцип обработки исключений.
Это приводит к тому, что блок catch обрабатывает не только ожидаемые исключения (например, IOException, SQLException), но и непредвиденные, фатальные ошибки, которые сигнализируют о серьезных сбоях в работе JVM. К таким ошибкам относятся NullPointerException, ArrayIndexOutOfBoundsException (программные ошибки), а также OutOfMemoryError, StackOverflowError (ошибки виртуальной машины).
Перехватывая Exception, разработчик маскирует баги, которые должны были привести к аварийному завершению программы и последующей диагностике. Вместо этого программа продолжает работу в некорректном состоянии, что может привести к повреждению данных, неконсистентности состояния и крайне сложной отладке.
Решение: Всегда перехватывайте максимально конкретные типы исключений, которые вы ожидаете и способны корректно обработать.
Используйте несколько блоков catch для разных типов исключений, располагая их от наиболее конкретных к наиболее общим. Если необходимо выполнить общие действия (например, логирование), используйте multi-catch (Java 7+) для объединения родственных типов исключений. Никогда не перехватывайте Throwable, если только вы не пишете код на самом верхнем уровне (например, пул потоков), где требуется гарантированно избежать "проглатывания" ошибок и обеспечить логирование фатальных сбоев перед завершением потока.
Объяснение: Иерархия исключений делится на проверяемые (восстановимые) и непроверяемые (ошибки программирования и JVM).
Перехватывая Exception, вы стираете эту границу. Правило простое: лови только то, что можешь обработать. FileNotFoundException можно обработать — запросить другой файл. NullPointerException обрабатывать нельзя — нужно исправлять код. OutOfMemoryError тем более не для catch — JVM в критическом состоянии.
Разработчик всегда задает вопрос: "Я могу это исправить?" — и если нет, не ловит.
#Java #советы
Тема: Не ловите Exception или Throwable без крайней необходимости. Ловите максимально конкретные исключения.
Проблема: Перехват общих типов исключений, таких как Exception или Throwable, является грубой ошибкой, нарушающей принцип обработки исключений.
Это приводит к тому, что блок catch обрабатывает не только ожидаемые исключения (например, IOException, SQLException), но и непредвиденные, фатальные ошибки, которые сигнализируют о серьезных сбоях в работе JVM. К таким ошибкам относятся NullPointerException, ArrayIndexOutOfBoundsException (программные ошибки), а также OutOfMemoryError, StackOverflowError (ошибки виртуальной машины).
Перехватывая Exception, разработчик маскирует баги, которые должны были привести к аварийному завершению программы и последующей диагностике. Вместо этого программа продолжает работу в некорректном состоянии, что может привести к повреждению данных, неконсистентности состояния и крайне сложной отладке.
Решение: Всегда перехватывайте максимально конкретные типы исключений, которые вы ожидаете и способны корректно обработать.
Используйте несколько блоков catch для разных типов исключений, располагая их от наиболее конкретных к наиболее общим. Если необходимо выполнить общие действия (например, логирование), используйте multi-catch (Java 7+) для объединения родственных типов исключений. Никогда не перехватывайте Throwable, если только вы не пишете код на самом верхнем уровне (например, пул потоков), где требуется гарантированно избежать "проглатывания" ошибок и обеспечить логирование фатальных сбоев перед завершением потока.
import java.io.*;
import java.sql.*;
public class ExceptionHandling {
//Антипаттерн
public void bad(String path) {
try {
BufferedReader reader = new BufferedReader(new FileReader(path));
} catch (Exception e) { // Ловит IOException, NPE, OOM
e.printStackTrace(); // Фатальные ошибки "проглочены"
}
}
//Правильно
public void good(String path) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
String line = reader.readLine();
} catch (FileNotFoundException e) {
System.err.println("Файл не найден: " + path);
// Это восстановимая ситуация
}
// IOException пробрасывается выше
// NPE, OOM не ловятся — пусть падают
}
//Multi-catch
public void multi(String path) {
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
} catch (FileNotFoundException | ClassNotFoundException e) {
System.err.println("Ресурс не найден: " + e.getMessage());
} catch (IOException e) {
throw new RuntimeException("Ошибка ввода-вывода", e);
}
}
//Единственный случай для Throwable
public void thread(Runnable task) {
new Thread(() -> {
try {
task.run();
} catch (Throwable t) { // Только для логирования на верхнем уровне
System.err.println("Критическая ошибка: " + t);
}
}).start();
}
}
Объяснение: Иерархия исключений делится на проверяемые (восстановимые) и непроверяемые (ошибки программирования и JVM).
Перехватывая Exception, вы стираете эту границу. Правило простое: лови только то, что можешь обработать. FileNotFoundException можно обработать — запросить другой файл. NullPointerException обрабатывать нельзя — нужно исправлять код. OutOfMemoryError тем более не для catch — JVM в критическом состоянии.
Разработчик всегда задает вопрос: "Я могу это исправить?" — и если нет, не ловит.
#Java #советы
👍5🤯1
Что выведет код?
#Tasks
public class Task230226 {
public static void main(String[] args) {
try {
throw new StackOverflowError();
} catch (Error e) {
System.out.println("Error caught");
} catch (Exception e) {
System.out.println("Exception caught");
} catch (Throwable e) {
System.out.println("Throwable caught");
}
}
}#Tasks
👍1
Варианты ответа:
Anonymous Quiz
13%
Exception caught
57%
Error caught
3%
Throwable caught
27%
Ничего, программа упадет
👍2
7. Введение в распределённую трассировку. OpenTelemetry & Jaeger.
Когда у вас один сервис — всё просто. Но как только появляется второй, вы слепнете.
Почему запрос тормозит? Кто виноват: ваш код или внешний сервис?
Метрики врут, логи разрозненны. Нужна распределённая трассировка.🤓
В этом видео мы шаг за шагом разберём, как работает трассировка на реальном примере:
два микросервиса (order-service и notification-service), HTTP-вызовы, OpenTelemetry и Jaeger.
Что вы узнаете:
- Как устроена распределённая трассировка: trace, span, traceId, propagation
- Как настроить OpenTelemetry в Spring Boot 3 с Micrometer Tracing
- Как поднять Jaeger в Docker и отправлять в него трассы
- Как анализировать трассу: parent-child связи, длительность, теги
- Почему в трассе три спана, хотя сервисов два
- Как добавить бизнес-атрибуты (order.id) и искать по ним в Jaeger
Исходный код проекта на GitHub очень ждет Ваших звезд☺️
Ссылка на Youtube
Ссылка на Рутьюб
Смотрите, ставьте лайки, подписывайтесь на каналы!✌️
Когда у вас один сервис — всё просто. Но как только появляется второй, вы слепнете.
Почему запрос тормозит? Кто виноват: ваш код или внешний сервис?
Метрики врут, логи разрозненны. Нужна распределённая трассировка.
В этом видео мы шаг за шагом разберём, как работает трассировка на реальном примере:
два микросервиса (order-service и notification-service), HTTP-вызовы, OpenTelemetry и Jaeger.
Что вы узнаете:
- Как устроена распределённая трассировка: trace, span, traceId, propagation
- Как настроить OpenTelemetry в Spring Boot 3 с Micrometer Tracing
- Как поднять Jaeger в Docker и отправлять в него трассы
- Как анализировать трассу: parent-child связи, длительность, теги
- Почему в трассе три спана, хотя сервисов два
- Как добавить бизнес-атрибуты (order.id) и искать по ним в Jaeger
Исходный код проекта на GitHub очень ждет Ваших звезд
Ссылка на Youtube
Ссылка на Рутьюб
Смотрите, ставьте лайки, подписывайтесь на каналы!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥1 1
Как работает цикл for-each? 🤓
Ответ:
for-each (или enhanced for loop) — это упрощенная форма цикла for для итерации по массивам и коллекциям, реализующим интерфейс Iterable.
Синтаксис: for (Тип переменная : коллекция) { ... }.
На каждой итерации в переменную автоматически помещается следующий элемент. Преимущество — краткость и отсутствие ошибок с индексами. Недостатки — нет доступа к индексу элемента, нельзя удалять элементы коллекции (вызовет ConcurrentModificationException) и изменять структуру коллекции во время итерации.
#собеседование
Ответ:
Синтаксис: for (Тип переменная : коллекция) { ... }.
На каждой итерации в переменную автоматически помещается следующий элемент. Преимущество — краткость и отсутствие ошибок с индексами. Недостатки — нет доступа к индексу элемента, нельзя удалять элементы коллекции (вызовет ConcurrentModificationException) и изменять структуру коллекции во время итерации.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История технологий сегодня — 24 Февраля
ℹ️ Кто родился в этот день
Сти́вен Пол (Стив) Джобс (англ. Steven Paul «Steve» Jobs; имя при рождении — Абдул Латиф Джандали; 24 февраля 1955, Сан-Франциско, Калифорния — 5 октября 2011, Пало-Алто, Санта-Клара, Калифорния) — американский предприниматель, изобретатель и промышленный дизайнер, получивший широкое признание в качестве пионера эры информационных технологий. Один из основателей, председатель совета директоров и CEO корпорации Apple. Один из основателей и CEO киностудии Pixar.
Ян Борисович Кум (род. 24 февраля 1976, Киев) — американский предприниматель и программист, сооснователь и CEO мессенджера WhatsApp.
Григо́рий Алекса́ндрович Маргу́лис (род. 24 февраля 1946, Москва) — советский и американский математик, доктор физико-математических наук (1978), научный сотрудник Института проблем передачи информации РАН, профессор Йельского университета (США), лауреат Филдсовской (1978), Абелевской (2020) премий и премии Вольфа (2004/05).
🌐 Знаковые события
Не нашел(
#Biography #Birth_Date #Events #24февраля
Сти́вен Пол (Стив) Джобс (англ. Steven Paul «Steve» Jobs; имя при рождении — Абдул Латиф Джандали; 24 февраля 1955, Сан-Франциско, Калифорния — 5 октября 2011, Пало-Алто, Санта-Клара, Калифорния) — американский предприниматель, изобретатель и промышленный дизайнер, получивший широкое признание в качестве пионера эры информационных технологий. Один из основателей, председатель совета директоров и CEO корпорации Apple. Один из основателей и CEO киностудии Pixar.
Ян Борисович Кум (род. 24 февраля 1976, Киев) — американский предприниматель и программист, сооснователь и CEO мессенджера WhatsApp.
Григо́рий Алекса́ндрович Маргу́лис (род. 24 февраля 1946, Москва) — советский и американский математик, доктор физико-математических наук (1978), научный сотрудник Института проблем передачи информации РАН, профессор Йельского университета (США), лауреат Филдсовской (1978), Абелевской (2020) премий и премии Вольфа (2004/05).
Не нашел(
#Biography #Birth_Date #Events #24февраля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4