История технологий сегодня — 11 марта
ℹ️ Кто родился в этот день
Джозеф Карл Робнетт Ликлайдер (англ. Joseph Carl Robnett Licklider; 11 марта 1915, Сент-Луис, штат Миссури, США — 26 июня 1990, Арлингтон, штат Массачусетс, США) — известный в научной и ИТ-среде как J.C.R. или «Лик» («Lick») — американский учёный. Ранние работы были посвящены психоакустике, последующие работы — сфере информационных технологий. Один из создателей сети ARPANET, прототипа Интернета.
В 1962—1964 годы работал в ARPA, заложил основы ARPANET. Высказал идею необходимости создания объединения компьютеров в сеть со свободным доступом любого человека из любого места мира к её ресурсам. Ликлайдера называют духовным отцом всемирной сети, человеком, посеявшим семена Интернета.
Вклад Ликлайдера в возникновение Интернета огромен, он состоит из идей и принципов, а не из изобретений и технологий. Ликлайдер предвидел необходимость объединения в сеть компьютеров, имеющих простые пользовательские интерфейсы. Его идеи предвосхитили компьютерную графику, интерфейсы, работающие по принципу указания и выбора (point-and-click), цифровые библиотеки, электронную коммерцию (e-commerce), дистанционное банковское обслуживание (online banking), а также программное обеспечение, размещаемое в сети. В США его считают «Джонни Эпплсидом программирования».
Вэни́вар[a] Буш (англ. Vannevar Bush /væˈniːvɑr/, 11 марта 1890, Эверетт, Массачусетс — 28 июня 1974, Белмонт, Массачусетс) — американский ученый, инженер, разработчик аналоговых компьютеров, методолог и организатор научных исследований и научного сообщества. Советник по науке при президенте Рузвельте. Автор статьи «Как мы можем мыслить», в которой предложил прообраз гипертекстового устройства Memex (интересное дальновидение - мое прим.).
Урбе́н Жан Жозе́ф Леверье́ (фр. Urbain Jean Joseph Le Verrier; 11 марта 1811, Сен-Ло — 23 сентября 1877, Париж) — французский математик, занимавшийся небесной механикой, бо́льшую часть своей жизни проработавший в Парижской обсерватории. Его наиболее известным достижением является предсказание существования планеты Нептун, сделанное с помощью математического анализа астрономических наблюдений. По предложению Франсуа Араго он выполнил вычисления для объяснения несоответствий между наблюдаемой орбитой Урана и той, которая должна быть согласно законам Кеплера и Ньютона.
🌐 Знаковые события
1878 — Французской Академии продемонстрирован фонограф, но изобретение было объявлено шарлатанством.
#Biography #Birth_Date #Events #11марта
Джозеф Карл Робнетт Ликлайдер (англ. Joseph Carl Robnett Licklider; 11 марта 1915, Сент-Луис, штат Миссури, США — 26 июня 1990, Арлингтон, штат Массачусетс, США) — известный в научной и ИТ-среде как J.C.R. или «Лик» («Lick») — американский учёный. Ранние работы были посвящены психоакустике, последующие работы — сфере информационных технологий. Один из создателей сети ARPANET, прототипа Интернета.
В 1962—1964 годы работал в ARPA, заложил основы ARPANET. Высказал идею необходимости создания объединения компьютеров в сеть со свободным доступом любого человека из любого места мира к её ресурсам. Ликлайдера называют духовным отцом всемирной сети, человеком, посеявшим семена Интернета.
Вклад Ликлайдера в возникновение Интернета огромен, он состоит из идей и принципов, а не из изобретений и технологий. Ликлайдер предвидел необходимость объединения в сеть компьютеров, имеющих простые пользовательские интерфейсы. Его идеи предвосхитили компьютерную графику, интерфейсы, работающие по принципу указания и выбора (point-and-click), цифровые библиотеки, электронную коммерцию (e-commerce), дистанционное банковское обслуживание (online banking), а также программное обеспечение, размещаемое в сети. В США его считают «Джонни Эпплсидом программирования».
Вэни́вар[a] Буш (англ. Vannevar Bush /væˈniːvɑr/, 11 марта 1890, Эверетт, Массачусетс — 28 июня 1974, Белмонт, Массачусетс) — американский ученый, инженер, разработчик аналоговых компьютеров, методолог и организатор научных исследований и научного сообщества. Советник по науке при президенте Рузвельте. Автор статьи «Как мы можем мыслить», в которой предложил прообраз гипертекстового устройства Memex (интересное дальновидение - мое прим.).
Урбе́н Жан Жозе́ф Леверье́ (фр. Urbain Jean Joseph Le Verrier; 11 марта 1811, Сен-Ло — 23 сентября 1877, Париж) — французский математик, занимавшийся небесной механикой, бо́льшую часть своей жизни проработавший в Парижской обсерватории. Его наиболее известным достижением является предсказание существования планеты Нептун, сделанное с помощью математического анализа астрономических наблюдений. По предложению Франсуа Араго он выполнил вычисления для объяснения несоответствий между наблюдаемой орбитой Урана и той, которая должна быть согласно законам Кеплера и Ньютона.
1878 — Французской Академии продемонстрирован фонограф, но изобретение было объявлено шарлатанством.
#Biography #Birth_Date #Events #11марта
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
[Совет по Java #014]
Тема: Инъекция через конструктор предпочтительнее инъекции в поле. Она делает зависимости явными, поля immutable и упрощает тестирование. В новых версиях Spring @Autowired можно не ставить, если конструктор один.
Проблема: Инъекция зависимостей через поле (@Autowired над полем) — самый быстрый способ написать код, но он создает скрытые проблемы.
Поля не могут быть final, что нарушает иммутабельность и позволяет создавать объекты в частично инициализированном состоянии.
При тестировании невозможно подставить mock через конструктор — приходится использовать рефлексию (PowerMock, ReflectionTestUtils) или поднимать контекст Spring.
Также это скрывает обязательные зависимости: глядя на класс, непонятно, без каких компонентов он не может работать.
Решение: Используйте конструктор для инъекции зависимостей.
Все поля помечайте как private final — они инициализируются один раз при создании бина и гарантированно не равны null после этого.
Объяснение: Constructor injection гарантирует, что все необходимые зависимости будут предоставлены в момент создания объекта.
Пометка полей как final защищает от случайного изменения и делает класс потокобезопасным (если сами зависимости потокобезопасны).
Проверка Objects.requireNonNull() в конструкторе обеспечивает раннее обнаружение ошибок конфигурации.
При использовании одного конструктора Spring автоматически использует его для инъекции — аннотация @Autowired становится опциональной, что соответствует принципу "convention over configuration".
Для циклических зависимостей используется @Lazy.
Разработчик всегда предпочитает constructor injection, оставляя field injection только для очень специфичных случаев (например, некоторые тестовые фреймворки).
#Java #советы
Тема: Инъекция через конструктор предпочтительнее инъекции в поле. Она делает зависимости явными, поля immutable и упрощает тестирование. В новых версиях Spring @Autowired можно не ставить, если конструктор один.
Проблема: Инъекция зависимостей через поле (@Autowired над полем) — самый быстрый способ написать код, но он создает скрытые проблемы.
Поля не могут быть final, что нарушает иммутабельность и позволяет создавать объекты в частично инициализированном состоянии.
При тестировании невозможно подставить mock через конструктор — приходится использовать рефлексию (PowerMock, ReflectionTestUtils) или поднимать контекст Spring.
Также это скрывает обязательные зависимости: глядя на класс, непонятно, без каких компонентов он не может работать.
Решение: Используйте конструктор для инъекции зависимостей.
Все поля помечайте как private final — они инициализируются один раз при создании бина и гарантированно не равны null после этого.
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import java.util.Objects;
//Антипаттерн: field injection
@Service
public class BadService {
@Autowired
private UserRepository userRepository; // не final, можно забыть проинициализировать
@Autowired
private EmailService emailService; // скрытая зависимость
public void registerUser(User user) {
// может быть NullPointerException, если забыли протестировать
userRepository.save(user);
emailService.sendWelcome(user);
}
// невозможно создать объект в тесте без Spring
}
//Правильно: constructor injection
@Service
public class GoodService {
private final UserRepository userRepository;
private final EmailService emailService;
private final AuditService auditService;
// С одним конструктором @Autowired не нужен (Spring 4.3+)
public GoodService(UserRepository userRepository,
EmailService emailService,
@Lazy AuditService auditService) {
this.userRepository = Objects.requireNonNull(userRepository,
"UserRepository must not be null");
this.emailService = Objects.requireNonNull(emailService);
this.auditService = auditService; // @Lazy — прокси будет создан при первом вызове
}
public void registerUser(User user) {
userRepository.save(user);
emailService.sendWelcome(user);
auditService.log("User registered: " + user.getId());
}
}
// Для циклических зависимостей — @Lazy
@Service
class A {
private final B b;
public A(@Lazy B b) { // B создастся лениво
this.b = b;
}
}
@Service
class B {
private final A a;
public B(A a) {
this.a = a;
}
}
Объяснение: Constructor injection гарантирует, что все необходимые зависимости будут предоставлены в момент создания объекта.
Пометка полей как final защищает от случайного изменения и делает класс потокобезопасным (если сами зависимости потокобезопасны).
Проверка Objects.requireNonNull() в конструкторе обеспечивает раннее обнаружение ошибок конфигурации.
При использовании одного конструктора Spring автоматически использует его для инъекции — аннотация @Autowired становится опциональной, что соответствует принципу "convention over configuration".
Для циклических зависимостей используется @Lazy.
Разработчик всегда предпочитает constructor injection, оставляя field injection только для очень специфичных случаев (например, некоторые тестовые фреймворки).
#Java #советы
👍4
Что выведет код?
#Tasks
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class Task110326 {
public static void main(String[] args) {
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Task110326.class)) {
UserService110326 service = context.getBean(UserService110326.class);
System.out.println(service.getUser());
}
}
}
@Component
class UserService110326 {
private UserRepository110326 userRepository;
@Autowired
public UserService110326(UserRepository110326 userRepository) {
this.userRepository = userRepository;
}
public String getUser() {
return userRepository.findUser();
}
}
@Component
class UserRepository110326 {
private DatabaseService110326 databaseService;
@Autowired
public UserRepository110326(DatabaseService110326 databaseService) {
this.databaseService = databaseService;
}
public String findUser() {
return "User from " + databaseService.getDataSource();
}
}
@Component
class DatabaseService110326 {
public String getDataSource() {
return "MainDB";
}
}
#Tasks
👍2
Варианты ответа:
Anonymous Quiz
56%
User from MainDB
11%
User from null
11%
Исключение NoSuchBeanDefinitionException
22%
Исключение NullPointerException
👍1
Что такое SOLID принципы? 🤓
Ответ:
SOLID — это пять основных принципов объектно-ориентированного проектирования.
S — Single Responsibility Principle (Принцип единственной ответственности): у класса должна быть только одна причина для изменения.
O — Open/Closed Principle (Открытости/закрытости): классы открыты для расширения, но закрыты для изменения.
L — Liskov Substitution Principle (Подстановки Лисков): наследники не должны нарушать поведение базового класса.
I — Interface Segregation Principle (Разделения интерфейса): много специализированных интерфейсов лучше, чем один общий.
D — Dependency Inversion Principle (Инверсии зависимостей): зависимости должны строиться на абстракциях, а не на конкретных классах.
#собеседование
Ответ:
S — Single Responsibility Principle (Принцип единственной ответственности): у класса должна быть только одна причина для изменения.
O — Open/Closed Principle (Открытости/закрытости): классы открыты для расширения, но закрыты для изменения.
L — Liskov Substitution Principle (Подстановки Лисков): наследники не должны нарушать поведение базового класса.
I — Interface Segregation Principle (Разделения интерфейса): много специализированных интерфейсов лучше, чем один общий.
D — Dependency Inversion Principle (Инверсии зависимостей): зависимости должны строиться на абстракциях, а не на конкретных классах.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
История технологий сегодня — 12 марта
ℹ️ Кто родился в этот день
Пётр Алекса́ндрович Фре́зе (29 февраля [12 марта] 1844, Санкт-Петербург, Российская империя — 24 апреля 1918, Граново, Вышневолоцкий уезд, Тверская губерния, РСФСР) — российский изобретатель, один из конструкторов первого российского автомобиля.
🌐 Знаковые события
1889 — Элмон Строуджер из США запатентовал автоматическую телефонную станцию.
1974 — станция «Марс-6» села на Марсе, впервые передав на Землю данные об атмосфере и почве этой планеты.
#Biography #Birth_Date #Events #12марта
Пётр Алекса́ндрович Фре́зе (29 февраля [12 марта] 1844, Санкт-Петербург, Российская империя — 24 апреля 1918, Граново, Вышневолоцкий уезд, Тверская губерния, РСФСР) — российский изобретатель, один из конструкторов первого российского автомобиля.
1889 — Элмон Строуджер из США запатентовал автоматическую телефонную станцию.
1974 — станция «Марс-6» села на Марсе, впервые передав на Землю данные об атмосфере и почве этой планеты.
#Biography #Birth_Date #Events #12марта
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Раздел 8. Stream API и функциональный стиль в Java
Глава 5: Контракты. Почему equals, hashCode и иммутабельность — закон
Иммутабельность данных в потоке — не прихоть, а необходимость
Stream API построен на функциональной парадигме, где данные текут через преобразования, сохраняя свою сущность неизменной. Этот принцип — иммутабельность (immutability) — не эстетическая прихоть, а архитектурный фундамент, обеспечивающий предсказуемость, безопасность параллелизма и корректность ленивых вычислений.
Когда мы говорим "поток обрабатывает данные, а не изменяет их", мы противопоставляем два ментальных модуса: трансформацию как порождение нового и мутацию как изменение существующего. Императивный код часто смешивает их: цикл читает элемент, модифицирует его поля, кладёт в результат. Потоковый код разделяет: исходные данные остаются неизменными, каждая операция порождает новое представление.
Контракт неизменности источника
Исходная коллекция, породившая поток, не должна модифицироваться во время обхода. Это правило кажется очевидным, но нарушается из-за недопонимания ленивости:
Поведение неопределённо. Если поток использует Iterator (коллекция не SIZED), модификация после создания потока, но до начала обхода выбросит ConcurrentModificationException при проверке modCount. Если поток использует Spliterator с характеристикой SIZED (например, ArrayList), и терминальная операция предвыделяет размер, добавление элемента приведёт к ArrayIndexOutOfBoundsException или пропуску элементов.
Ещё опаснее модификация внутри потоковой операции:
Удаление элементов из коллекции во время её обхода — классическая ошибка, приводящая к исключению или пропуску элементов из-за сдвига индексов.
Правильный подход — создание новой коллекции вместо модификации существующей:
Иммутабельность промежуточных результатов
Не только источник, но и объекты в потоке должны быть неизменяемыми для корректности.
Рассмотрим изменяемый объект в map:
forEach здесь используется не для агрегации, а для побочного эффекта — инкремента счётчика. Исходные объекты модифицированы, что делает код сложным для отладки и тестирования. Если позже тот же список обрабатывается другим потоком, результаты зависят от порядка выполнения.
Рефакторинг к иммутабельности:
Здесь "обновление" — порождение новой версии объекта, а не модификация существующего. Старые данные сохраняются, новые создаются, история не разрушается.
#Java #для_новичков #beginner #stream_api
Глава 5: Контракты. Почему equals, hashCode и иммутабельность — закон
Иммутабельность данных в потоке — не прихоть, а необходимость
Stream API построен на функциональной парадигме, где данные текут через преобразования, сохраняя свою сущность неизменной. Этот принцип — иммутабельность (immutability) — не эстетическая прихоть, а архитектурный фундамент, обеспечивающий предсказуемость, безопасность параллелизма и корректность ленивых вычислений.
Когда мы говорим "поток обрабатывает данные, а не изменяет их", мы противопоставляем два ментальных модуса: трансформацию как порождение нового и мутацию как изменение существующего. Императивный код часто смешивает их: цикл читает элемент, модифицирует его поля, кладёт в результат. Потоковый код разделяет: исходные данные остаются неизменными, каждая операция порождает новое представление.
Контракт неизменности источника
Исходная коллекция, породившая поток, не должна модифицироваться во время обхода. Это правило кажется очевидным, но нарушается из-за недопонимания ленивости:
List<Book> library = new ArrayList<>(fetchBooks());
Stream<Book> stream = library.stream(); // Поток создан, но не активирован
// Позже, до терминальной операции:
library.add(new Book("New", "Author", 2024)); // Модификация источника!
// Теперь терминальная операция:
List<Book> result = stream.collect(toList()); // ConcurrentModificationException?
Поведение неопределённо. Если поток использует Iterator (коллекция не SIZED), модификация после создания потока, но до начала обхода выбросит ConcurrentModificationException при проверке modCount. Если поток использует Spliterator с характеристикой SIZED (например, ArrayList), и терминальная операция предвыделяет размер, добавление элемента приведёт к ArrayIndexOutOfBoundsException или пропуску элементов.
Ещё опаснее модификация внутри потоковой операции:
// Катастрофа: модификация источника изнутри потока
library.stream()
.filter(b -> b.year() < 1950)
.forEach(library::remove); // ConcurrentModificationException гарантирован
Удаление элементов из коллекции во время её обхода — классическая ошибка, приводящая к исключению или пропуску элементов из-за сдвига индексов.
Правильный подход — создание новой коллекции вместо модификации существующей:
// Правильно: фильтрация через collect, не removeIf в потоке
List<Book> modernBooks = library.stream()
.filter(b -> b.year() >= 1950)
.collect(toList());
// Или без потока, если модификация исходной нужна:
library.removeIf(b -> b.year() < 1950); // Метод коллекции, не Stream API
Иммутабельность промежуточных результатов
Не только источник, но и объекты в потоке должны быть неизменяемыми для корректности.
Рассмотрим изменяемый объект в map:
public class MutableBook {
private String title;
private int readCount; // Мутабельное поле!
public void incrementRead() { readCount++; }
}
// Антипаттерн: мутация внутри потока
List<MutableBook> books = fetchBooks();
books.stream()
.filter(b -> b.getTitle().startsWith("A"))
.forEach(MutableBook::incrementRead); //Модифицируем исходные объекты!
// Теперь исходный список books изменён — побочный эффектforEach здесь используется не для агрегации, а для побочного эффекта — инкремента счётчика. Исходные объекты модифицированы, что делает код сложным для отладки и тестирования. Если позже тот же список обрабатывается другим потоком, результаты зависят от порядка выполнения.
Рефакторинг к иммутабельности:
public record Book(String title, int readCount) {
public Book withIncrementedRead() {
return new Book(title, readCount + 1); //Новый экземпляр
}
}
// Правильно: создание новых объектов
List<Book> updatedBooks = books.stream()
.filter(b -> b.title().startsWith("A"))
.map(Book::withIncrementedRead)
.collect(toList());
// Исходный список books неизменёнЗдесь "обновление" — порождение новой версии объекта, а не модификация существующего. Старые данные сохраняются, новые создаются, история не разрушается.
#Java #для_новичков #beginner #stream_api
👍6
Контролируемые побочные эффекты
Абсолютный запрет на побочные эффекты невозможен в реальных системах. Логирование, метрики, кэширование, внешние вызовы — всё это требует взаимодействия с внешним миром. Различие между допустимым и недопустимым — в контролируемости и изоляции.
Критерии контролируемого побочного эффекта:
Идемпотентность: повторный вызов с теми же входными данными даёт тот же результат (или эквивалентный с точки зрения системы).
Потокобезопасность: при параллельном выполнении эффект корректен без дополнительной синхронизации.
Изолированность: эффект не влияет на другие элементы потока или внешнее состояние, используемое в потоке.
Необходимость: эффект является целью операции, не побочным продуктом.
Пример: атомарный счётчик для отладки
AtomicInteger обеспечивает потокобезопасность инкремента. Эффект изолирован — счётчик не влияет на обработку элементов. Он идемпотентен с точки зрения бизнес-логики (конечный результат results не зависит от счётчика). Но это всё ещё антипаттерн: peek предназначен для отладки, а не для бизнес-логики, и его поведение может измениться в будущих версиях JDK.
Более чистый подход — отделение агрегации от обработки:
Или использование teeing для подсчёта параллельно с сбором результатов.
Пример: логирование
Логирование — необходимый побочный эффект. Он потокобезопасен, если auditLog потокобезопасен. Он изолирован — не влияет на обработку заказа. Но размещение в peek рискованно: при оптимизации конвейера peek может быть пропущен или вызван менее раз, чем ожидается.
Надёжнее:
Теперь логирование гарантировано для каждого прошедшего фильтр элемента, хотя map с побочным эффектом всё ещё нарушает чистоту функции.
Граница допустимого
Правило практики: побочные эффекты допустимы только в терминальных операциях, работающих с уже потокобезопасными внешними системами. forEach для отправки сообщений в Kafka, collect в ConcurrentHashMap, reduce с атомарными операциями — приемлемы. Побочные эффекты в промежуточных операциях (map, filter, flatMap) — почти всегда ошибка.
Исключение — кэширование вычислений внутри операции, но и здесь предпочтительны чистые функции с мемоизацией вне потока.
#Java #для_новичков #beginner #stream_api
Абсолютный запрет на побочные эффекты невозможен в реальных системах. Логирование, метрики, кэширование, внешние вызовы — всё это требует взаимодействия с внешним миром. Различие между допустимым и недопустимым — в контролируемости и изоляции.
Критерии контролируемого побочного эффекта:
Идемпотентность: повторный вызов с теми же входными данными даёт тот же результат (или эквивалентный с точки зрения системы).
Потокобезопасность: при параллельном выполнении эффект корректен без дополнительной синхронизации.
Изолированность: эффект не влияет на другие элементы потока или внешнее состояние, используемое в потоке.
Необходимость: эффект является целью операции, не побочным продуктом.
Пример: атомарный счётчик для отладки
AtomicInteger processedCount = new AtomicInteger(0);
List<Result> results = items.parallelStream()
.map(this::heavyProcessing)
.peek(r -> processedCount.incrementAndGet()) // Контролируемый эффект
.collect(toList());
System.out.println("Обработано: " + processedCount.get());
AtomicInteger обеспечивает потокобезопасность инкремента. Эффект изолирован — счётчик не влияет на обработку элементов. Он идемпотентен с точки зрения бизнес-логики (конечный результат results не зависит от счётчика). Но это всё ещё антипаттерн: peek предназначен для отладки, а не для бизнес-логики, и его поведение может измениться в будущих версиях JDK.
Более чистый подход — отделение агрегации от обработки:
// Лучше: явная агрегация результата
class ProcessingResult {
final List<Result> results;
final int count;
ProcessingResult(List<Result> results, int count) {
this.results = results;
this.count = count;
}
}
ProcessingResult finalResult = items.parallelStream()
.collect(() -> new ProcessingResult(new ArrayList<>(), 0),
(acc, item) -> {
acc.results.add(process(item));
acc.count++;
},
(left, right) -> {
left.results.addAll(right.results);
left.count += right.count;
});
Или использование teeing для подсчёта параллельно с сбором результатов.
Пример: логирование
orders.stream()
.filter(o -> o.amount().compareTo(THRESHOLD) > 0)
.peek(o -> auditLog.record("Крупный заказ", o.id())) // Побочный эффект
.map(this::processLargeOrder)
.collect(toList());
Логирование — необходимый побочный эффект. Он потокобезопасен, если auditLog потокобезопасен. Он изолирован — не влияет на обработку заказа. Но размещение в peek рискованно: при оптимизации конвейера peek может быть пропущен или вызван менее раз, чем ожидается.
Надёжнее:
List<ProcessedOrder> processed = orders.stream()
.filter(o -> o.amount().compareTo(THRESHOLD) > 0)
.map(o -> {
auditLog.record("Крупный заказ", o.id()); // Явный эффект в map
return processLargeOrder(o);
})
.collect(toList());
Теперь логирование гарантировано для каждого прошедшего фильтр элемента, хотя map с побочным эффектом всё ещё нарушает чистоту функции.
Граница допустимого
Правило практики: побочные эффекты допустимы только в терминальных операциях, работающих с уже потокобезопасными внешними системами. forEach для отправки сообщений в Kafka, collect в ConcurrentHashMap, reduce с атомарными операциями — приемлемы. Побочные эффекты в промежуточных операциях (map, filter, flatMap) — почти всегда ошибка.
Исключение — кэширование вычислений внутри операции, но и здесь предпочтительны чистые функции с мемоизацией вне потока.
#Java #для_новичков #beginner #stream_api
👍5
Что выведет код?
#Tasks
import java.util.*;
import java.util.stream.*;
public class Task120326 {
public static void main(String[] args) {
List<Person120326> people = new ArrayList<>(Arrays.asList(
new Person120326("Alice", 25),
new Person120326("Bob", 30),
new Person120326("Charlie", 20)
));
List<String> names = people.stream()
.map(p -> p.name)
.sorted((a, b) -> {
people.get(0).age = 999;
return a.compareTo(b);
})
.collect(Collectors.toList());
System.out.println(people);
System.out.println(names);
}
static class Person120326 {
String name;
int age;
Person120326(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return name + ":" + age;
}
}
}
#Tasks
👍2
Что такое Dependency Injection (DI) и Inversion of Control (IoC)? 🤓
Ответ:
Inversion of Control (IoC) — это общий принцип, при котором фреймворк управляет потоком программы и объектами, а не наоборот.
Dependency Injection (DI) — это конкретная реализация IoC, при которой объекты получают свои зависимости извне (через конструктор, сеттер или интерфейс), а не создают их сами.
Это уменьшает связанность кода, повышает тестируемость (легко подставить моки) и гибкость.
Главный контейнер DI в Java-мире — это Spring IoC-контейнер.
#собеседование
Ответ:
Dependency Injection (DI) — это конкретная реализация IoC, при которой объекты получают свои зависимости извне (через конструктор, сеттер или интерфейс), а не создают их сами.
Это уменьшает связанность кода, повышает тестируемость (легко подставить моки) и гибкость.
Главный контейнер DI в Java-мире — это Spring IoC-контейнер.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
История технологий сегодня — 13 марта
ℹ️ Кто родился в этот день
Джон Хазбрук Ван Флек (англ. John Hasbrouck van Vleck; 13 марта 1899, Мидлтаун — 27 октября 1980, Кембридж, Массачусетс) — американский физик, лауреат Нобелевской премии по физике 1977 года. Работы по квантовой теории атомной структуры, магнетизму, теории валентности, изучению атомных и молекулярных спектров, ферро- и ферримагнитному резонансу. Один из создателей современных представителей о магнетизме вещества. Разработал квантовомеханическую теорию диа- и парамагнетизма (1926—1928), получил парамагнитную добавку к диамагнитной восприимчивости несимметричных атомов и молекул, названную ванфлековским парамагнетизмом (1927). Развил теорию внутрикристаллического (лигандного) поля. Дал детальную трактовку антиферромагнетизма (1941), термодинамическую теорию молекулярного поля для антиферромагнетиков, развил гейзенберговскую модель локализованных спинов и предложил эффективный спиновый гамильтониан.
🌐 Знаковые события
1781 — Английский астроном Вильям Гершель с помощью собственноручно изготовленного телескопа открыл седьмую планету Солнечной системы — Уран. Правда, первоначально он принял её за комету. Когда выяснилось, что это неизвестная ранее планета, он получил медаль Королевского общества и должность придворного астронома. Сам Гершель назвал планету в честь своего высокого покровителя короля Георга III «Звездой Георга», короткое время она носила имя первооткрывателя, пока немецкий астроном Иоганн Боде не придумал для неё название Уран.
1930 — американский астроном Клайд Томбо объявил в докладе об открытии им 18 февраля девятой планеты Солнечной системы. Доклад был приурочен к 75-летию основателя и первого директора крупнейшей частной обсерватории в США, Персиваля Лоуэлла, который многие годы потратил на поиски предсказанной им девятой планеты. На следующий день 14 марта Венеция Бёрни, одиннадцатилетняя школьница из Оксфорда, предложит имя для новой планеты, и в мае будет опубликовано официальное имя — Плутон.
1989 — была изобретена Всемирная паутина (World Wide Web, WWW), более известная как Интернет. Изобретателем Интернета считается английский учёный Тим Бернерс-Ли и его коллеги, работавшие в Европейском совете по ядерным исследованиям (CERN), передали начальнику своего отдела документ, озаглавленный «Информационный менеджмент: некоторые предложения», в котором были заложены основные принципы WWW.
#Biography #Birth_Date #Events #13марта
Джон Хазбрук Ван Флек (англ. John Hasbrouck van Vleck; 13 марта 1899, Мидлтаун — 27 октября 1980, Кембридж, Массачусетс) — американский физик, лауреат Нобелевской премии по физике 1977 года. Работы по квантовой теории атомной структуры, магнетизму, теории валентности, изучению атомных и молекулярных спектров, ферро- и ферримагнитному резонансу. Один из создателей современных представителей о магнетизме вещества. Разработал квантовомеханическую теорию диа- и парамагнетизма (1926—1928), получил парамагнитную добавку к диамагнитной восприимчивости несимметричных атомов и молекул, названную ванфлековским парамагнетизмом (1927). Развил теорию внутрикристаллического (лигандного) поля. Дал детальную трактовку антиферромагнетизма (1941), термодинамическую теорию молекулярного поля для антиферромагнетиков, развил гейзенберговскую модель локализованных спинов и предложил эффективный спиновый гамильтониан.
1781 — Английский астроном Вильям Гершель с помощью собственноручно изготовленного телескопа открыл седьмую планету Солнечной системы — Уран. Правда, первоначально он принял её за комету. Когда выяснилось, что это неизвестная ранее планета, он получил медаль Королевского общества и должность придворного астронома. Сам Гершель назвал планету в честь своего высокого покровителя короля Георга III «Звездой Георга», короткое время она носила имя первооткрывателя, пока немецкий астроном Иоганн Боде не придумал для неё название Уран.
1930 — американский астроном Клайд Томбо объявил в докладе об открытии им 18 февраля девятой планеты Солнечной системы. Доклад был приурочен к 75-летию основателя и первого директора крупнейшей частной обсерватории в США, Персиваля Лоуэлла, который многие годы потратил на поиски предсказанной им девятой планеты. На следующий день 14 марта Венеция Бёрни, одиннадцатилетняя школьница из Оксфорда, предложит имя для новой планеты, и в мае будет опубликовано официальное имя — Плутон.
1989 — была изобретена Всемирная паутина (World Wide Web, WWW), более известная как Интернет. Изобретателем Интернета считается английский учёный Тим Бернерс-Ли и его коллеги, работавшие в Европейском совете по ядерным исследованиям (CERN), передали начальнику своего отдела документ, озаглавленный «Информационный менеджмент: некоторые предложения», в котором были заложены основные принципы WWW.
#Biography #Birth_Date #Events #13марта
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
[Совет по Java #015]
Тема: @Async по умолчанию не работает внутри того же класса. Вызов асинхронного метода из другого метода этого же класса не пройдет через Spring Proxy.
Проблема: Аннотация @Async работает благодаря Spring AOP, который создает прокси вокруг целевого бина.
При вызове метода через прокси (например, из другого бина) запускается асинхронное выполнение. Однако при прямом вызове из того же класса через this прокси не участвует — вызывается оригинальный метод, и асинхронность теряется.
Это частая ошибка: код выглядит правильно, но метод выполняется синхронно, что приводит к неожиданным задержкам и блокировкам.
Решение: Никогда не вызывайте @Async методы напрямую внутри того же класса.
Используйте self-injection (внедрение ссылки на самого себя через @Autowired/@jakarta.inject.Inject) или вынесите асинхронную логику в отдельный @Service-компонент.
Self-injection заставляет обращаться к прокси, а не к реальному объекту.
Объяснение: Spring создает прокси-объект, который перехватывает вызовы @Async методов и передает их в пул потоков.
Когда бин внедряет сам себя (selfProxy), он получает именно прокси, а не исходный объект. Вызов через selfProxy.asyncMethod() корректно обрабатывается перехватчиком. Self-injection работает благодаря тому, что Spring после создания бина внедряет его же прокси (если включен режим @EnableAsync и прокси-таргет класс). Для этого требуется либо использовать интерфейсы (JDK proxy), либо CGLIB (proxy-target-class=true).
Альтернативное и более чистое решение — вынести асинхронный метод в отдельный бин, что полностью исключает проблему внутренних вызовов.
Разработчик всегда проверяет, через какой объект вызывается @Async метод, и избегает вызовов через this.
#Java #советы
Тема: @Async по умолчанию не работает внутри того же класса. Вызов асинхронного метода из другого метода этого же класса не пройдет через Spring Proxy.
Проблема: Аннотация @Async работает благодаря Spring AOP, который создает прокси вокруг целевого бина.
При вызове метода через прокси (например, из другого бина) запускается асинхронное выполнение. Однако при прямом вызове из того же класса через this прокси не участвует — вызывается оригинальный метод, и асинхронность теряется.
Это частая ошибка: код выглядит правильно, но метод выполняется синхронно, что приводит к неожиданным задержкам и блокировкам.
Решение: Никогда не вызывайте @Async методы напрямую внутри того же класса.
Используйте self-injection (внедрение ссылки на самого себя через @Autowired/@jakarta.inject.Inject) или вынесите асинхронную логику в отдельный @Service-компонент.
Self-injection заставляет обращаться к прокси, а не к реальному объекту.
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.concurrent.CompletableFuture;
@Service
public class AsyncService {
@Autowired
private AsyncService selfProxy; // self-injection
@Async
public CompletableFuture<String> asyncMethod() {
System.out.println("Асинхронный вызов в потоке: " + Thread.currentThread().getName());
return CompletableFuture.completedFuture("Результат");
}
//Проблема: прямой вызов
public void badCall() {
System.out.println("Прямой вызов");
asyncMethod(); // this.asyncMethod() — асинхронности НЕТ!
}
//Решение: вызов через self-proxy
public void goodCall() {
System.out.println("Вызов через self-proxy");
selfProxy.asyncMethod(); // через прокси — асинхронно
}
}
// Альтернатива: отдельный компонент
@Service
class AsyncWorker {
@Async
public CompletableFuture<String> doWork() {
return CompletableFuture.completedFuture("Работа выполнена");
}
}
@Service
class CallerService {
@Autowired
private AsyncWorker worker;
public void call() {
worker.doWork(); // асинхронно через прокси
}
}
Объяснение: Spring создает прокси-объект, который перехватывает вызовы @Async методов и передает их в пул потоков.
Когда бин внедряет сам себя (selfProxy), он получает именно прокси, а не исходный объект. Вызов через selfProxy.asyncMethod() корректно обрабатывается перехватчиком. Self-injection работает благодаря тому, что Spring после создания бина внедряет его же прокси (если включен режим @EnableAsync и прокси-таргет класс). Для этого требуется либо использовать интерфейсы (JDK proxy), либо CGLIB (proxy-target-class=true).
Альтернативное и более чистое решение — вынести асинхронный метод в отдельный бин, что полностью исключает проблему внутренних вызовов.
Разработчик всегда проверяет, через какой объект вызывается @Async метод, и избегает вызовов через this.
#Java #советы
👍5
Что выведет код?
#Tasks
@SpringBootApplication
@EnableAsync
public class Task130326 implements CommandLineRunner {
@Autowired
private AsyncService130326 service;
public static void main(String[] args) {
SpringApplication.run(Task130326.class, args);
}
@Override
public void run(String... args) {
service.directCall();
service.proxyCall();
}
}
@Component
class AsyncService130326 {
@Lazy
@Autowired
private AsyncService130326 self;
@Async
public void asyncMethod() {
System.out.println("asyncMethod: " + Thread.currentThread().getName());
}
public void directCall() {
System.out.println("directCall: " + Thread.currentThread().getName());
asyncMethod();
}
public void proxyCall() {
System.out.println("proxyCall: " + Thread.currentThread().getName());
self.asyncMethod();
}
}
#Tasks
👍2
Что такое Java Memory Model (JMM)? 🤓
Ответ:
Java Memory Model (JMM) — это формальная модель, описывающая, как потоки взаимодействуют через память и какое поведение можно ожидать в многопоточной среде.
JMM определяет правила, когда изменения, сделанные одним потоком, становятся видимыми для других потоков. Она описывает отношение "happens-before", которое гарантирует видимость и упорядоченность действий. Без JMM компилятор и процессор могли бы переупорядочивать инструкции так, что многопоточный код работал бы непредсказуемо.
Ключевые слова synchronized, volatile, final обеспечивают определенные гарантии видимости в рамках JMM.
#собеседование
Ответ:
JMM определяет правила, когда изменения, сделанные одним потоком, становятся видимыми для других потоков. Она описывает отношение "happens-before", которое гарантирует видимость и упорядоченность действий. Без JMM компилятор и процессор могли бы переупорядочивать инструкции так, что многопоточный код работал бы непредсказуемо.
Ключевые слова synchronized, volatile, final обеспечивают определенные гарантии видимости в рамках JMM.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
История технологий сегодня — 14 марта
ℹ️ Кто родился в этот день
Станислав Алексеевич Кудж (род. 14 марта 1979, Москва, РСФСР, СССР) — российский учёный, специалист в области автоматизированных систем государственного управления, многопрофильных и многофункциональных информационных систем.
🌐 Знаковые события
1956 — американская компания Ampex продемонстрировала первый в мире видеомагнитофон VR-1000.
1994 — релиз Linux версии 1.0.0.
#Biography #Birth_Date #Events #14марта
Станислав Алексеевич Кудж (род. 14 марта 1979, Москва, РСФСР, СССР) — российский учёный, специалист в области автоматизированных систем государственного управления, многопрофильных и многофункциональных информационных систем.
1956 — американская компания Ampex продемонстрировала первый в мире видеомагнитофон VR-1000.
1994 — релиз Linux версии 1.0.0.
#Biography #Birth_Date #Events #14марта
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
С 07.03 по 13.03
Предыдущий пост(с 28.02 по 06.03)
Воскресный мотивационный пост:
Не было мотивации
Запись встреч/видео:
Видео в процессе подготовки...
Обучающие статьи:
Раздел 8. Stream API и функциональный стиль
Глава 5: Контракты. Почему equals, hashCode и иммутабельность — закон
equals/hashCode в операциях distinct, groupingBy, toSet
Иммутабельность данных в потоке — не прихоть, а необходимость
Советы по Java:
[Совет по Java #013]
Тема: Аннотация @Transactional не работает на private и protected методах
[Совет по Java #014]
Тема: Инъекция через конструктор предпочтительнее инъекции в поле
[Совет по Java #015]
Тема: @Async по умолчанию не работает внутри того же класса
Полезные статьи и видео:
Java без розовых очков: какие знания отделяют грейды
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
Предыдущий пост(с 28.02 по 06.03)
Воскресный мотивационный пост:
Не было мотивации
Запись встреч/видео:
Видео в процессе подготовки...
Обучающие статьи:
Раздел 8. Stream API и функциональный стиль
Глава 5: Контракты. Почему equals, hashCode и иммутабельность — закон
equals/hashCode в операциях distinct, groupingBy, toSet
Иммутабельность данных в потоке — не прихоть, а необходимость
Советы по Java:
[Совет по Java #013]
Тема: Аннотация @Transactional не работает на private и protected методах
[Совет по Java #014]
Тема: Инъекция через конструктор предпочтительнее инъекции в поле
[Совет по Java #015]
Тема: @Async по умолчанию не работает внутри того же класса
Полезные статьи и видео:
Java без розовых очков: какие знания отделяют грейды
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
👍2
История технологий сегодня — 15 марта
ℹ️ Кто родился в этот день
Жоре́с Ива́нович Алфёров (бел. Жарэс Іванавіч Алфёраў; 15 марта 1930, Витебск — 1 марта 2019, Санкт-Петербург) — советский и российский учёный-физик. Политический деятель. Лауреат Нобелевской премии по физике (2000 год, за разработку полупроводниковых гетероструктур и создание быстрых опто- и микроэлектронных компонентов).
🌐 Знаковые события
1892 — американский изобретатель Джесс Рено (англ. Jesse Reno) запатентовал первый эскалатор.
1985 — зарегистрирован первый домен в зоне .com
#Biography #Birth_Date #Events #15марта
Жоре́с Ива́нович Алфёров (бел. Жарэс Іванавіч Алфёраў; 15 марта 1930, Витебск — 1 марта 2019, Санкт-Петербург) — советский и российский учёный-физик. Политический деятель. Лауреат Нобелевской премии по физике (2000 год, за разработку полупроводниковых гетероструктур и создание быстрых опто- и микроэлектронных компонентов).
1892 — американский изобретатель Джесс Рено (англ. Jesse Reno) запатентовал первый эскалатор.
1985 — зарегистрирован первый домен в зоне .com
#Biography #Birth_Date #Events #15марта
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6