Java for Beginner
743 subscribers
708 photos
196 videos
12 files
1.14K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
YAGNI: Тебе это не понадобится

YAGNI (You Ain't Gonna Need It — Тебе это не понадобится) — принцип, который предупреждает против добавления функциональности заранее, на основе предположений о будущем. Реализуйте только то, что нужно сейчас, чтобы избежать переусложнения.

Почему важно: Предвидение будущего часто ошибочно, и лишний код увеличивает сложность, баги и время на поддержку.
Как применять в Java: Добавляйте код по мере необходимости, используйте рефакторинг для расширений.


Пример нарушения YAGNI:

Класс с "будущими" методами:
// Нарушение: Лишние методы "на всякий случай"
public class User {
private String name;

public User(String name) {
this.name = name;
}

public void sendEmail() { /* Пока пусто */ }
public void sendSMS() { /* Пока пусто */ }
public void integrateWithAPI() { /* Пока пусто */ }
}
Исправление: Только необходимое:
javapublic class User {
private String name;

public User(String name) {
this.name = name;
}

// Только базовая функциональность
public String getName() {
return name;
}
}


Нюансы:
Связано с принципом "You Are Not Gonna Need It" — фокус на MVP (минимально жизнеспособном продукте).
В ООП: Не создавайте абстрактные классы "на будущее" — реализуйте, когда нужно.
В Java: Избегайте over-engineering в дизайне (например, Factory для простых объектов).
Ловушка: YAGNI не значит игнорировать планирование — используйте TDD (тест-драйвен разработку) для роста.



Полезные советы для новичков

DRY: Ищите дубли — рефакторьте в методы или утилиты.
KISS: Читайте код через день — если не понятно, упростите.
YAGNI: Задавайте: "Нужно ли это прямо сейчас?"
В Java: Используйте IDE для рефакторинга (Extract Method для DRY).
Ресурсы: Книга "Чистый код" Роберта Мартина — классика по этим принципам.



#Java #для_новичков #beginner #OOP #DRY #KISS #YAGNI
👍4🔥1
Что выведет код?

class Task220925 {
public static void main(String[] args) {
String input = " ";
String result = StringUtils.safeTrim(input);
System.out.println("'" + result + "'");
System.out.println("isEmpty: " + StringUtils.isEmpty(result));
}
}

public class StringUtils {
// KISS
public static boolean isEmpty(String s) {
return s == null || s.trim().isEmpty();
}

// YAGNI
public static String toTitleCase(String s) {
if (isEmpty(s)) return s;
return Character.toUpperCase(s.charAt(0)) + s.substring(1).toLowerCase();
}

// DRY
public static String safeTrim(String s) {
return isEmpty(s) ? "" : s.trim();
}
}


#Tasks
👍1
Вопрос с собеседований

Что такое паттерн 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
🗓 История IT-технологий сегодня — 23 сентября


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

Натаниэль С. Боренштейн (родился 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:
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<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
Что выведет код?

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
Создал канал в сетке!

Присоединяйтесь! 🙂

https://set.ki/channel/35sLVoe
Please open Telegram to view this post
VIEW IN TELEGRAM
👍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

Для множественных агрегаций.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🗓 История IT-технологий сегодня — 24 сентября


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

Серге́й Влади́мирович Абламе́йко (бел. Сярге́й Уладзі́міравіч Абламе́йка; род. 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):
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 — реакции в одном месте, код чище.

Пример подписки:
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
Что выведет код?

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
Варианты ответа:
Anonymous Quiz
10%
1 и 1
55%
1 и 2
21%
2 и 1
10%
2 и 2
3%
3 и 8
👍1
Продолжаем выбирать темы для разбора и голосовать за рассмотрение предложенных! 🤓

Голосуем за тему к рассмотрению в эти выходные!

Выбираем новую тему!
(можете предложить что-то из того, что предлагали на прошлой и позапрошлых неделях и что проиграло в голосовании!)

Не стесняемся! ✌️
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1