Как обобрать дерево в несколько потоков?
Всем привет, меня зовут Антон, я Java‑разработчик в Сбере, подразделение SberWorks. Я разрабатываю Giga IDE — новую IDE на основе IntelliJ IDEA. В ходе работы столкнулся с тем, что при открытии проектов происходит сканирование всех папок для поиска тех или иных файлов. Если обобщить, то задача сводится к обходу дерева. Я решил подробнее рассмотреть эту тему, причём с прицелом на многопоточность.
Задача обхода деревьев далеко не нова, существуют два основных подхода: обход в ширину и глубину. В первом случае удобно применять рекурсивный алгоритм, а во втором — понадобится дополнительная коллекция, в которую будут складываться узлы дерева, но всё это в один поток, а я решил рассмотреть эту задачу в многопоточной интерпретации.
https://habr.com/ru/companies/sberbank/articles/921528/
👉@BookJava
Всем привет, меня зовут Антон, я Java‑разработчик в Сбере, подразделение SberWorks. Я разрабатываю Giga IDE — новую IDE на основе IntelliJ IDEA. В ходе работы столкнулся с тем, что при открытии проектов происходит сканирование всех папок для поиска тех или иных файлов. Если обобщить, то задача сводится к обходу дерева. Я решил подробнее рассмотреть эту тему, причём с прицелом на многопоточность.
Задача обхода деревьев далеко не нова, существуют два основных подхода: обход в ширину и глубину. В первом случае удобно применять рекурсивный алгоритм, а во втором — понадобится дополнительная коллекция, в которую будут складываться узлы дерева, но всё это в один поток, а я решил рассмотреть эту задачу в многопоточной интерпретации.
https://habr.com/ru/companies/sberbank/articles/921528/
👉@BookJava
👍6🤔1
🔔 Прокачайте системный подход + скидка 🎁 10% на курс до 30 июня
Системный дизайн — для тех, кто отвечает за стратегическое мышление и принятие архитектурных решений
Хотите глубже понимать, как проектируются масштабируемые и устойчивые системы?
Курс «System Design» от OTUS — это:
— Не просто паттерны, а практика проектирования сложных систем,
— Подготовка к архитектурным интервью,
— Реальные кейсы из крупных компаний,
— Финальный проект, который можно показать в портфолио.
Курс подойдёт разработчикам, архитекторам, техническим лидам и DevOps-инженерам, которые хотят повысить квалификацию и системно мыслить при проектировании.
🚀 Успейте воспользоваться 🏷10% скидкой на курс. Выгодные условия действуют до 30 июня включительно!
🔗 Получить скидку и оставить заявку: https://vk.cc/cNfrd0
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Системный дизайн — для тех, кто отвечает за стратегическое мышление и принятие архитектурных решений
Хотите глубже понимать, как проектируются масштабируемые и устойчивые системы?
Курс «System Design» от OTUS — это:
— Не просто паттерны, а практика проектирования сложных систем,
— Подготовка к архитектурным интервью,
— Реальные кейсы из крупных компаний,
— Финальный проект, который можно показать в портфолио.
Курс подойдёт разработчикам, архитекторам, техническим лидам и DevOps-инженерам, которые хотят повысить квалификацию и системно мыслить при проектировании.
🔗 Получить скидку и оставить заявку: https://vk.cc/cNfrd0
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
Вопрос с собеседования: Опишите жизненный цикл Spring Bean
Beans – центральный объект заботы Spring Framework. За кулисами фреймворка с ними происходит множество процессов. Во многие из них можно вмешаться, добавив собственную логику в разные этапы жизненного цикла. Через следующие этапы проходит каждый отдельно взятый бин:
1. Инстанцирование объекта. Техническое начало жизни бина, работа конструктора его класса;
2. Установка свойств из конфигурации бина, внедрение зависимостей;
3. Нотификация aware-интерфейсов. BeanNameAware, BeanFactoryAware и другие. Мы уже писали о таких интерфейсах ранее. Технически, выполняется системными подтипами BeanPostProcessor, и совпадает с шагом 4;
4. Пре-инициализация – метод postProcessBeforeInitialization() интерфейса BeanPostProcessor;
5. Инициализация. Разные способы применяются в таком порядке:
• Метод бина с аннотацией
• Метод afterPropertiesSet() бина под интерфейсом InitializingBean;
• Init-метод. Для отдельного бина его имя устанавливается в параметре определения initMethod. В xml-конфигурации можно установить для всех бинов сразу, с помощью default-init-method;
6. Пост-инициализация – метод postProcessAfterInitialization() интерфейса BeanPostProcessor.
Когда IoC-контейнер завершает свою работу, мы можем кастомизировать этап штатного уничтожения бина. Как со всеми способами финализации в Java, при жестком выключении (kill -9) гарантии вызова этого этапа нет. Три альтернативных способа «деинициализации» вызываются в том же порядке, что симметричные им методы инициализации:
1. Метод с аннотацией
2. Метод с именем, которое указано в свойстве destroyMethod определния бина (или в глобальном default-destroy-method);
3. Метод destroy() интерфейса DisposableBean.
Не следует путать жизненный цикл отдельного бина с жизненным циклом контекста и этапами подготовки фабрик бинов. О них мы поговорим в будущих публикациях.
👉@BookJava
Beans – центральный объект заботы Spring Framework. За кулисами фреймворка с ними происходит множество процессов. Во многие из них можно вмешаться, добавив собственную логику в разные этапы жизненного цикла. Через следующие этапы проходит каждый отдельно взятый бин:
1. Инстанцирование объекта. Техническое начало жизни бина, работа конструктора его класса;
2. Установка свойств из конфигурации бина, внедрение зависимостей;
3. Нотификация aware-интерфейсов. BeanNameAware, BeanFactoryAware и другие. Мы уже писали о таких интерфейсах ранее. Технически, выполняется системными подтипами BeanPostProcessor, и совпадает с шагом 4;
4. Пре-инициализация – метод postProcessBeforeInitialization() интерфейса BeanPostProcessor;
5. Инициализация. Разные способы применяются в таком порядке:
• Метод бина с аннотацией
@PostConstruct
из стандарта JSR-250 (рекомендуемый способ);• Метод afterPropertiesSet() бина под интерфейсом InitializingBean;
• Init-метод. Для отдельного бина его имя устанавливается в параметре определения initMethod. В xml-конфигурации можно установить для всех бинов сразу, с помощью default-init-method;
6. Пост-инициализация – метод postProcessAfterInitialization() интерфейса BeanPostProcessor.
Когда IoC-контейнер завершает свою работу, мы можем кастомизировать этап штатного уничтожения бина. Как со всеми способами финализации в Java, при жестком выключении (kill -9) гарантии вызова этого этапа нет. Три альтернативных способа «деинициализации» вызываются в том же порядке, что симметричные им методы инициализации:
1. Метод с аннотацией
@PreDestroy
;2. Метод с именем, которое указано в свойстве destroyMethod определния бина (или в глобальном default-destroy-method);
3. Метод destroy() интерфейса DisposableBean.
Не следует путать жизненный цикл отдельного бина с жизненным циклом контекста и этапами подготовки фабрик бинов. О них мы поговорим в будущих публикациях.
👉@BookJava
👍8🔥3❤1
🚀 Java Streams: Основные методы для чистого и эффективного кода!
Java Streams предлагают множество методов для упрощения манипуляций с данными и повышения читаемости кода.
Вот краткое руководство с примерами:
Освойте эти методы, чтобы писать более чистый и эффективный код на Java! 💡
👉@BookJava
Java Streams предлагают множество методов для упрощения манипуляций с данными и повышения читаемости кода.
Вот краткое руководство с примерами:
Освойте эти методы, чтобы писать более чистый и эффективный код на Java! 💡
👉@BookJava
👍4
👩💻🎯 Открытый урок «Основы многопоточности в Java».
🗓 7 июля в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java-разработчик».
Приглашаем вас на бесплатный вебинар, посвященный основам многопоточности в Java. Абсолютное большинство коммерческих Java-приложений работает в многопоточном режиме, и понимание принципов многопоточной обработки позволяет писать более эффективные программы, избегая распространенных ошибок. На занятии мы разберем ключевые подходы к многопоточности, изучим используемые классы, а также рассмотрим типовые проблемы и их решения.
Программа урока:
✔️ Введение в многопоточность: что это и зачем это нужно.
✔️ Изучение базовых классов для работы с потоками.
✔️ Разбор типовых проблем многопоточности и подходов к их решению.
Урок будет полезен тем, кто хочет:
- Разобраться в основах многопоточности в Java.
- Понять, как писать многопоточные программы.
- Узнать, какие классы используются для работы с потоками в Java.
В результате урока вы:
- Поймете подходы к многопоточности в Java.
- Изучите базовые классы и синтаксис многопоточной обработки.
- Сможете применять полученные знания для создания более эффективных Java-приложений.
🔗 Ссылка на регистрацию: https://vk.cc/cNjooh
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🗓 7 июля в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java-разработчик».
Приглашаем вас на бесплатный вебинар, посвященный основам многопоточности в Java. Абсолютное большинство коммерческих Java-приложений работает в многопоточном режиме, и понимание принципов многопоточной обработки позволяет писать более эффективные программы, избегая распространенных ошибок. На занятии мы разберем ключевые подходы к многопоточности, изучим используемые классы, а также рассмотрим типовые проблемы и их решения.
Программа урока:
Урок будет полезен тем, кто хочет:
- Разобраться в основах многопоточности в Java.
- Понять, как писать многопоточные программы.
- Узнать, какие классы используются для работы с потоками в Java.
В результате урока вы:
- Поймете подходы к многопоточности в Java.
- Изучите базовые классы и синтаксис многопоточной обработки.
- Сможете применять полученные знания для создания более эффективных Java-приложений.
🔗 Ссылка на регистрацию: https://vk.cc/cNjooh
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1👎1👏1
JEP 511 расширяет язык программирования Java, добавляя возможность кратко импортировать все пакеты, экспортируемые модулем — это упрощает повторное использование модульных библиотек, но при этом не требует, чтобы код, осуществляющий импорт, сам находился в модуле.
➡️ Подробнее: https://openjdk.org/jeps/511
👉@BookJava
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1
2 июля(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама. ООО "ШОРТКАТ", ИНН: 9731139396, erid: 2VtzqxP5g9d
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
🔥 Пройдите тест! 💻 Ответьте на 22 вопроса и узнайте, достаточно ли у вас знаний, для обучения на онлайн-курсе «Java Developer. Advanced» от OTUS.
На курсе вы изучите:
Вас ждут живые вебинары, общение с преподавателями и вашей группой в Telegram, сдача домашних работ и получение обратной связи от преподавателя..
🦾 Пора стать тем самым разработчиком, которого компании хантят друг у друга. Нужно только перейти на принципиально новый уровень.
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
10 полезных функций, которые часто пригождаются продвинутым Java-разработчикам
1. Safe Cast с Optional
2. Таймер производительности (Stopwatch)
3. Deep Copy через сериализацию
4. Рекурсивный поиск файлов с фильтром
5. Универсальный Retry Wrapper
6. Сериализация Map в query string
7. Группировка по произвольному ключу
8. Метод ожидания условия с таймаутом
9. Поиск первого ненулевого значения
10. Конвертация Enum в Map
👉@BookJava
1. Safe Cast с Optional
public static <T> Optional<T> safeCast(Object obj, Class<T> clazz) {
return clazz.isInstance(obj) ? Optional.of(clazz.cast(obj)) : Optional.empty();
}
2. Таймер производительности (Stopwatch)
public static <T> T measureTime(String label, Supplier<T> supplier) {
long start = System.nanoTime();
T result = supplier.get();
long duration = System.nanoTime() - start;
System.out.printf("[%s] Duration: %d ms%n", label, duration / 1_000_000);
return result;
}
3. Deep Copy через сериализацию
@SuppressWarnings("unchecked")
public static <T extends Serializable> T deepCopy(T object) {
try (
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)
) {
oos.writeObject(object);
try (
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais)
) {
return (T) ois.readObject();
}
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException("Deep copy failed", e);
}
}
4. Рекурсивный поиск файлов с фильтром
public static List<Path> findFiles(Path root, Predicate<Path> filter) throws IOException {
try (Stream<Path> stream = Files.walk(root)) {
return stream.filter(Files::isRegularFile).filter(filter).collect(Collectors.toList());
}
}
5. Универсальный Retry Wrapper
public static <T> T retry(int attempts, Duration delay, Supplier<T> task) {
for (int i = 1; i <= attempts; i++) {
try {
return task.get();
} catch (Exception e) {
if (i == attempts) throw e;
try { Thread.sleep(delay.toMillis()); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); }
}
}
throw new RuntimeException("Retry failed");
}
6. Сериализация Map в query string
public static String toQueryString(Map<String, String> params) {
return params.entrySet().stream()
.map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8) + "=" +
URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
}
7. Группировка по произвольному ключу
public static <T, K> Map<K, List<T>> groupBy(Collection<T> items, Function<T, K> classifier) {
return items.stream().collect(Collectors.groupingBy(classifier));
}
8. Метод ожидания условия с таймаутом
public static boolean waitFor(Predicate<Void> condition, Duration timeout, Duration interval) {
long deadline = System.currentTimeMillis() + timeout.toMillis();
while (System.currentTimeMillis() < deadline) {
if (condition.test(null)) return true;
try { Thread.sleep(interval.toMillis()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}
return false;
}
9. Поиск первого ненулевого значения
@SafeVarargs
public static <T> Optional<T> firstNonNull(Supplier<T>... suppliers) {
for (Supplier<T> supplier : suppliers) {
T value = supplier.get();
if (value != null) return Optional.of(value);
}
return Optional.empty();
}
10. Конвертация Enum в Map
public static <E extends Enum<E>> Map<String, E> enumMap(Class<E> enumClass) {
return Arrays.stream(enumClass.getEnumConstants())
.collect(Collectors.toMap(Enum::name, Function.identity()));
}
👉@BookJava
👍7🤡4🔥1👏1🤔1
🧠Принципы SOLID
📌 S — Single Responsibility Principle (SRP)
Класс должен иметь только одну причину для изменения.
📌 O — Open/Closed Principle (OCP)
Классы открыты для расширения, но закрыты для изменения.
📌 L — Liskov Substitution Principle (LSP)
Объекты подклассов должны заменять объекты суперклассов без ошибок.
⚠️ Нарушение LSP вызывает баги, когда подкласс меняет поведение базового класса.
✅ Решение — выносить общее поведение в интерфейсы по возможностям, а не по наследованию.
📌 I — Interface Segregation Principle (ISP)
Лучше несколько маленьких интерфейсов, чем один жирный.
📌 D — Dependency Inversion Principle (DIP)
Модули верхнего уровня не должны зависеть от низкоуровневых. Зависимость — от абстракций.
💡 Spring идеально подходит для соблюдения DIP — внедрение зависимостей через
Если вы соблюдаете SOLID — ваш код легче тестировать, расширять и поддерживать. Но без фанатизма: балансируйте с принципами KISS и YAGNI.
👉@BookJava
📌 S — Single Responsibility Principle (SRP)
Класс должен иметь только одну причину для изменения.
// ❌ Плохо: один класс делает и валидацию, и сохранение
class UserService {
void register(User user) {
if (user.email().isBlank()) throw new IllegalArgumentException();
userRepository.save(user);
}
}
// ✅ Хорошо: разбили ответственности
class UserValidator {
void validate(User user) { /*...*/ }
}
class UserService {
void register(User user) {
validator.validate(user);
userRepository.save(user);
}
}
📌 O — Open/Closed Principle (OCP)
Классы открыты для расширения, но закрыты для изменения.
// ✅ Используем Strategy вместо if-else
interface DiscountStrategy {
BigDecimal apply(BigDecimal price);
}
class BlackFridayDiscount implements DiscountStrategy {
public BigDecimal apply(BigDecimal price) { return price.multiply(new BigDecimal("0.8")); }
}
class CheckoutService {
BigDecimal checkout(BigDecimal price, DiscountStrategy strategy) {
return strategy.apply(price);
}
}
📌 L — Liskov Substitution Principle (LSP)
Объекты подклассов должны заменять объекты суперклассов без ошибок.
⚠️ Нарушение LSP вызывает баги, когда подкласс меняет поведение базового класса.
class Bird {
void fly() { /*...*/ }
}
class Ostrich extends Bird {
void fly() { throw new UnsupportedOperationException(); } // ❌ нарушает LSP
}
✅ Решение — выносить общее поведение в интерфейсы по возможностям, а не по наследованию.
📌 I — Interface Segregation Principle (ISP)
Лучше несколько маленьких интерфейсов, чем один жирный.
// ❌ Плохо: интерфейс заставляет имплементировать ненужное
interface Machine {
void print(); void scan(); void fax();
}
// ✅ Хорошо: разделение по возможностям
interface Printer { void print(); }
interface Scanner { void scan(); }
📌 D — Dependency Inversion Principle (DIP)
Модули верхнего уровня не должны зависеть от низкоуровневых. Зависимость — от абстракций.
// ✅ Вместо прямой зависимости от класса — интерфейс
interface NotificationSender {
void send(String message);
}
class EmailSender implements NotificationSender { /*...*/ }
class UserNotifier {
private final NotificationSender sender;
public UserNotifier(NotificationSender sender) {
this.sender = sender;
}
}
💡 Spring идеально подходит для соблюдения DIP — внедрение зависимостей через
@Autowired
или @Bean
.Если вы соблюдаете SOLID — ваш код легче тестировать, расширять и поддерживать. Но без фанатизма: балансируйте с принципами KISS и YAGNI.
👉@BookJava
👍7❤3
🧑🏻💻Хотите научиться создавать приложения на Android?
9 июля в 20:00 МСК мы разберёмся, как создать простое приложение «Фото дня». На открытом вебинаре вы научитесь работать с API, скачивать данные с сервера, отображать фотографии и их описания в приложении, а также писать бизнес-логику для загрузки и отображения информации.
Вы освоите ключевые навыки, необходимые начинающему разработчику Android-приложений: подключение к серверу, взаимодействие с API, отображение данных и создание интерфейса. Этот опыт станет основой для вашего пути в мобильной разработке.
⚡️Открытый урок проходит в преддверии старта курса «Android Developer». Все участники получат скидку на обучение. Регистрация открыта: https://vk.cc/cNsUdo
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
9 июля в 20:00 МСК мы разберёмся, как создать простое приложение «Фото дня». На открытом вебинаре вы научитесь работать с API, скачивать данные с сервера, отображать фотографии и их описания в приложении, а также писать бизнес-логику для загрузки и отображения информации.
Вы освоите ключевые навыки, необходимые начинающему разработчику Android-приложений: подключение к серверу, взаимодействие с API, отображение данных и создание интерфейса. Этот опыт станет основой для вашего пути в мобильной разработке.
⚡️Открытый урок проходит в преддверии старта курса «Android Developer». Все участники получат скидку на обучение. Регистрация открыта: https://vk.cc/cNsUdo
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Media is too big
VIEW IN TELEGRAM
Абстрактные классы и методы в Java: объяснение за 7 минут
Что такое абстрактные классы и методы в Java, как и зачем их использовать?
Также — в чём разница между абстрактным классом и интерфейсом?
Абстрактные классы могут показаться странной и сложной концепцией в Java, но на самом деле всё довольно просто. Мы объясним их всего за несколько минут в этом видеоуроке для начинающих по Java.
Как создать абстрактный класс или абстрактный метод? Почему вообще стоит использовать абстрактный класс в Java? Чем абстрактный класс отличается от интерфейса?
Улучшайте свои знания Java, наблюдая за живым написанием кода!
Привет, меня зовут Джон! Я ведущий инженер-программист Java с более чем десятилетним опытом работы в индустрии. Мне нравится делиться тем, что я узнал за эти годы, понятным языком — для программистов любого уровня.
👉@BookJava
Что такое абстрактные классы и методы в Java, как и зачем их использовать?
Также — в чём разница между абстрактным классом и интерфейсом?
Абстрактные классы могут показаться странной и сложной концепцией в Java, но на самом деле всё довольно просто. Мы объясним их всего за несколько минут в этом видеоуроке для начинающих по Java.
Как создать абстрактный класс или абстрактный метод? Почему вообще стоит использовать абстрактный класс в Java? Чем абстрактный класс отличается от интерфейса?
Улучшайте свои знания Java, наблюдая за живым написанием кода!
Привет, меня зовут Джон! Я ведущий инженер-программист Java с более чем десятилетним опытом работы в индустрии. Мне нравится делиться тем, что я узнал за эти годы, понятным языком — для программистов любого уровня.
👉@BookJava
👍2
🗓 17 июля в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Java-разработчик».
Ошибки в кодировках ломают приложения, превращая текст в «абракадабру». Понимание таблиц кодировок — must-have навык для работы с данными, файлами и международными проектами.
О чём поговорим:
Кому будет интересно:
Начинающим Java-разработчикам и тестировщикам, сталкивающимся с международными данными и проблемами кодировки.
В результате вебинара вы:
Научитесь контролировать кодировки в своих приложениях, исправлять «кракозябры» и работать с любыми текстовыми данными без страха.
🔗 Ссылка на регистрацию: https://vk.cc/cNvkAu
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM