Методы Enum-класса и полезные функции
Enum наследует от Enum<E>, предоставляя методы:
name(): Возвращает имя константы как String.
ordinal(): Порядковый номер (начиная с 0).
valueOf(String name): Возвращает enum по имени.
values(): Массив всех констант.
Пример:
Нюанс: ordinal() не рекомендуется для логики — лучше поля, так как порядок может измениться.
Switch с enum
Enum идеален для switch — безопасно и читаемо.
Нюанс: Нет default, если все случаи покрыты — компилятор не требует.
Все нюансы enum
Наследование и реализация:
Enum не может extends класс (уже extends Enum), но может implements интерфейсы.
Нюанс: public enum MyEnum implements Interface { ... }
Конструкторы и поля:
Конструкторы private.
Константы должны быть первыми в enum, за ними — поля/методы.
Нюанс: Константы с параметрами: CONSTANT(params),
Иммутабельность: Enum константы final и immutable — идеально для singleton.
Сериализация: Enum сериализуется по имени, безопасно.
Ошибки:
Enum с public конструктором — ошибка.
valueOf("INVALID") — IllegalArgumentException.
Enum не может быть abstract, но может иметь abstract методы (константы реализуют).
Дизайн:
Используйте для фиксированных наборов (статусы, типы).
Добавляйте методы для логики.
Нюанс: Nested enum — static по умолчанию.
Как создать это в IntelliJ IDEA
Enum: New → Enum → Planet.
Константы: Напишите MERCURY(3.303e+23, 2.4397e6), — IDE подскажет конструктор.
Методы: Добавьте surfaceGravity() — IDE поможет с override для abstract.
Switch: Напишите switch (day) — IDE сгенерирует cases.
Полезные советы для новичков
Замените int/String константы: Enum safer.
Добавляйте toString(): Переопределите для custom вывода.
Используйте в коллекциях: Set для уникальных.
ordinal() осторожно: Лучше поля для значений.
Ресурсы: Oracle Tutorials on Enum Types.
#Java #для_новичков #beginner #OOP #Enum
Enum наследует от Enum<E>, предоставляя методы:
name(): Возвращает имя константы как String.
ordinal(): Порядковый номер (начиная с 0).
valueOf(String name): Возвращает enum по имени.
values(): Массив всех констант.
Пример:
Day[] days = Day.values();
for (Day d : days) {
System.out.println(d + " ordinal: " + d.ordinal());
}
Вывод: MONDAY ordinal: 0, etc.
Нюанс: ordinal() не рекомендуется для логики — лучше поля, так как порядок может измениться.
Switch с enum
Enum идеален для switch — безопасно и читаемо.
public void printDayType(Day day) {
switch (day) {
case MONDAY:
case TUESDAY:
case WEDNESDAY:
case THURSDAY:
case FRIDAY:
System.out.println("Рабочий день");
break;
case SATURDAY:
case SUNDAY:
System.out.println("Выходной");
break;
}
}
Нюанс: Нет default, если все случаи покрыты — компилятор не требует.
Все нюансы enum
Наследование и реализация:
Enum не может extends класс (уже extends Enum), но может implements интерфейсы.
Нюанс: public enum MyEnum implements Interface { ... }
Конструкторы и поля:
Конструкторы private.
Константы должны быть первыми в enum, за ними — поля/методы.
Нюанс: Константы с параметрами: CONSTANT(params),
Иммутабельность: Enum константы final и immutable — идеально для singleton.
Сериализация: Enum сериализуется по имени, безопасно.
Ошибки:
Enum с public конструктором — ошибка.
valueOf("INVALID") — IllegalArgumentException.
Enum не может быть abstract, но может иметь abstract методы (константы реализуют).
Дизайн:
Используйте для фиксированных наборов (статусы, типы).
Добавляйте методы для логики.
Нюанс: Nested enum — static по умолчанию.
Как создать это в IntelliJ IDEA
Enum: New → Enum → Planet.
Константы: Напишите MERCURY(3.303e+23, 2.4397e6), — IDE подскажет конструктор.
Методы: Добавьте surfaceGravity() — IDE поможет с override для abstract.
Switch: Напишите switch (day) — IDE сгенерирует cases.
Полезные советы для новичков
Замените int/String константы: Enum safer.
Добавляйте toString(): Переопределите для custom вывода.
Используйте в коллекциях: Set для уникальных.
ordinal() осторожно: Лучше поля для значений.
Ресурсы: Oracle Tutorials on Enum Types.
#Java #для_новичков #beginner #OOP #Enum
👍3
Во скольких телеграм - каналах по Java, вы состоите? А во скольких постоянно общаетесь?
Anonymous Poll
15%
Больше 10 точно. Нигде не общаюсь, только читаю.
4%
Больше 10 точно. Везде активно переписываюсь.
19%
От 5 до 10. Просто читаю, не люблю печатать.
0%
От 5 до 10. Во всех успел засветиться и являюсь живым пользователем чатов.
15%
Менее 5. Только читаю.
7%
Менее 5. Редко но пишу.
37%
Только этот! Самый лучший ❤️
4%
Вообще нигде и никогда и никому и ничего не пишу. 💪
👍1
Что выведет код?
#Tasks
enum Status {
ACTIVE, INACTIVE;
Status() {
System.out.print(this.name() + " ");
}
}
public class Task170925 {
public static void main(String[] args) {
System.out.print("Start ");
Status status = Status.ACTIVE;
System.out.print("End");
}
}
#Tasks
🔥2
Варианты ответа:
Anonymous Quiz
63%
Start ACTIVE End
19%
Start End
9%
Start ACTIVE INACTIVE End
9%
ACTIVE INACTIVE Start End
🔥3
Вопрос с собеседований
Что такое interface segregation principle (ISP)?🤓
Ответ:
ISP (из SOLID) — принцип, что клиенты не должны зависеть от ненужных методов интерфейса. Лучше несколько маленьких интерфейсов.
Пример: Вместо большого Worker разделить на Eater, Worker.
Улучшает гибкость.
#собеседование
Что такое interface segregation principle (ISP)?
Ответ:
ISP (из SOLID)
Пример: Вместо большого Worker разделить на Eater, Worker.
Улучшает гибкость.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Жан Берна́р Лео́н Фуко́ (фр. Jean Bernard Léon Foucault; 18 сентября 1819, Париж — 11 февраля 1868, там же) — французский физик, механик и астроном, член Парижской Академии наук (1865). Состоял членом Берлинской академии наук, был членом-корреспондентом Петербургской Академии наук (1860), иностранным членом Лондонского королевского общества (1864).
Владимир Александрович Сухомлин (род. 18 сентября 1945, Москва) — доктор технических наук, профессор, заведующий лабораторией открытых информационных технологий факультета ВМК МГУ.
Ю́рий Васи́льевич Гуля́ев (род. 18 сентября 1935) — советский и российский физик, научный руководитель Института радиотехники и электроники РАН (ИРЭ РАН), директор Института нанотехнологий микроэлектроники РАН (ИНМЭ РАН), академик и член Президиума РАН, профессор и заведующий кафедрой твердотельной электроники и радиофизики ФФКЭ МФТИ. Лауреат двух Государственных премий СССР. Почётный доктор Новгородского государственного университета им. Ярослава Мудрого (2013).
Томас Г. Лейн (род. 18 сентября 1955) — специалист по информатике, занимающийся разработкой программного обеспечения с открытым исходным кодом . В опросе 2000 года он был включён в десятку ведущих разработчиков программного обеспечения с открытым исходным кодом, внёс 0,782% от общего объёма кода.
Джеймс Уильям Кули (18 сентября 1926 г. — 29 июня 2016 г.) — американский математик. Кули получил степень бакалавра в 1949 году в Манхэттенском колледже в Бронксе, штат Нью-Йорк, степень магистра в 1951 году в Колумбийском университете в Нью-Йорке, штат Нью-Йорк, и степень доктора философии в 1961 году по прикладной математике в Колумбийском университете. С 1953 по 1956 год он работал программистом на компьютере Джона фон Неймана в Институте перспективных исследований в Принстоне, штат Нью-Джерси, где, в частности, запрограммировал преобразование Блэкмана — Тьюки.
1961 — в лаборатории люминесценции Физического института АН СССР начал работать первый советский лазер на искусственном кристалле рубина.
1989 — Релиз NeXTSTEP 1.0 (NeXT, ОС, разработанная командой Стива Джобса).
2024 — число статьей в Русской Википедии достигло 2 миллиона.
#Biography #Birth_Date #Events #18Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Реактивное программирование
Что такое потоки данных в реактивном мире?
В реактивном программировании данные — это не статичный объект, который вы запрашиваете и ждёте. Это динамичный поток: последовательность элементов (событий), которые могут приходить в любое время, в любом количестве. Поток может быть бесконечным (как лента новостей) или конечным (как результаты поиска). Главное — обработка идёт реактивно: программа "подписывается" на поток и реагирует на каждый элемент по мере его появления, без блокировок.
Это решает боли из предыдущего поста: вместо выделения потока на ожидание, мы используем неблокирующий механизм. Если данных нет — ничего не происходит, ресурсы свободны. Когда данные приходят — срабатывают реакции. Это как подписка на уведомления: телефон не висит в ожидании, а просто пиликает при новом сообщении.
В основе лежит спецификация Reactive Streams — стандарт, который определяет, как строить такие потоки.
Он включает четыре ключевых интерфейса:
Издатель (Publisher): источник данных. Он "публикует" элементы потока. Например, это может быть база данных, генерирующая записи по запросу.
Подписчик (Subscriber): получатель данных. Он "подписывается" на издателя и реагирует на элементы: onNext (получил элемент), onError (ошибка), onComplete (поток завершён).
Подписка (Subscription): связь между издателем и подписчиком. Через неё подписчик может запросить больше данных (request(n)) или отменить подписку (cancel). Это вводит "обратное давление" — механизм, чтобы подписчик не захлёбывался данными, если не успевает их обрабатывать.
Процессор (Processor): комбинация издателя и подписчика, для промежуточной обработки (как фильтр в конвейере).
Эти интерфейсы — основа. Они обеспечивают асинхронность без блокировок: всё работает на основе событий, а не ожиданий.
События как река: метафора и практика
Представьте реку событий: вода (данные) течёт непрерывно, иногда бурно (пиковая нагрузка), иногда спокойно. Ваша программа — не плотина, которая блокирует поток, а турбина, которая генерирует энергию по мере течения. Если река слишком быстрая — турбина сигнализирует "замедлить" (обратное давление), чтобы не перегрузиться.
В Project Reactor это реализовано через два типа потоков:
Mono: поток для нуля или одного элемента. Идеален для одиночных операций, как HTTP-запрос, возвращающий один ответ.
Пример:
Flux: поток для нуля, одного или многих элементов, возможно бесконечных. Для последовательностей, как стриминг данных.
Пример:
Flux "выдаёт" элементы по одному: 1, 2, 3... Это как река: элементы приходят последовательно, но асинхронно.
Почему это лучше традиционных подходов?
В CompletableFuture вы строите цепочки, но рискуете блокировками внутри.
В реактивном стиле всё неблокирующее: используйте операторы вроде map (преобразовать элемент), filter (отфильтровать), flatMap (развернуть в подпотоки).
Пример цепочки:
#Java #middle #Reactor #data_stream
Что такое потоки данных в реактивном мире?
В реактивном программировании данные — это не статичный объект, который вы запрашиваете и ждёте. Это динамичный поток: последовательность элементов (событий), которые могут приходить в любое время, в любом количестве. Поток может быть бесконечным (как лента новостей) или конечным (как результаты поиска). Главное — обработка идёт реактивно: программа "подписывается" на поток и реагирует на каждый элемент по мере его появления, без блокировок.
Это решает боли из предыдущего поста: вместо выделения потока на ожидание, мы используем неблокирующий механизм. Если данных нет — ничего не происходит, ресурсы свободны. Когда данные приходят — срабатывают реакции. Это как подписка на уведомления: телефон не висит в ожидании, а просто пиликает при новом сообщении.
В основе лежит спецификация Reactive Streams — стандарт, который определяет, как строить такие потоки.
Он включает четыре ключевых интерфейса:
Издатель (Publisher): источник данных. Он "публикует" элементы потока. Например, это может быть база данных, генерирующая записи по запросу.
Подписчик (Subscriber): получатель данных. Он "подписывается" на издателя и реагирует на элементы: onNext (получил элемент), onError (ошибка), onComplete (поток завершён).
Подписка (Subscription): связь между издателем и подписчиком. Через неё подписчик может запросить больше данных (request(n)) или отменить подписку (cancel). Это вводит "обратное давление" — механизм, чтобы подписчик не захлёбывался данными, если не успевает их обрабатывать.
Процессор (Processor): комбинация издателя и подписчика, для промежуточной обработки (как фильтр в конвейере).
Эти интерфейсы — основа. Они обеспечивают асинхронность без блокировок: всё работает на основе событий, а не ожиданий.
События как река: метафора и практика
Представьте реку событий: вода (данные) течёт непрерывно, иногда бурно (пиковая нагрузка), иногда спокойно. Ваша программа — не плотина, которая блокирует поток, а турбина, которая генерирует энергию по мере течения. Если река слишком быстрая — турбина сигнализирует "замедлить" (обратное давление), чтобы не перегрузиться.
В Project Reactor это реализовано через два типа потоков:
Mono: поток для нуля или одного элемента. Идеален для одиночных операций, как HTTP-запрос, возвращающий один ответ.
Пример:
Mono<string> mono = Mono.just("Привет из реки"); // Создаём простой Mono с одним элементом
mono.subscribe(
value -> System.out.println("Получено: " + value), // onNext: реакция на элемент
error -> System.err.println("Ошибка: " + error), // onError
() -> System.out.println("Завершено") // onComplete
);
Здесь subscribe — это подписка. Mono "течёт" асинхронно: если элемент готов — срабатывает onNext, потом onComplete. Нет блокировок: код continue после subscribe.
Flux: поток для нуля, одного или многих элементов, возможно бесконечных. Для последовательностей, как стриминг данных.
Пример:
Flux<integer> flux = Flux.range(1, 5); // Поток чисел от 1 до 5
flux.subscribe(
value -> System.out.println("Элемент: " + value),
error -> System.err.println("Ошибка: " + error),
() -> System.out.println("Поток завершён")
);
Flux "выдаёт" элементы по одному: 1, 2, 3... Это как река: элементы приходят последовательно, но асинхронно.
Почему это лучше традиционных подходов?
В CompletableFuture вы строите цепочки, но рискуете блокировками внутри.
В реактивном стиле всё неблокирующее: используйте операторы вроде map (преобразовать элемент), filter (отфильтровать), flatMap (развернуть в подпотоки).
Пример цепочки:
Flux.fromIterable(List.of("яблоко", "банан", "вишня"))
.filter(fruit -> fruit.startsWith("б")) // Фильтруем
.map(String::toUpperCase) // Преобразуем
.subscribe(System.out::println); // Подписываемся
Результат: "БАНАН". Всё течёт как конвейер, без callback-ада: код читаем, как последовательный, но работает асинхронно.
#Java #middle #Reactor #data_stream
👍3
Обратное давление: контроль
Одна из ключевых фишек — backpressure (обратное давление). В традиционных системах, если производитель данных быстрее потребителя, буфер переполняется, и система падает. В Reactive Streams подписчик через Subscription.request(n) говорит: "Дай мне n элементов". Издатель выдаёт ровно столько, сколько запрошено. Это как шлюзы на реке: предотвращают наводнение.
Пример в Flux:
Подписчик контролирует темп, избегая перегрузки.
Почему это новый подход, который нам нужен?
Реактивное программирование не просто добавляет инструменты — оно меняет мышление. Вместо "императивного" кода (делай то, жди это), мы пишем "декларативно": опиши, как реагировать на поток. Это масштабируется: на сервере с 4 ядрами можно обрабатывать тысячи подключений, потому что нет блокирующих потоков. Библиотеки вроде Reactor интегрируются с неблокирующими драйверами (например, reactive JDBC или WebFlux для веб), решая боли блокировок.
#Java #middle #Reactor #data_stream
Одна из ключевых фишек — backpressure (обратное давление). В традиционных системах, если производитель данных быстрее потребителя, буфер переполняется, и система падает. В Reactive Streams подписчик через Subscription.request(n) говорит: "Дай мне n элементов". Издатель выдаёт ровно столько, сколько запрошено. Это как шлюзы на реке: предотвращают наводнение.
Пример в Flux:
Flux<integer> fastFlux = Flux.range(1, 1000); // Быстрый источник
fastFlux.subscribe(new BaseSubscriber<integer>() {
@Override
protected void hookOnSubscribe(Subscription subscription) {
request(10); // Запрашиваем только 10 элементов сначала
}
@Override
protected void hookOnNext(Integer value) {
System.out.println(value);
if (value % 10 == 0) request(10); // Запрашиваем ещё по мере обработки
}
});
Подписчик контролирует темп, избегая перегрузки.
Почему это новый подход, который нам нужен?
Реактивное программирование не просто добавляет инструменты — оно меняет мышление. Вместо "императивного" кода (делай то, жди это), мы пишем "декларативно": опиши, как реагировать на поток. Это масштабируется: на сервере с 4 ядрами можно обрабатывать тысячи подключений, потому что нет блокирующих потоков. Библиотеки вроде Reactor интегрируются с неблокирующими драйверами (например, reactive JDBC или WebFlux для веб), решая боли блокировок.
#Java #middle #Reactor #data_stream
👍4
Что выведет код?
#Tasks
import java.util.HashSet;
import java.util.Set;
public class Task180925 {
public static void main(String[] args) {
Point p1 = new Point(1, 2);
Point p2 = new Point(1, 3);
Set<Point> set = new HashSet<>();
set.add(p1);
set.add(p2);
System.out.println(set.size());
}
public record Point(int x, int y) {
public Point {
if (x < 0) throw new IllegalArgumentException("x < 0");
if (y < 0) throw new IllegalArgumentException("y < 0");
}
public boolean equals(Object o) {
return o instanceof Point p && p.x == x;
}
public int hashCode() {
return x;
}
}
}
#Tasks
👍2
👍2
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Вопрос с собеседований
Что такое dependency inversion principle (DIP)?🤓
Ответ:
DIP (SOLID)— высокоуровневые модули не зависят от низкоуровневых, а от абстракций.
Пример:
Использовать интерфейс Database вместо конкретного MySQLDatabase.
С Inversion of Control (IoC) упрощает тестирование.
#собеседование
Что такое dependency inversion principle (DIP)?
Ответ:
DIP (SOLID)
Пример:
Использовать интерфейс Database вместо конкретного MySQLDatabase.
С Inversion of Control (IoC) упрощает тестирование.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Вале́рий Пантеле́евич Бака́лов (19 сентября 1940, Новосибирск — 21 июня 2021, там же) — советский/российский деятель в области связи и образования, доктор технических наук; был ректором Сибирского государственного университета телекоммуникаций и информатики (НЭИС), руководил кафедрами, развивал специальности по связи, информационно-измерительной технике и телеметрии.
Конвей Морис Бернерс-Ли (19 сентября 1921 — 1 февраля 2019) — математик и компьютерный учёный; участвовал в разработке Ferranti Mark 1 — одной из первых коммерческих ЭВМ с хранимой в памяти программой.
Яков За́лманович Цы́пкин (19 сентября 1919[1], Екатеринослав — 2 декабря 1997) — советский кибернетик и инженер-электрик, член АН СССР; внёс значительный вклад в теорию автоматического управления, разработку релейных и импульсных автоматов, критериев устойчивости систем.
Питер Смит (19 сентября 1956 — 27 мая 2025) — британский учёный в области искусственного интеллекта / компьютерных наук; профессор, наставник многих докторов, внёс вклад в развитие PhD-образования и исследовательской поддержки в ИИ.
Администратор канала Java for Beginner - просто Ден.
1982 — Скотт Фалман предложил использовать смайлики в качестве способа выражения эмоций при общении в Сети.
1990 — Ассоциация пользователей UNIX зарегистрировала домен верхнего уровня SU для применения на территории СССР.
#Biography #Birth_Date #Events #19Сентября
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Основы ООП в Java
Глава 7. Принципы проектирования и хорошего кода
SOLID
SOLID — это аббревиатура из первых букв пяти принципов проектирования объектно-ориентированных систем. Эти принципы помогают избежать распространенных ошибок в коде, таких как жесткая связь между частями программы, сложность в добавлении новых функций или трудности в тестировании. Применяя SOLID, вы делаете код более гибким, понятным и устойчивым к изменениям. Это особенно полезно в больших проектах, где работает команда разработчиков.
1. Принцип единственной ответственности (S — Single Responsibility Principle)
Этот принцип гласит, что каждый класс или модуль в программе должен отвечать только за одну задачу или иметь только одну причину для изменения. Иными словами, класс не должен заниматься несколькими несвязанными вещами сразу. Если класс делает слишком много, он становится сложным, и изменения в одной части могут сломать другую.
Почему важно: Если класс отвечает за несколько задач, то при изменении одной из них (например, из-за новых требований бизнеса) вы рискуете сломать другие части. Это приводит к ошибкам и усложняет поддержку кода.
Подробное объяснение: Представьте, что класс одновременно читает данные из файла, обрабатывает их и выводит на экран. Если изменится формат файла, вам придется менять весь класс, даже если обработка и вывод не изменились. Лучше разделить: один класс для чтения, другой для обработки, третий для вывода.
Пример нарушения принципа:
Пример правильного применения:
Совет: Задайте вопрос: "Сколько причин для изменения у этого класса?" Если больше одной — разделите.
2. Принцип открытости-закрытости (O — Open-Closed Principle)
Этот принцип утверждает, что классы и модули должны быть открыты для расширения (то есть, вы можете добавлять новое поведение), но закрыты для изменения (то есть, существующий код не должен меняться при добавлении новых функций). Другими словами, чтобы добавить новую возможность, вы расширяете систему, не трогая старый код.
Почему важно: Если каждый раз при новых требованиях вы меняете существующий код, это может ввести ошибки в уже работающие части программы. Принцип позволяет добавлять функции безопасно.
Подробное объяснение: Расширение происходит через наследование, интерфейсы или композицию. Например, если у вас есть класс для фигур, добавление новой фигуры не должно менять код для существующих.
#Java #для_новичков #beginner #OOP #SOLID
Глава 7. Принципы проектирования и хорошего кода
SOLID
SOLID — это аббревиатура из первых букв пяти принципов проектирования объектно-ориентированных систем. Эти принципы помогают избежать распространенных ошибок в коде, таких как жесткая связь между частями программы, сложность в добавлении новых функций или трудности в тестировании. Применяя SOLID, вы делаете код более гибким, понятным и устойчивым к изменениям. Это особенно полезно в больших проектах, где работает команда разработчиков.
1. Принцип единственной ответственности (S — Single Responsibility Principle)
Этот принцип гласит, что каждый класс или модуль в программе должен отвечать только за одну задачу или иметь только одну причину для изменения. Иными словами, класс не должен заниматься несколькими несвязанными вещами сразу. Если класс делает слишком много, он становится сложным, и изменения в одной части могут сломать другую.
Почему важно: Если класс отвечает за несколько задач, то при изменении одной из них (например, из-за новых требований бизнеса) вы рискуете сломать другие части. Это приводит к ошибкам и усложняет поддержку кода.
Подробное объяснение: Представьте, что класс одновременно читает данные из файла, обрабатывает их и выводит на экран. Если изменится формат файла, вам придется менять весь класс, даже если обработка и вывод не изменились. Лучше разделить: один класс для чтения, другой для обработки, третий для вывода.
Пример нарушения принципа:
public class Report {
// Нарушение: Класс делает всё сразу
public void readDataFromFile(String fileName) {
// Код для чтения данных
}
public void processData() {
// Код для обработки данных
}
public void printReport() {
// Код для печати отчета
}
}
Здесь класс имеет три ответственности. Если изменится способ чтения файлов, придется трогать весь класс.
Пример правильного применения:
public class DataReader {
public String readDataFromFile(String fileName) {
// Только чтение данных
return "Данные из файла";
}
}
public class DataProcessor {
public String processData(String data) {
// Только обработка
return "Обработанные данные: " + data;
}
}
public class ReportPrinter {
public void printReport(String processedData) {
// Только печать
System.out.println(processedData);
}
}
Теперь каждый класс имеет одну ответственность. Изменение в чтении не затронет печать.
Совет: Задайте вопрос: "Сколько причин для изменения у этого класса?" Если больше одной — разделите.
2. Принцип открытости-закрытости (O — Open-Closed Principle)
Этот принцип утверждает, что классы и модули должны быть открыты для расширения (то есть, вы можете добавлять новое поведение), но закрыты для изменения (то есть, существующий код не должен меняться при добавлении новых функций). Другими словами, чтобы добавить новую возможность, вы расширяете систему, не трогая старый код.
Почему важно: Если каждый раз при новых требованиях вы меняете существующий код, это может ввести ошибки в уже работающие части программы. Принцип позволяет добавлять функции безопасно.
Подробное объяснение: Расширение происходит через наследование, интерфейсы или композицию. Например, если у вас есть класс для фигур, добавление новой фигуры не должно менять код для существующих.
#Java #для_новичков #beginner #OOP #SOLID
👍4🔥1
Пример нарушения принципа:
Пример правильного применения:Используем абстракцию и полиморфизм.
Совет: Используйте абстрактные классы или интерфейсы для "открытости", а переопределение — для расширения.
3. Принцип подстановки Лисков (L — Liskov Substitution Principle)
Этот принцип, предложенный Барбарой Лисков, гласит, что объекты подкласса должны быть способны заменять объекты суперкласса без изменения правильности программы. Иными словами, подкласс не должен нарушать ожидания, установленные суперклассом.
Почему важно: Если подкласс меняет поведение суперкласса неожиданным образом, код, использующий суперкласс, может сломаться при подстановке подкласса. Это нарушает полиморфизм.
Подробное объяснение: Подкласс должен сохранять контракты суперкласса: предусловия (входные данные) не ужесточаются, постусловия (выход) не ослабляются, инварианты (постоянные свойства) сохраняются.
Пример нарушения принципа:
Представьте суперкласс Bird (Птица) с методом fly() (летать). Подкласс Penguin (Пингвин) переопределяет fly() и бросает исключение, потому что пингвины не летают. Тогда код Bird bird = new Penguin(); bird.fly(); сломается, хотя ожидалось, что любая птица может летать.
Пример правильного применения:
Лучше разделить: суперкласс Animal, интерфейс Flyable для летающих. Пингвин extends Animal, но не implements Flyable.
Совет: Проверяйте: "Можно ли заменить суперкласс подклассом без проблем?" Если нет — пересмотрите дизайн.
#Java #для_новичков #beginner #OOP #SOLID
public class ShapeCalculator {
public double calculateArea(Object shape) {
if (shape instanceof Circle) {
// Код для круга
return Math.PI * ((Circle) shape).getRadius() * ((Circle) shape).getRadius();
} else if (shape instanceof Square) {
// Код для квадрата
return ((Square) shape).getSide() * ((Square) shape).getSide();
}
// Если добавить треугольник, придется менять метод
return 0;
}
}
Добавление новой фигуры требует изменения метода, что нарушает принцип.
Пример правильного применения:Используем абстракцию и полиморфизм.
public abstract class Shape {
public abstract double calculateArea(); // Метод для расширения
}
public class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
}
public class Square extends Shape {
private double side;
public Square(double side) {
this.side = side;
}
@Override
public double calculateArea() {
return side * side;
}
}
// Для новой фигуры просто добавьте класс, без изменения старого кода
Теперь ShapeCalculator может быть:
public class ShapeCalculator {
public double calculateArea(Shape shape) {
return shape.calculateArea(); // Полиморфизм, закрыт для изменений
}
}
Добавление треугольника — новый класс extends Shape, без изменений в калькуляторе.
Совет: Используйте абстрактные классы или интерфейсы для "открытости", а переопределение — для расширения.
3. Принцип подстановки Лисков (L — Liskov Substitution Principle)
Этот принцип, предложенный Барбарой Лисков, гласит, что объекты подкласса должны быть способны заменять объекты суперкласса без изменения правильности программы. Иными словами, подкласс не должен нарушать ожидания, установленные суперклассом.
Почему важно: Если подкласс меняет поведение суперкласса неожиданным образом, код, использующий суперкласс, может сломаться при подстановке подкласса. Это нарушает полиморфизм.
Подробное объяснение: Подкласс должен сохранять контракты суперкласса: предусловия (входные данные) не ужесточаются, постусловия (выход) не ослабляются, инварианты (постоянные свойства) сохраняются.
Пример нарушения принципа:
Представьте суперкласс Bird (Птица) с методом fly() (летать). Подкласс Penguin (Пингвин) переопределяет fly() и бросает исключение, потому что пингвины не летают. Тогда код Bird bird = new Penguin(); bird.fly(); сломается, хотя ожидалось, что любая птица может летать.
public class Bird {
public void fly() {
System.out.println("Летаю!");
}
}
public class Penguin extends Bird {
@Override
public void fly() {
throw new UnsupportedOperationException("Пингвины не летают!");
}
}
Это нарушение: подстановка пингвина ломает код.
Пример правильного применения:
Лучше разделить: суперкласс Animal, интерфейс Flyable для летающих. Пингвин extends Animal, но не implements Flyable.
public class Animal {
// Общие методы
}
public interface Flyable {
void fly();
}
public class Eagle extends Animal implements Flyable {
@Override
public void fly() {
System.out.println("Орел летает высоко!");
}
}
public class Penguin extends Animal {
// Нет fly(), так что не нарушает
}
Теперь код работает только с Flyable, без неожиданностей.
Совет: Проверяйте: "Можно ли заменить суперкласс подклассом без проблем?" Если нет — пересмотрите дизайн.
#Java #для_новичков #beginner #OOP #SOLID
👍4🔥1
4. Принцип разделения интерфейсов (I — Interface Segregation Principle)
Этот принцип говорит, что интерфейсы должны быть маленькими и специализированными, а не большими и универсальными. Клиенты (классы, использующие интерфейс) не должны зависеть от методов, которые они не используют.
Почему важно: Большой интерфейс заставляет классы реализовывать ненужные методы, что приводит к "пустым" реализациям и усложняет код.
Подробное объяснение: Лучше несколько маленьких интерфейсов, чем один большой. Это делает систему модульной и легче для понимания.
Пример нарушения принципа:
Пример правильного применения:
Разделите на маленькие интерфейсы.
Совет: Интерфейс должен быть "толстым" для клиента, но "тонким" для реализатора — маленькие интерфейсы.
5. Принцип инверсии зависимостей (D — Dependency Inversion Principle)
Этот принцип утверждает, что высокоуровневые модули (бизнес-логика) не должны зависеть от низкоуровневых (детали реализации), а оба должны зависеть от абстракций (интерфейсов). Абстракции не зависят от деталей, детали зависят от абстракций.
Почему важно: Это уменьшает связь между частями системы, делая код легче для изменения и тестирования (например, замена базы данных без изменения бизнес-логики).
Подробное объяснение: Используйте интерфейсы или абстрактные классы как "прослойку". Высокий уровень зависит от интерфейса, низкий — реализует его.
Пример нарушения принципа:
Пример правильного применения:
Совет: Используйте dependency injection (внедрение зависимостей) для передачи абстракций.
Полезные советы для новичков
Применяйте SOLID постепенно: Начните с единственной ответственности, потом добавляйте другие.
Примеры в Java: Смотрите стандартную библиотеку — она следует SOLID.
Ресурсы: Книга "Clean Code" Роберта Мартина для глубокого понимания.
Практика: Возьмите свой код и проверьте на соответствие каждому принципу.
#Java #для_новичков #beginner #OOP #SOLID
Этот принцип говорит, что интерфейсы должны быть маленькими и специализированными, а не большими и универсальными. Клиенты (классы, использующие интерфейс) не должны зависеть от методов, которые они не используют.
Почему важно: Большой интерфейс заставляет классы реализовывать ненужные методы, что приводит к "пустым" реализациям и усложняет код.
Подробное объяснение: Лучше несколько маленьких интерфейсов, чем один большой. Это делает систему модульной и легче для понимания.
Пример нарушения принципа:
public interface Worker {
void work(); // Для всех
void eat(); // Только для людей
void charge(); // Только для роботов
}
Класс Human реализует charge() бесполезно, Robot — eat().
Пример правильного применения:
Разделите на маленькие интерфейсы.
public interface Workable {
void work();
}
public interface Eatable {
void eat();
}
public interface Chargeable {
void charge();
}
public class Human implements Workable, Eatable {
@Override
public void work() { /*...*/ }
@Override
public void eat() { /*...*/ }
}
public class Robot implements Workable, Chargeable {
@Override
public void work() { /*...*/ }
@Override
public void charge() { /*...*/ }
}
Теперь классы реализуют только нужное.
Совет: Интерфейс должен быть "толстым" для клиента, но "тонким" для реализатора — маленькие интерфейсы.
5. Принцип инверсии зависимостей (D — Dependency Inversion Principle)
Этот принцип утверждает, что высокоуровневые модули (бизнес-логика) не должны зависеть от низкоуровневых (детали реализации), а оба должны зависеть от абстракций (интерфейсов). Абстракции не зависят от деталей, детали зависят от абстракций.
Почему важно: Это уменьшает связь между частями системы, делая код легче для изменения и тестирования (например, замена базы данных без изменения бизнес-логики).
Подробное объяснение: Используйте интерфейсы или абстрактные классы как "прослойку". Высокий уровень зависит от интерфейса, низкий — реализует его.
Пример нарушения принципа:
public class ReportService {
private MySQLDatabase db = new MySQLDatabase(); // Зависит от конкретной реализации
public void generateReport() {
db.connect();
// ...
}
}
Смена базы данных требует изменения сервиса.
Пример правильного применения:
public interface Database {
void connect();
// ...
}
public class MySQLDatabase implements Database {
@Override
public void connect() { /*...*/ }
}
public class ReportService {
private Database db; // Зависит от абстракции
public ReportService(Database db) { // Инъекция зависимости
this.db = db;
}
public void generateReport() {
db.connect();
// ...
}
}
Теперь можно передать любую реализацию: new ReportService(new MySQLDatabase()) или new ReportService(new PostgreSQLDatabase()).
Совет: Используйте dependency injection (внедрение зависимостей) для передачи абстракций.
Полезные советы для новичков
Применяйте SOLID постепенно: Начните с единственной ответственности, потом добавляйте другие.
Примеры в Java: Смотрите стандартную библиотеку — она следует SOLID.
Ресурсы: Книга "Clean Code" Роберта Мартина для глубокого понимания.
Практика: Возьмите свой код и проверьте на соответствие каждому принципу.
#Java #для_новичков #beginner #OOP #SOLID
👍3🔥2 1
Что выведет код?
#Tasks
class Animal190925 {
public String speak() {
return "Some sound";
}
}
class Dog190925 extends Animal190925 {
public String speak() {
return "Woof";
}
public String fetch() {
return "Fetching stick";
}
}
public class Task190925 {
public static void main(String[] args) {
Animal190925 myAnimal = new Dog190925();
System.out.println(myAnimal.speak());
System.out.println(myAnimal.fetch());
}
}
#Tasks
👍4
Варианты ответа:
Anonymous Quiz
14%
"Some sound" и "Fetching stick"
45%
"Woof" и "Fetching stick"
34%
Ошибка компиляции
7%
Ошибка выполнения
😱1
Вопрос с собеседований
Что такое паттерн Chain of Responsibility?🤓
Ответ:
Chain of Responsibility — паттерн, где запрос передается по цепочке обработчиков.
Пример:
abstract class Handler {
protected Handler next;
abstract void handle(Request request);
}
class ConcreteHandler extends Handler {
void handle(Request request) { if (canHandle) process(); else next.handle(request); }
}
Используется в logging или обработке событий.
#собеседование
Что такое паттерн Chain of Responsibility?
Ответ:
Chain of Responsibility
Пример:
abstract class Handler {
protected Handler next;
abstract void handle(Request request);
}
class ConcreteHandler extends Handler {
void handle(Request request) { if (canHandle) process(); else next.handle(request); }
}
Используется в logging или обработке событий.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1