Варианты ответа:
Anonymous Quiz
7%
'' isEmpty: false
20%
' ' isEmpty: false
53%
'' isEmpty: true
20%
NullPointerException
👍1
Вопрос с собеседований
Что такое паттерн Mediator?🤓
Ответ:
Mediator — паттерн для централизованного общения объектов.
Пример:
interface Mediator {
void notify(Component sender, String event);
}
class ConcreteMediator implements Mediator { /* Логика */ }
class Component {
protected Mediator mediator;
}
Снижает coupling в системах вроде чатов.
#собеседование
Что такое паттерн Mediator?
Ответ:
Mediator
Пример:
interface Mediator {
void notify(Component sender, String event);
}
class ConcreteMediator implements Mediator { /* Логика */ }
class Component {
protected Mediator mediator;
}
Снижает coupling в системах вроде чатов.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Натаниэль С. Боренштейн (родился 23 сентября 1957 года) — американский учёный-компьютерщик . Он был одним из первых разработчиков протокола MIME для форматирования мультимедийных электронных писем в Интернете и первым отправил вложение к электронному письму.
Линь-Шань Ли (кит .李琳山; родился 23 сентября 1952 г.) — тайваньский компьютерный учёный; внёс вклад в распознавание и синтез речи, особо для китайского языка, и в технологии поиска по речи и речи-в-текст.
1873 — в Петербурге вместо керосиновых ламп зажглись первые в мире электрические фонари.
1997 — была анонсирована поисковая машина Yandex.Ru.
#Biography #Birth_Date #Events #23Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Реактивное программирование
Концепции реактивного программирования: Push vs Pull — кто управляет данными
Сегодня разберём модели Push (отправку данных) и Pull (получение данных), почему одна из них идеальна для реактивного стиля, и как это решает проблемы из первого поста: от тяжёлых потоков до callback-ада.
Представьте: у вас есть конвейер на фабрике. В pull-модели рабочий сам подходит к предыдущему этапу и "берет" деталь, когда ему нужно. В push-модели предыдущий этап "отправляет" деталь дальше, как только она готова, не спрашивая.
Какая модель лучше? Зависит от сценария. В программировании это то же самое: pull подходит для предсказуемых, контролируемых потоков, а push — для динамичных, событийных, где данные приходят непредсказуемо (сеть, пользователи, сенсоры).
Реактивное программирование строится на push — и вот почему это революция.
Pull-модель: вы контролируете темп, но рискуете блокировками
В традиционном императивном программировании (когда код выполняется шаг за шагом, как рецепт) данные обычно "получаются" по требованию. Это pull-модель: потребитель (ваш код) сам запрашивает данные, когда готов их обработать.
Пример — чтение из итератора в Java:
Здесь вы контролируете процесс: hasNext() проверяет наличие, next() получает элемент. Это удобно для локальных, синхронных данных — вы знаете, сколько элементов, и ничего не ждёте. Но под капотом это синхронно: если данные в потоке (файл, сеть), next() может заблокироваться, как в старых потоках. Поток висит в ожидании, ресурсы тратятся впустую.
В асинхронных сценариях pull эволюционировал в Future или CompletableFuture: вы "запрашиваете" результат через get() или цепочки, но контроль остаётся у вас.
Проблема: если источник данных медленный (БД, API), ваш pull-запрос блокирует или создаёт callback-ад. Под нагрузкой — тысячи pull-запросов — система не масштабируется, потому что каждый требует ресурса (потока). Это как толпа в очереди: каждый тянет за своим, но если касса одна, все стоят.
Ещё минус: pull не справляется с "лишними" данными. Если источник генерирует 1 млн событий в секунду, а вы получаете по одному — либо перегрузка буфера, либо вы не успеваете. Нет встроенного механизма, чтобы сказать "замедлись".
#Java #middle #Reactor #Push #Flux
Концепции реактивного программирования: Push vs Pull — кто управляет данными
Сегодня разберём модели Push (отправку данных) и Pull (получение данных), почему одна из них идеальна для реактивного стиля, и как это решает проблемы из первого поста: от тяжёлых потоков до callback-ада.
Представьте: у вас есть конвейер на фабрике. В pull-модели рабочий сам подходит к предыдущему этапу и "берет" деталь, когда ему нужно. В push-модели предыдущий этап "отправляет" деталь дальше, как только она готова, не спрашивая.
Какая модель лучше? Зависит от сценария. В программировании это то же самое: pull подходит для предсказуемых, контролируемых потоков, а push — для динамичных, событийных, где данные приходят непредсказуемо (сеть, пользователи, сенсоры).
Реактивное программирование строится на push — и вот почему это революция.
Pull-модель: вы контролируете темп, но рискуете блокировками
В традиционном императивном программировании (когда код выполняется шаг за шагом, как рецепт) данные обычно "получаются" по требованию. Это pull-модель: потребитель (ваш код) сам запрашивает данные, когда готов их обработать.
Пример — чтение из итератора в Java:
List<String> fruits = Arrays.asList("яблоко", "банан", "вишня");
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
String fruit = iterator.next(); // "Вытягиваем" следующий элемент
System.out.println(fruit.toUpperCase());
}
Здесь вы контролируете процесс: hasNext() проверяет наличие, next() получает элемент. Это удобно для локальных, синхронных данных — вы знаете, сколько элементов, и ничего не ждёте. Но под капотом это синхронно: если данные в потоке (файл, сеть), next() может заблокироваться, как в старых потоках. Поток висит в ожидании, ресурсы тратятся впустую.
В асинхронных сценариях pull эволюционировал в Future или CompletableFuture: вы "запрашиваете" результат через get() или цепочки, но контроль остаётся у вас.
Проблема: если источник данных медленный (БД, API), ваш pull-запрос блокирует или создаёт callback-ад. Под нагрузкой — тысячи pull-запросов — система не масштабируется, потому что каждый требует ресурса (потока). Это как толпа в очереди: каждый тянет за своим, но если касса одна, все стоят.
Ещё минус: pull не справляется с "лишними" данными. Если источник генерирует 1 млн событий в секунду, а вы получаете по одному — либо перегрузка буфера, либо вы не успеваете. Нет встроенного механизма, чтобы сказать "замедлись".
#Java #middle #Reactor #Push #Flux
👍3
Push-модель: данные приходят сами, реактивно и эффективно
Теперь изменим: в push-модели источник "отправляет" данные потребителю, как только они готовы, без запросов. Потребитель пассивен — он подписывается и реагирует.
Это основа реактивного программирования: события push'атся асинхронно, без блокировок. Контроль переходит к источнику, но с обратным давлением — подписчик может сказать "хватит на время".
В Reactive Streams это реализовано через Publisher и Subscriber: издатель толкает onNext(элемент), подписчик реагирует сразу.
Пример с Flux в Project Reactor (push-стиль):
Здесь Flux — издатель, который отправляет элементы по мере готовности. subscribe() — подписка, и элементы приходят автоматически: "ЯБЛОКО", "БАНАН"... Нет next() — нет pull.
Если источник асинхронный, например, чтение из сети:
Данные push'атся по мере поступления от сервера — без блокировок. Reactor использует неблокирующий IO (на базе Netty), так что поток не висит: один event-loop-цикл (цикл обработки событий) обслуживает тысячи подписок.
Почему push лучше для реактивности?
Во-первых, эффективность: нет лишних проверок hasNext().
Во-вторых, естественность для событий: клик мыши, сообщение в чате — это push по природе, они приходят сами.
В-третьих, масштабируемость: тысячи подписчиков на один издатель — ок, потому что push идёт через события, а не потоки на каждого.
Гибридные сценарии: когда mix работает
На практике модели смешиваются. В Reactor Flux может имитировать pull через операторы вроде buffer() или take(), но основа — push.
Пример: pull из локального списка, но push в сеть:
Здесь локальный pull (fromIterable) переходит в push (flatMap для API).
Это гибкость: используйте pull для контроля, push для асинхронности. Но важно избегать блокировок: Reactor проверяет и предупреждает, если в лямбде блокирующий код (onBlock()).
Ещё пример из реальной жизни: стриминг видео в Netflix. Pull — когда пользователь сам получает фреймы, но под нагрузкой лагает. Push — сервер отдает фреймы по мере готовности, с буферизацией. Реактивные библиотеки (как RxJava) позволяют строить такие конвейеры.
Почему Push — ключ к новому подходу в реактивном программировании
Возвращаясь к проблемам: потоки тяжёлые, потому что pull требует ожидания; Future блокирует на get(), потому что это pull в асинхронной обёртке; CompletableFuture даёт цепочки, но push-подход в нём слаб (колбэки — это мини-push, но без полного контроля).
Реактивный push меняет всё: данные текут как река, вы реагируете без ожидания, ресурсы на минимуме. Системы становятся resilient (устойчивыми): если один поток сломается, другие продолжают. Под нагрузкой — горизонтальное масштабирование без боли.
#Java #middle #Reactor #Push #Flux
Теперь изменим: в push-модели источник "отправляет" данные потребителю, как только они готовы, без запросов. Потребитель пассивен — он подписывается и реагирует.
Это основа реактивного программирования: события push'атся асинхронно, без блокировок. Контроль переходит к источнику, но с обратным давлением — подписчик может сказать "хватит на время".
В Reactive Streams это реализовано через Publisher и Subscriber: издатель толкает onNext(элемент), подписчик реагирует сразу.
Пример с Flux в Project Reactor (push-стиль):
Flux<String> pushFlux = Flux.fromIterable(Arrays.asList("яблоко", "банан", "вишня"))
.map(String::toUpperCase); // Преобразование в потоке
pushFlux.subscribe(
fruit -> System.out.println("Получено из push: " + fruit), // Реакция на толкание
Throwable::printStackTrace, // Обработка ошибок
() -> System.out.println("Push завершён")
);
Здесь Flux — издатель, который отправляет элементы по мере готовности. subscribe() — подписка, и элементы приходят автоматически: "ЯБЛОКО", "БАНАН"... Нет next() — нет pull.
Если источник асинхронный, например, чтение из сети:
WebClient.create()
.get()
.uri("https://api.example.com/fruits")
.retrieve()
.bodyToFlux(String.class) // Flux толкает строки из ответа
.subscribe(fruit -> System.out.println("Push из API: " + fruit));
Данные push'атся по мере поступления от сервера — без блокировок. Reactor использует неблокирующий IO (на базе Netty), так что поток не висит: один event-loop-цикл (цикл обработки событий) обслуживает тысячи подписок.
Почему push лучше для реактивности?
Во-первых, эффективность: нет лишних проверок hasNext().
Во-вторых, естественность для событий: клик мыши, сообщение в чате — это push по природе, они приходят сами.
В-третьих, масштабируемость: тысячи подписчиков на один издатель — ок, потому что push идёт через события, а не потоки на каждого.
Гибридные сценарии: когда mix работает
На практике модели смешиваются. В Reactor Flux может имитировать pull через операторы вроде buffer() или take(), но основа — push.
Пример: pull из локального списка, но push в сеть:
Flux.fromIterable(fruits)
.map(String::toUpperCase)
.flatMap(fruit -> sendToApi(fruit)) // flatMap толкает в асинхронный API
.subscribe(result -> System.out.println("Ответ: " + result));
Здесь локальный pull (fromIterable) переходит в push (flatMap для API).
Это гибкость: используйте pull для контроля, push для асинхронности. Но важно избегать блокировок: Reactor проверяет и предупреждает, если в лямбде блокирующий код (onBlock()).
Ещё пример из реальной жизни: стриминг видео в Netflix. Pull — когда пользователь сам получает фреймы, но под нагрузкой лагает. Push — сервер отдает фреймы по мере готовности, с буферизацией. Реактивные библиотеки (как RxJava) позволяют строить такие конвейеры.
Почему Push — ключ к новому подходу в реактивном программировании
Возвращаясь к проблемам: потоки тяжёлые, потому что pull требует ожидания; Future блокирует на get(), потому что это pull в асинхронной обёртке; CompletableFuture даёт цепочки, но push-подход в нём слаб (колбэки — это мини-push, но без полного контроля).
Реактивный push меняет всё: данные текут как река, вы реагируете без ожидания, ресурсы на минимуме. Системы становятся resilient (устойчивыми): если один поток сломается, другие продолжают. Под нагрузкой — горизонтальное масштабирование без боли.
#Java #middle #Reactor #Push #Flux
👍3
А вы готовы для устройства на работу в IT, подделать документы, трудовую и тд? 🤫
Anonymous Poll
26%
Да, конечно, а как по другому? ✌️
9%
Наверное да, но оооочееееень осторожно. 😉
11%
Не знаю. 🤷♀️
6%
Наверное нет. Я опасаюсь. 😏
49%
Точно нет. Я не нарушаю законов. 👮
👍1
Что выведет код?
#Tasks
import java.util.Random;
public class Task230925 {
public static void main(String[] args) {
Random rand1 = new Random(42);
Random rand2 = new Random(42);
System.out.println(rand1.nextInt(100) == rand2.nextInt(100));
}
}
#Tasks
👍2
Варианты ответа:
Anonymous Quiz
34%
true
14%
false
14%
Ошибка компиляции
38%
Иногда true, иногда false
👍5
Please open Telegram to view this post
VIEW IN TELEGRAM
Сетка
Java for Beginner. Канал в Сетке
Канал для новичков в Java
👍1
Вопрос с собеседований
Что такое teeing в Stream API?🤓
Ответ:
Метод Collectors.teeing() применяет два коллектора и объединяет результаты.
Пример:
List<Integer> list = Arrays.asList(1, 2, 3);
String result = list.stream ().collect(Collectors.teeing(
Collectors.summingInt(i -> i),
Collectors.counting(),
(sum, count) -> "Sum: " + sum + ", Count: " + count
)); // Sum: 6, Count: 3
Для множественных агрегаций.
#собеседование
Что такое teeing в Stream API?
Ответ:
Метод Collectors.teeing()
Пример:
List<Integer> list = Arrays.asList(1, 2, 3);
String result =
Collectors.summingInt(i -> i),
Collectors.counting(),
(sum, count) -> "Sum: " + sum + ", Count: " + count
)); // Sum: 6, Count: 3
Для множественных агрегаций.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Серге́й Влади́мирович Абламе́йко (бел. Сярге́й Уладзі́міравіч Абламе́йка; род. 24 сентября 1956, Вороново, Гродненская область) — белорусский математик и учёный в области информатики и технологий, профессор, академик НАН Беларуси. Специалист по распознаванию образов и обработке графической информации; под его руководством создана сильная школа и программные комплексы, применяемые в картографии, медицине и машиностроении.
Сергей Савостьянович Гончаров (род. 24 сентября 1951) — советский/российский математик, академик; работает в теории вычислимости и математической логике, руководитель научных подразделений, преподаватель информатики и дискретной математики.
Александр Леонидович Асеев (род. 24 сентября 1946) — академик РАН, специалист по элементной базе микроэлектроники; его исследования в полупроводниках (кремний, германий) важны для компонентной основы вычислительной техники.
Вернер Цорн (родился 24 сентября 1942 года во Франкфурте-на-Майне) — немецкий учёный-информатик, один из пионеров интернета; был профессором и занимался системами коммуникаций, распознаванием символов и классификаторами.
Энтони Джеймс Барр (родился 24 сентября 1940 года) — американский разработчик языков программирования и программного обеспечения; внес вклад в Statistical Analysis System (SAS) и другие системы для анализа данных и классификации.
1970 — межпланетная станция «Луна-16» доставила на Землю лунный грунт.
2014 — индийская АМС «Мангальян» вышла на орбиту Марса
2023 — капсула с американской АМС OSIRIS-REx с грунтом астероида (101955) Бенну успешно вернулась на Землю.
#Biography #Birth_Date #Events #24Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Реактивное программирование
Концепции реактивного программирования: Reactive Streams API — Publisher и Subscriber
Сегодня разберём Reactive Streams API — это спецификация, которая лежит в сердце реактивного программирования на Java. Она не просто набор интерфейсов, а рамка для построения асинхронных потоков данных с контролем над ними. Представьте это как правила дорожного движения для потока событий: без них — хаос и пробки, с ними — плавный поток.
Reactive Streams API решает ключевые проблемы из первого поста: вместо тяжёлых потоков и callback-ада, мы получаем унифицированный способ обмена данными между компонентами. Это не библиотека, а интерфейсы, которые реализуют фреймворки вроде Project Reactor или RxJava. Они обеспечивают совместимость: один компонент от Reactor может работать с другим от Akka Streams.
Что такое Reactive Streams API
Спецификация Reactive Streams появилась в 2015 году как ответ на хаос асинхронности. До неё каждый фреймворк изобретал велосипед: свои способы обработки потоков, ошибок и давления.
API стандартизирует это: четыре интерфейса (Publisher, Subscriber, Subscription, Processor), которые описывают, как данные текут асинхронно. Главная идея — неблокирующая коммуникация: ничего не ждём синхронно, всё через события.
Это подводит нас ближе к реактивному мышлению: вместо "запроси и жди" (как в Future.get()), мы "подпишись и реагируй". Под нагрузкой это экономит ресурсы: один поток (event-loop) может обслуживать тысячи подписок, без создания новых на каждую задачу. В итоге, системы становятся более отзывчивыми и масштабируемыми — идеально для микросервисов или реального времени.
Publisher: источник данных, который отправляет события
Publisher — это интерфейс для издателя, который генерирует поток данных.
Он как фабрика событий: производит элементы (любые объекты), ошибки или сигнал завершения. Publisher не знает, кто его слушает, — он просто готов отправлять (push) данные, когда они появятся.
Интерфейс прост: всего один метод subscribe(Subscriber s). Когда вы вызываете его, издатель регистрирует подписчика и начинает процесс. Но данные не льются сразу — всё под контролем (об этом ниже).
Пример простого издателя в Project Reactor (который реализует Reactive Streams):
Здесь publisher — источник.
Он может быть асинхронным: например, читать из сети или БД. Когда данные готовы, он отправляет их подписчику через onNext(элемент).
Если ошибка — onError(Throwable).
Если конец — onComplete().
Почему это лучше традиционных подходов? В отличие от потоков (где каждый запрос — отдельный тяжёлый объект), publisher лёгкий: он не выделяет ресурсы заранее, а реагирует на подписку. Нет блокировок: если данных нет, ничего не происходит.
#Java #middle #Reactor #Reactive_Streams_API #Processor #Subscription #Subscriber #Publisher
Концепции реактивного программирования: Reactive Streams API — Publisher и Subscriber
Сегодня разберём Reactive Streams API — это спецификация, которая лежит в сердце реактивного программирования на Java. Она не просто набор интерфейсов, а рамка для построения асинхронных потоков данных с контролем над ними. Представьте это как правила дорожного движения для потока событий: без них — хаос и пробки, с ними — плавный поток.
Reactive Streams API решает ключевые проблемы из первого поста: вместо тяжёлых потоков и callback-ада, мы получаем унифицированный способ обмена данными между компонентами. Это не библиотека, а интерфейсы, которые реализуют фреймворки вроде Project Reactor или RxJava. Они обеспечивают совместимость: один компонент от Reactor может работать с другим от Akka Streams.
Что такое Reactive Streams API
Спецификация Reactive Streams появилась в 2015 году как ответ на хаос асинхронности. До неё каждый фреймворк изобретал велосипед: свои способы обработки потоков, ошибок и давления.
API стандартизирует это: четыре интерфейса (Publisher, Subscriber, Subscription, Processor), которые описывают, как данные текут асинхронно. Главная идея — неблокирующая коммуникация: ничего не ждём синхронно, всё через события.
Это подводит нас ближе к реактивному мышлению: вместо "запроси и жди" (как в Future.get()), мы "подпишись и реагируй". Под нагрузкой это экономит ресурсы: один поток (event-loop) может обслуживать тысячи подписок, без создания новых на каждую задачу. В итоге, системы становятся более отзывчивыми и масштабируемыми — идеально для микросервисов или реального времени.
Publisher: источник данных, который отправляет события
Publisher — это интерфейс для издателя, который генерирует поток данных.
Он как фабрика событий: производит элементы (любые объекты), ошибки или сигнал завершения. Publisher не знает, кто его слушает, — он просто готов отправлять (push) данные, когда они появятся.
Интерфейс прост: всего один метод subscribe(Subscriber s). Когда вы вызываете его, издатель регистрирует подписчика и начинает процесс. Но данные не льются сразу — всё под контролем (об этом ниже).
Пример простого издателя в Project Reactor (который реализует Reactive Streams):
import reactor.core.publisher.Flux; // Flux реализует Publisher
Flux<Integer> publisher = Flux.range(1, 5); // Издатель: поток от 1 до 5
Здесь publisher — источник.
Он может быть асинхронным: например, читать из сети или БД. Когда данные готовы, он отправляет их подписчику через onNext(элемент).
Если ошибка — onError(Throwable).
Если конец — onComplete().
Почему это лучше традиционных подходов? В отличие от потоков (где каждый запрос — отдельный тяжёлый объект), publisher лёгкий: он не выделяет ресурсы заранее, а реагирует на подписку. Нет блокировок: если данных нет, ничего не происходит.
#Java #middle #Reactor #Reactive_Streams_API #Processor #Subscription #Subscriber #Publisher
👍1
Subscriber: получатель, который реагирует на события
Subscriber — интерфейс для подписчика, который "слушает" издателя. Он как потребитель на конвейере: получает элементы и решает, что с ними делать.
Методы:
- onSubscribe(Subscription s): вызывается сразу после подписки. Здесь подписчик получает подписку — объект для контроля.
- onNext(T item): срабатывает на каждый элемент. Здесь обработка: логика, трансформация и т.д.
- onError(Throwable t): если ошибка — обработка исключения.
- onComplete(): поток завершён успешно.
Подписчик пассивен: не получает данные (pull), а ждёт push. Это решает callback-ад из CompletableFuture — реакции в одном месте, код чище.
Пример подписки:
Здесь subscribe() связывает publisher и subscriber. Данные отправляются по одному, по запросу (request(1)). Это асинхронно: код после subscribe() продолжается сразу, без ожидания.
В Reactor есть BaseSubscriber для упрощения — переопределяйте только нужные методы.
Subscription: мост контроля с обратным давлением
Subscription — ключ к управлению: это объект, который подписчик получает в onSubscribe.
Методы:
- request(long n): "Дай мне n элементов". Это обратное давление (backpressure) — подписчик контролирует темп, чтобы не захлебнуться.
- cancel(): "Хватит, отпишись".
Без этого publisher мог бы зафлудить подписчика данными. Например, если источник — бесконечный поток (сенсоры), без request(n) — переполнение памяти.
В примере выше request(1) делает обработку последовательной: получил — обработал — запросил следующий. Для скорости — request(Long.MAX_VALUE) (неограниченно), но осторожно: рискуете буфером.
Это решает проблемы блокировок: вместо висящих потоков, всё в event-loop. Под нагрузкой — graceful degradation (грациозная деградация): если подписчик медленный, publisher замедляется, а не падает.
Processor: промежуточный звено для трансформаций
Processor — комбо: реализует и Publisher, и Subscriber. Он как фильтр в конвейере: принимает данные от одного издателя, обрабатывает и отправляет дальше.
Пример — в цепочках Flux: map() или filter() создают процессоры внутри.
В практике вы редко пишете свой Processor — библиотеки предоставляют готовые операторы. Но понимание помогает: весь конвейер — цепь publisher → processor → ... → subscriber.
Практические советы и подводные камни
- Всегда управляйте подпиской: без request() данные не потекут (по умолчанию unbounded — неограниченно, но лучше явно).
- Обрабатывайте ошибки: onError — ваш спасатель, чтобы не потерять исключения.
- Тестируйте с TestSubscriber (в Reactor): симулируйте сценарии.
- Камень: если в onNext блокирующий код — сломаете асинхронность. Используйте Schedulers для offload (перенос на другой поток).
В реальном коде: в Spring WebFlux контроллеры возвращают Flux/Mono — publisher'ы, клиенты подписываются.
#Java #middle #Reactor #Reactive_Streams_API #Processor #Subscription #Subscriber
Subscriber — интерфейс для подписчика, который "слушает" издателя. Он как потребитель на конвейере: получает элементы и решает, что с ними делать.
Методы:
- onSubscribe(Subscription s): вызывается сразу после подписки. Здесь подписчик получает подписку — объект для контроля.
- onNext(T item): срабатывает на каждый элемент. Здесь обработка: логика, трансформация и т.д.
- onError(Throwable t): если ошибка — обработка исключения.
- onComplete(): поток завершён успешно.
Подписчик пассивен: не получает данные (pull), а ждёт push. Это решает callback-ад из CompletableFuture — реакции в одном месте, код чище.
Пример подписки:
publisher.subscribe(new Subscriber<Integer>() {
private Subscription subscription;
@Override
public void onSubscribe(Subscription s) {
this.subscription = s;
s.request(1); // Запрашиваем первый элемент
}
@Override
public void onNext(Integer item) {
System.out.println("Получено: " + item);
subscription.request(1); // Запрашиваем следующий
}
@Override
public void onError(Throwable t) {
System.err.println("Ошибка: " + t);
}
@Override
public void onComplete() {
System.out.println("Завершено");
}
});
Здесь subscribe() связывает publisher и subscriber. Данные отправляются по одному, по запросу (request(1)). Это асинхронно: код после subscribe() продолжается сразу, без ожидания.
В Reactor есть BaseSubscriber для упрощения — переопределяйте только нужные методы.
Subscription: мост контроля с обратным давлением
Subscription — ключ к управлению: это объект, который подписчик получает в onSubscribe.
Методы:
- request(long n): "Дай мне n элементов". Это обратное давление (backpressure) — подписчик контролирует темп, чтобы не захлебнуться.
- cancel(): "Хватит, отпишись".
Без этого publisher мог бы зафлудить подписчика данными. Например, если источник — бесконечный поток (сенсоры), без request(n) — переполнение памяти.
В примере выше request(1) делает обработку последовательной: получил — обработал — запросил следующий. Для скорости — request(Long.MAX_VALUE) (неограниченно), но осторожно: рискуете буфером.
Это решает проблемы блокировок: вместо висящих потоков, всё в event-loop. Под нагрузкой — graceful degradation (грациозная деградация): если подписчик медленный, publisher замедляется, а не падает.
Processor: промежуточный звено для трансформаций
Processor — комбо: реализует и Publisher, и Subscriber. Он как фильтр в конвейере: принимает данные от одного издателя, обрабатывает и отправляет дальше.
Пример — в цепочках Flux: map() или filter() создают процессоры внутри.
В практике вы редко пишете свой Processor — библиотеки предоставляют готовые операторы. Но понимание помогает: весь конвейер — цепь publisher → processor → ... → subscriber.
Практические советы и подводные камни
- Всегда управляйте подпиской: без request() данные не потекут (по умолчанию unbounded — неограниченно, но лучше явно).
- Обрабатывайте ошибки: onError — ваш спасатель, чтобы не потерять исключения.
- Тестируйте с TestSubscriber (в Reactor): симулируйте сценарии.
- Камень: если в onNext блокирующий код — сломаете асинхронность. Используйте Schedulers для offload (перенос на другой поток).
В реальном коде: в Spring WebFlux контроллеры возвращают Flux/Mono — publisher'ы, клиенты подписываются.
#Java #middle #Reactor #Reactive_Streams_API #Processor #Subscription #Subscriber
👍1
Вы верите, что в современном интернете можно сохранить анонимность?
Anonymous Poll
26%
Да, но для этого надо самому постараться, используя специальные методики и технологии.
6%
Наверно, если не оставлять цифровых следов.
3%
Не знаю, никогда не задумывался.
32%
Наверное нет. Ведь каждый провайдер знает о клиенте почти все.
32%
Точно нет. Информация о каждом уже есть в интернете.
👍1
Что выведет код?
#Tasks
import java.util.HashMap;
public class Task240925 {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put(new String("a"), 2);
System.out.println(map.size());
System.out.println(map.get("a"));
}
}
#Tasks
👍1
👍1
Продолжаем выбирать темы для разбора и голосовать за рассмотрение предложенных! 🤓
Голосуем за тему к рассмотрению в эти выходные!
Выбираем новую тему!
(можете предложить что-то из того, что предлагали на прошлой и позапрошлых неделях и что проиграло в голосовании!)
Не стесняемся!✌️
Голосуем за тему к рассмотрению в эти выходные!
Выбираем новую тему!
(можете предложить что-то из того, что предлагали на прошлой и позапрошлых неделях и что проиграло в голосовании!)
Не стесняемся!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Вопрос с собеседований
Что такое байт-код?🤓
Ответ:
Байт-код — это промежуточное представление Java-программы после компиляции.
Он не зависит от платформы и исполняется JVM. Это позволяет запускать один и тот же код на разных ОС, не меняя программу.
Байт-код лежит в .class файлах, создаваемых компилятором javac.
#собеседование
Что такое байт-код?
Ответ:
Байт-код
Он не зависит от платформы и исполняется JVM. Это позволяет запускать один и тот же код на разных ОС, не меняя программу.
Байт-код лежит в .class файлах, создаваемых компилятором javac.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Алексе́й Андре́евич Ляпуно́в (25 сентября [8 октября] 1911, Москва — 23 июня 1973, Москва) — советский математик, один из основоположников кибернетики; работал над теоретическими вопросами программирования, математической логикой и математической лингвистикой.
Серге́й Влади́мирович Русако́в (род. 25 сентября 1954, Молотов) — советский/российский математик и профессор, заведующий кафедрой прикладной математики и информатики; лидер направления «моделирование, анализ и управление сложными динамическими системами».
Уильям Даниэль «Дэнни» Хиллис (англ. William Daniel "Danny" Hillis, родился 25 сентября 1956) — американский учёный, инженер и предприниматель, пионер параллельных компьютеров, основатель Thinking Machines Corporation; внёс значительный вклад в аппаратные и программные подходы к параллелизму.
1906 — испанский математик и инженер Леонардо Торрес-и-Кеведо продемонстрировал одно из первых в мире радиоуправляемых устройств — «Telekino».
#Biography #Birth_Date #Events #25Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Основы ООП в Java
Глава 7. Принципы проектирования и хорошего кода
Композиция vs Наследование
В объектно-ориентированном программировании композиция и наследование — это два способа организации кода для повторного использования и связи между классами. Они решают разные задачи и подходят для разных ситуаций.
Наследование:
Механизм, при котором класс (подкласс) наследует поля, методы и поведение от другого класса (суперкласса) с помощью ключевого слова extends. Это воплощает отношение "является" (is-a). Например, Dog является Animal.
Композиция:
Механизм, при котором класс содержит объекты других классов как поля, используя их функциональность. Это воплощает отношение "имеет" (has-a). Например, Car имеет Engine.
Оба подхода позволяют повторно использовать код, но их применение влияет на гибкость, читаемость и масштабируемость программы.
Наследование: Когда использовать и проблемы
Наследование удобно, когда классы имеют четкое отношение "является", и подкласс естественным образом расширяет поведение суперкласса.
Пример наследования:
Когда использовать:
Есть четкое is-a отношение: Dog — это Animal.
Нужно переопределить или расширить поведение (через override).
Полиморфизм: Работа с подклассами через ссылку на суперкласс (Animal[] animals).
Преимущества:
Простота: Код автоматически наследуется.
Полиморфизм: Легко реализовать через override.
Иерархия: Удобно для моделирования реальных сущностей (например, Животное → Млекопитающее → Собака).
Недостатки:
Жесткая связь: Подкласс привязан к суперклассу — изменения в суперклассе могут сломать подклассы.
Хрупкий базовый класс: Изменение метода в суперклассе может неожиданно повлиять на подклассы.
Ограничение Java: Только одиночное наследование (один extends).
Сложность в глубоких иерархиях: Много уровней наследования трудно поддерживать.
Нарушение инкапсуляции: Подклассы могут зависеть от внутренней реализации.
Пример проблемы: Если добавить метод в Animal, который не подходит для всех подклассов (например, fly()), подклассы вроде Dog окажутся в неудобном положении.
Композиция: Когда использовать и преимущества
Композиция — это включение объектов других классов как полей, чтобы использовать их функциональность. Это отношения, где класс владеет компонентами.
Пример композиции:
Использование:
Когда использовать:
Отношения: Car имеет Engine, а не является им.
Нужно гибкое сочетание функциональности без жесткой связи.
Требуется заменяемость компонентов (например, разные двигатели).
Преимущества:
Гибкость: Легко заменить компонент (например, Engine на ElectricEngine).
Слабая связь: Изменения в Engine не ломают Car, если интерфейс сохранен.
Инкапсуляция: Car скрывает детали Engine, управляя доступом.
Модульность: Компоненты можно использовать в других классах.
Тестирование: Легче подменять компоненты (mocking) для тестов.
#Java #для_новичков #beginner #OOP #Composition #Extends
Глава 7. Принципы проектирования и хорошего кода
Композиция vs Наследование
В объектно-ориентированном программировании композиция и наследование — это два способа организации кода для повторного использования и связи между классами. Они решают разные задачи и подходят для разных ситуаций.
Наследование:
Механизм, при котором класс (подкласс) наследует поля, методы и поведение от другого класса (суперкласса) с помощью ключевого слова extends. Это воплощает отношение "является" (is-a). Например, Dog является Animal.
Композиция:
Механизм, при котором класс содержит объекты других классов как поля, используя их функциональность. Это воплощает отношение "имеет" (has-a). Например, Car имеет Engine.
Оба подхода позволяют повторно использовать код, но их применение влияет на гибкость, читаемость и масштабируемость программы.
Наследование: Когда использовать и проблемы
Наследование удобно, когда классы имеют четкое отношение "является", и подкласс естественным образом расширяет поведение суперкласса.
Пример наследования:
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void makeSound() {
System.out.println(name + " издает звук.");
}
}
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println(name + " лает: Гав!");
}
}
Когда использовать:
Есть четкое is-a отношение: Dog — это Animal.
Нужно переопределить или расширить поведение (через override).
Полиморфизм: Работа с подклассами через ссылку на суперкласс (Animal[] animals).
Преимущества:
Простота: Код автоматически наследуется.
Полиморфизм: Легко реализовать через override.
Иерархия: Удобно для моделирования реальных сущностей (например, Животное → Млекопитающее → Собака).
Недостатки:
Жесткая связь: Подкласс привязан к суперклассу — изменения в суперклассе могут сломать подклассы.
Хрупкий базовый класс: Изменение метода в суперклассе может неожиданно повлиять на подклассы.
Ограничение Java: Только одиночное наследование (один extends).
Сложность в глубоких иерархиях: Много уровней наследования трудно поддерживать.
Нарушение инкапсуляции: Подклассы могут зависеть от внутренней реализации.
Пример проблемы: Если добавить метод в Animal, который не подходит для всех подклассов (например, fly()), подклассы вроде Dog окажутся в неудобном положении.
Композиция: Когда использовать и преимущества
Композиция — это включение объектов других классов как полей, чтобы использовать их функциональность. Это отношения, где класс владеет компонентами.
Пример композиции:
public class Engine {
private int horsepower;
public Engine(int horsepower) {
this.horsepower = horsepower;
}
public void start() {
System.out.println("Двигатель с " + horsepower + " л.с. запущен.");
}
}
public class Car {
private String model;
private Engine engine; // Композиция: Car "имеет" Engine
public Car(String model, Engine engine) {
this.model = model;
this.engine = engine;
}
public void drive() {
engine.start();
System.out.println(model + " едет.");
}
}
Использование:
public class Main {
public static void main(String[] args) {
Engine engine = new Engine(200);
Car car = new Car("Toyota", engine);
car.drive(); // Двигатель с 200 л.с. запущен. Toyota едет.
}
}
Когда использовать:
Отношения: Car имеет Engine, а не является им.
Нужно гибкое сочетание функциональности без жесткой связи.
Требуется заменяемость компонентов (например, разные двигатели).
Преимущества:
Гибкость: Легко заменить компонент (например, Engine на ElectricEngine).
Слабая связь: Изменения в Engine не ломают Car, если интерфейс сохранен.
Инкапсуляция: Car скрывает детали Engine, управляя доступом.
Модульность: Компоненты можно использовать в других классах.
Тестирование: Легче подменять компоненты (mocking) для тестов.
#Java #для_новичков #beginner #OOP #Composition #Extends
👍4
Недостатки:
Больше кода: Нужно явно создавать и передавать компоненты.
Сложнее полиморфизм: Требуются интерфейсы для единообразия.
Композиция vs Наследование: Как выбирать
Выбирайте композицию, если:
Нет четкого is-a отношения, а скорее has-a.
Нужна гибкость: Компоненты могут меняться (например, разные реализации Engine).
Хотите избежать жесткой связи или хрупкого базового класса.
Нужно реализовать поведение, которое не должно быть частью иерархии.
Выбирайте наследование, если:
Есть четкое is-a отношение, и подкласс логично расширяет суперкласс.
Нужен полиморфизм через ссылки на суперкласс.
Иерархия простая (1-2 уровня).
Пример: Композиция вместо наследования:
Наследование (проблема):
Все нюансы
Наследование:
Жесткая связь: Подкласс зависит от реализации суперкласса.
Проблема ромба: В Java избежана (одиночное наследование), но множественное через интерфейсы.
Нюанс: Переопределение может нарушить контракт (Liskov Substitution Principle).
Композиция:
Требует интерфейсов для полиморфизма (например, Movable).
Нюанс: Больше кода для передачи компонентов (конструктор, сеттеры).
Делегирование: Car вызывает методы Engine — это нормально.
Когда комбинировать:
Используйте наследование для базовой структуры, композицию для поведения.
Пример: extends AbstractVehicle, но Engine как поле.
Ошибки:
Наследование вместо композиции: Глубокие иерархии или неподходящие is-a.
Композиция без интерфейсов: Теряется полиморфизм.
Дизайн:
Композиция соответствует принципу KISS (меньше связей).
Наследование — YAGNI: Не создавайте иерархии "на будущее".
DRY: Оба подхода помогают повторно использовать код.
Java-специфика:
Интерфейсы + default методы часто заменяют наследование.
Dependency Injection (Spring) — пример композиции.
Как создать это в IntelliJ IDEA
Композиция: Создайте интерфейс (New → Interface), класс с полем и методами.
Наследование: New → Class, укажите extends, IDE поможет override.
Рефакторинг: Extract Interface для перехода от наследования к композиции.
Полезные советы для новичков
Композиция по умолчанию: Если сомневаетесь, начните с has-a.
Проверяйте is-a: Dog is-an Animal? Да. Car is-an Engine? Нет.
Интерфейсы для гибкости: Комбинируйте композицию с интерфейсами.
Избегайте глубоких иерархий: Не больше 2-3 уровней.
#Java #для_новичков #beginner #OOP #Composition #Extends
Больше кода: Нужно явно создавать и передавать компоненты.
Сложнее полиморфизм: Требуются интерфейсы для единообразия.
Композиция vs Наследование: Как выбирать
Выбирайте композицию, если:
Нет четкого is-a отношения, а скорее has-a.
Нужна гибкость: Компоненты могут меняться (например, разные реализации Engine).
Хотите избежать жесткой связи или хрупкого базового класса.
Нужно реализовать поведение, которое не должно быть частью иерархии.
Выбирайте наследование, если:
Есть четкое is-a отношение, и подкласс логично расширяет суперкласс.
Нужен полиморфизм через ссылки на суперкласс.
Иерархия простая (1-2 уровня).
Пример: Композиция вместо наследования:
Наследование (проблема):
public class Vehicle {
public void move() {
System.out.println("Движется с помощью двигателя.");
}
}
public class Car extends Vehicle {
// Проблема: А если электромобиль или велосипед?
}
Композиция (решение):
public interface Movable {
void move();
}
public class EngineMovable implements Movable {
@Override
public void move() {
System.out.println("Движется с помощью двигателя.");
}
}
public class Car {
private Movable movement;
public Car(Movable movement) {
this.movement = movement;
}
public void drive() {
movement.move();
}
}
Теперь Car может использовать любой Movable (двигатель, электромотор), без привязки к иерархии.
Все нюансы
Наследование:
Жесткая связь: Подкласс зависит от реализации суперкласса.
Проблема ромба: В Java избежана (одиночное наследование), но множественное через интерфейсы.
Нюанс: Переопределение может нарушить контракт (Liskov Substitution Principle).
Композиция:
Требует интерфейсов для полиморфизма (например, Movable).
Нюанс: Больше кода для передачи компонентов (конструктор, сеттеры).
Делегирование: Car вызывает методы Engine — это нормально.
Когда комбинировать:
Используйте наследование для базовой структуры, композицию для поведения.
Пример: extends AbstractVehicle, но Engine как поле.
Ошибки:
Наследование вместо композиции: Глубокие иерархии или неподходящие is-a.
Композиция без интерфейсов: Теряется полиморфизм.
Дизайн:
Композиция соответствует принципу KISS (меньше связей).
Наследование — YAGNI: Не создавайте иерархии "на будущее".
DRY: Оба подхода помогают повторно использовать код.
Java-специфика:
Интерфейсы + default методы часто заменяют наследование.
Dependency Injection (Spring) — пример композиции.
Как создать это в IntelliJ IDEA
Композиция: Создайте интерфейс (New → Interface), класс с полем и методами.
Наследование: New → Class, укажите extends, IDE поможет override.
Рефакторинг: Extract Interface для перехода от наследования к композиции.
Полезные советы для новичков
Композиция по умолчанию: Если сомневаетесь, начните с has-a.
Проверяйте is-a: Dog is-an Animal? Да. Car is-an Engine? Нет.
Интерфейсы для гибкости: Комбинируйте композицию с интерфейсами.
Избегайте глубоких иерархий: Не больше 2-3 уровней.
#Java #для_новичков #beginner #OOP #Composition #Extends
👍4