Java for Beginner
870 subscribers
1.01K photos
275 videos
14 files
1.69K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
История технологий сегодня — 19 марта

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

Фредери́к Жолио́-Кюри́ (фр. Jean Frédéric Joliot-Curie, до брака — Фредерик Жолио; 19 марта 1900, Париж — 14 августа 1958, там же) — французский физик и общественный деятель, лауреат Нобелевской премии по химии (совместно с Ирен Жолио-Кюри, 1935) и, одновременно, инициатор Стокгольмского воззвания, посвящённого безусловному запрету атомного оружия.


🌐 Знаковые события

1964 — руководство фирмы IBM приняло решение о разработке и запуске в производство семейства ЭВМ System/360.

2008 — Запуск в МГУ им. Ломоносова самого мощного в России суперкомпьютера «СКИФ МГУ».


#Biography #Birth_Date #Events #19марта
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
[Совет по Java #017]

Тема: ConcurrentModificationException при итерации и модификации коллекции. Нельзя удалять элементы из ArrayList в цикле for-each. Используйте Iterator.remove() или removeIf().

Проблема: При итерации по коллекции с использованием for-each (синтаксического сахара над Iterator) нельзя напрямую добавлять или удалять элементы.

Коллекция ведет подсчет модификаций (modCount), а итератор проверяет его при каждом next(). Прямой вызов list.remove() изменяет modCount, но не уведомляет итератор — при следующем вызове next() выбрасывается ConcurrentModificationException.

Это защитный механизм, предотвращающий непредсказуемое состояние во время итерации.

Решение: Для безопасного удаления во время итерации используйте собственный Iterator и его метод remove(), который синхронизирует состояние итератора с коллекцией.

Начиная с Java 8, предпочтительнее использовать Collection.removeIf() с лямбда-выражением — это декларативный и более читаемый подход.
public class ConcurrentModificationExample {

public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));

//Антипаттерн: удаление в for-each
try {
for (String item : list) {
if (item.equals("b")) {
list.remove(item); //ConcurrentModificationException!
}
}
} catch (ConcurrentModificationException e) {
System.out.println("Ошибка: " + e);
}

//Явный Iterator.remove()
list = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (item.equals("b")) {
iterator.remove(); // Безопасно
}
}
System.out.println("После iterator.remove(): " + list);

//removeIf()
list = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
list.removeIf(item -> item.equals("b")); // Самый лаконичный способ
System.out.println("После removeIf(): " + list);

//Сбор элементов для удаления
list = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
List<String> toRemove = new ArrayList<>();
for (String item : list) {
if (item.equals("b")) {
toRemove.add(item); //Отмечаем на удаление
}
}
list.removeAll(toRemove); //Удаляем после итерации
System.out.println("После removeAll(): " + list);
}
}


Объяснение: Механизм fail-fast итераторов в Java основан на проверке поля modCount.

При создании итератора он запоминает текущее значение modCount. Каждый раз при вызове next() или remove() итератор проверяет, не изменилось ли modCount коллекции другими способами. Если изменилось — выбрасывается ConcurrentModificationException.

Метод iterator.remove() изменяет коллекцию и одновременно корректирует ожидаемый счетчик итератора. removeIf() использует тот же механизм внутри своей реализации.

#Java #советы
👍5
Что выведет код?

import java.util.*;

public class Task190326 {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));

for (String s : list) {
if (s.equals("C")) {
list.remove(s);
}
System.out.print(s + " ");
}
}
}


#Tasks
👍3
👍2
Какие бывают области видимости бинов (scopes) в Spring? 🤓

Ответ:

В Spring контейнер управляет бинами, и у каждого бина есть свой scope (область видимости).

Основные:
singleton (по умолчанию) — один экземпляр бина на весь IoC-контейнер.
prototype — новый экземпляр создается при каждом запросе бина.

Для веб-приложений:
request — один экземпляр на один HTTP-запрос.
session — один экземпляр на одну HTTP-сессию пользователя.
application — один экземпляр на весь ServletContext.
websocket — один экземпляр на всю WebSocket-сессию.

Выбор scope зависит от потребностей приложения и потокобезопасности бина.


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

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

Серге́й Петро́вич Но́виков (20 марта 1938, Горький — 6 июня 2024, Москва) — советский, российский и американский математик, специалист в области дифференциальной топологии. Академик РАН (с 1981 по 1991 — академик АН СССР), доктор физико-математических наук. Лауреат Филдсовской премии.

Норберт Польманн (родился 20 марта 1960 года) специалист в области информатики и профессор Вестфальской высшей школы. Он также является председателем правления ассоциации по информационной безопасности TeleTrusT.


🌐 Знаковые события

Не нашел(


#Biography #Birth_Date #Events #20марта
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Раздел 8. Stream API и функциональный стиль в Java

Глава 6: Parallel Stream

Условия эффективности параллельного stream

Параллельные потоки ускоряют не всегда. В худшем случае они замедляют выполнение, увеличивают потребление памяти и вносят race conditions. Эффективность зависит от четырёх факторов: характеристик источника, стоимости операции над элементом, чистоты функций и структуры конвейера.


Источник данных: качество разделения

Первый и решающий фактор — способность источника к эффективному разделению. Как обсуждалось ранее, Spliterator.trySplit() определяет, насколько равномерно данные распределятся между воркерами.
Идеальные источники демонстрируют три свойства: точное знание размера (SIZED), поддержка произвольного доступа (RANDOM_ACCESS), быстрое разделение (SUBSIZED).

ArrayList, массивы примитивов, IntStream.range обладают всеми тремя. Их разделение работает за константное время, создавая сбалансированные сегменты.
// ArrayList: O(1) разделение, равномерная нагрузка
List<Book> books = new ArrayList<>(100000);
books.parallelStream() // Эффективен
.map(this::expensiveAnalysis)
.collect(toList());


Приемлемые источники работают хуже, но применимы. HashSet разделяется по бакетам хеш-таблицы. Если распределение хешей равномерное и заполнение высокое, разделение качественное. Но при коллизиях или неравномерном заполнении некоторые сегменты становятся существенно больше других, нарушая балансировку.

Проблемные источники лишены возможности эффективного разделения. LinkedList требует O(n) для поиска середины. Stream.iterate и Stream.generate не делятся вообще — каждый элемент порождается последовательно, и весь поток обрабатывается одним воркером, независимо от вызова parallel().
// LinkedList: разделение O(n), часто деградирует к последовательному
LinkedList<Book> linkedBooks = new LinkedList<>();
linkedBooks.parallelStream() // Нет выигрыша, возможен проигрыш
.map(this::expensiveAnalysis)
.collect(toList());

// Stream.iterate: не делится, parallel бесполезен
Stream.iterate(0, n -> n + 1)
.parallel() // Игнорируется
.limit(1000)
.map(this::expensiveComputation)
.collect(toList());


Источники ввода-вывода (Files.lines, BufferedReader.lines) представляют особый случай. Они не поддерживают разделение, но могут быть обёрнуты в Stream с буферизацией. Параллелизм здесь достигается через промежуточную коллекцию: чтение последовательное, обработка параллельная.


Стоимость операции: порог эффективности

Даже при идеальном источнике параллелизм имеет накладные расходы: создание задач ForkJoinTask, разделение Spliterator, синхронизация при слиянии результатов, кэш-коэрентность между ядрами. Эти затраты должны компенсироваться выигрышем от параллельного выполнения.

Эмпирический порог — порядка 10 микросекунд на элемент. Если операция дешевле, накладные расходы перевешивают выгоду. Если дороже — параллелизм эффективен.
// Слишком дёшево: параллелизм замедлит
List<Integer> doubled = numbers.parallelStream()
.map(n -> n * 2) // Одна инструкция процессора
.collect(toList());

// Достаточно дорого: параллелизм ускорит
List<Result> analyzed = documents.parallelStream()
.map(doc -> nlpPipeline.analyze(doc)) // 50-100 мс на документ
.collect(toList());


Сложность оценки в том, что "стоимость" включает не только CPU-инструкции, но и кэш-промахи, аллокации, вызовы методов. Профилирование (JMH, async-profiler) необходимо для точного определения порога в конкретном контексте.


#Java #для_новичков #beginner #stream_api #ForkJoinPool #parallelStream
👍5
Отсутствие shared mutable state

Параллелизм превращает скрытые баги в явные катастрофы. Код, работающий корректно в последовательном потоке, может давать неверные результаты или зависать при parallel().

Race condition в accumulator:
// Антипаттерн: общий счётчик
AtomicInteger counter = new AtomicInteger(0);

List<Result> results = data.parallelStream()
.map(d -> {
counter.incrementAndGet(); // Потокобезопасен, но не бесплатен
return process(d);
})
.collect(toList());


AtomicInteger обеспечивает корректность, но каждый incrementAndGet() требует атомарной операции и кэш-коэрентности между ядрами. При высоком contention производительность падает ниже последовательной версии.

Непотокобезопасная коллекция в collect:
// Катастрофа: ArrayList не потокобезопасен
List<Result> results = data.parallelStream()
.map(this::process)
.collect(ArrayList::new, List::add, List::addAll); // Race condition!


Стандартный toList() использует Collector с правильным combiner, создающим локальные ArrayList для каждого сегмента и сливающим их в конце. Прямое использование ArrayList::new в collect нарушает этот протокол.

Изменяемые ключи в groupingBy:
// Опасность: изменяемый ключ после группировки
Map<MutableAuthor, List<Book>> byAuthor = books.parallelStream()
.collect(groupingBy(MutableAuthor::new));

// Позже в другом потоке...
byAuthor.keySet().iterator().next().setName("New"); // Непредсказуемое поведение


Параллелизм увеличивает вероятность одновременного доступа к изменяемым структурам. Иммутабельность ключей и элементов становится не рекомендацией, а требованием.


#Java #для_новичков #beginner #stream_api #ForkJoinPool #parallelStream
👍4
Отсутствие барьеров в конвейере

Барьер (synchronization point) — операция, требующая видимости всех элементов или глобальной координации. Барьеры разрушают параллелизм, заставляя воркеров ждать друг друга.

sorted: полный барьер

Операция sorted() требует всех элементов для сортировки. В параллельном потоке каждый сегмент сортируется локально, затем результаты сливаются (merge) в глобально отсортированную последовательность. Слияние требует координации и дополнительной памяти.
// Барьер: локальная сортировка + глобальное слияние
List<Book> sorted = books.parallelStream()
.sorted(comparing(Book::year)) // Накладные расходы на merge
.collect(toList());


Если конвейер содержит sorted без последующих операций, параллелизм может быть оправдан для дорогих предшествующих операций. Но sorted + limit — особенно неэффективная комбинация: все элементы сортируются, хотя нужны только первые N.

limit и findFirst: частичные барьеры

limit(n) в параллельном потоке создаёт глобальный счётчик оставшихся элементов. Когда один воркер достигает лимита, другие должны быть уведомлены для остановки. Это требует синхронизации и снижает эффективность.
findFirst() требует упорядоченности. Если источник ORDERED, воркеры должны координироваться для определения, кто нашёл "первый" элемент.

Если источник неупорядочен или порядок не важен, findAny() предпочтительнее — он возвращает любой найденный элемент без координации.
// Плохо: упорядоченный источник + findFirst в parallel
Optional<Book> first = books.parallelStream()
.filter(b -> b.year() > 2000)
.findFirst(); // Требует проверки всех предшествующих сегментов

// Лучше: findAny для неупорядоченных задач
Optional<Book> any = books.parallelStream()
.filter(b -> b.year() > 2000)
.findAny(); // Первый найденный в любом сегменте


distinct: барьер с состоянием

distinct() в параллельном потоке требует глобального множества уникальных элементов, доступного всем воркерам. Реализация использует ConcurrentHashMap, что добавляет накладные расходы на синхронизацию. Для больших потоков с высокой кардинальностью это может быть медленнее последовательной версии с HashSet.


Когда parallelStream применим

Суммируя критерии, эффективный сценарий для parallelStream:
Источник: ArrayList, массив, IntStream.range с большим размером (10 000+ элементов)
Операция: CPU-bound, дорогая (> 10 мкс), без блокировок
Конвейер: stateless операции, без sorted, limit, distinct или с ними в конце
Данные: иммутабельные, без shared mutable state
Цель: агрегация в коллектор с эффективным combiner
Пример подходящей задачи: анализ миллиона документов, извлечение признаков, подсчёт статистики.
Пример неподходящей задачи: фильтрация списка идентификаторов с простым предикатом, преобразование в строки, лимит первых десяти.


Измерение прежде оптимизации

Предположения о производительности часто ошибочны. Единственный надёжный метод — измерение с репрезентативными данными:
// JMH-бенчмарк для сравнения
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class StreamBenchmark {

@State(Scope.Thread)
public static class Data {
List<Book> books = generateBooks(100000);
}

@Benchmark
public List<Result> sequential(Data d) {
return d.books.stream()
.map(this::expensiveTransform)
.collect(toList());
}

@Benchmark
public List<Result> parallel(Data d) {
return d.books.parallelStream()
.map(this::expensiveTransform)
.collect(toList());
}
}


Микробенчмарки без JMH ненадёжны из-за JIT-оптимизаций, GC-пauses и прогрева кэша. Реальное приложение требует мониторинга в production: метрики latency, throughput, использование CPU, профилирование hot paths.


#Java #для_новичков #beginner #stream_api #ForkJoinPool #parallelStream
👍5
Что выведет код?

import java.util.*;

public class Task200326 {
public static void main(String[] args) {
List<Integer> list1 = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8));
List<Integer> list2 = new LinkedList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8));

long count1 = list1.parallelStream()
.map(x -> {
try { Thread.sleep(10); } catch (InterruptedException e) {}
return x * 2;
})
.count();

long count2 = list2.parallelStream()
.map(x -> {
try { Thread.sleep(10); } catch (InterruptedException e) {}
return x * 2;
})
.count();

System.out.println(count1 == count2);
System.out.println(list1.parallelStream().isParallel());
System.out.println(list2.parallelStream().isParallel());
}
}


#Tasks
👍3
👍2
Что такое инициализационные блоки (initializer blocks)? 🤓

Ответ:

В Java есть два типа блоков инициализации.

Статические блоки (static { ... }) выполняются один раз при загрузке класса, до создания любых объектов, и используются для инициализации статических переменных.

Нестатические (instance) блоки { ... } выполняются при создании каждого нового объекта, перед вызовом конструктора. Они выполняются в порядке объявления. Instance-блоки удобны, когда у класса несколько конструкторов и нужно выполнить общий для всех код.


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

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

Барон (1809) Жан-Бати́ст Жозе́ф Фурье́ (фр. Jean-Baptiste Joseph Fourier; 21 марта 1768, Осер, Франция — 16 мая 1830, Париж) — французский математик и физик. Нашёл формулу представления функции с помощью интеграла, играющую важную роль в современной математике. Доказал, что всякую произвольно начерченную линию, составленную из отрезков дуг разных кривых, можно представить единым аналитическим выражением. В 1823 году независимо от Эрстеда открыл термоэлектрический эффект, показал, что он обладает свойством суперпозиции, создал термоэлектрический элемент.


🌐 Знаковые события

1924 — 24-летний физик Вольфганг Паули в опубликованной статье сформулировал один из важнейших принципов современной теоретической физики, за который в 1945 году получил Нобелевскую премию.

1940 — Учёные Отто Фриш и Рудольф Пайерлс в Бирмингемском университете (Великобритания) сделали оценку критической массы урана-235.


#Biography #Birth_Date #Events #21марта
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
С 14.03 по 20.03
Предыдущий пост(с 07.03 по 13.03)

Воскресный мотивационный пост:
Не было мотивации, а вообще нужна?) (все равно это никто не читает)

Запись встреч/видео:
Видео в процессе подготовки... lvl2

Обучающие статьи:
Раздел 8. Stream API и функциональный стиль

Глава 5: Контракты. Почему equals, hashCode и иммутабельность — закон
(Практика): Саботаж и починка в «Библиотеке»

Глава 6: Parallel Stream
Механика ForkJoinPool.commonPool()
Условия эффективности параллельного stream

[Совет по Java #016]
Тема: Ленивая загрузка в Hibernate (FetchType.LAZY) не работает после закрытия сессии.

[Совет по Java #017]
Тема: ConcurrentModificationException при итерации и модификации коллекции


Полезные статьи и видео:
WebFlux, Virtual Threads и все-все-все

Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
👍4🔥1
🤣4
🤣4
Потратил 6! часов, чтобы собрать настройки ретраев и CircuitBreaker в resilience4j в полноценно работающую демонстрацию...

И все для вас)))🧑‍💻

Скоро будет видео 💃
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍3🍾11
2😱1
История технологий сегодня — 22 марта

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

Ро́берт Э́ндрюс Ми́лликен (англ. Robert Andrews Millikan; 22 марта 1868, Моррисон, Иллинойс, США — 19 декабря 1953, Сан-Марино, Калифорния, США) — американский физик. В 1923 году получил Нобелевскую премию по физике за работы в области фотоэлектрического эффекта и за измерения заряда электрона[4]. Впоследствии он занимался изучением космических лучей.

Бертон Ри́хтер (англ. Burton Richter; 22 марта 1931, Нью-Йорк, США — 18 июля 2018, Станфорд, штат Калифорния, США) американский физик, лауреат Нобелевской премии по физике в 1976 году, совместно с Самюэлем Тингом «за основополагающий вклад в работу по открытию тяжёлой элементарной частицы нового типа».


🌐 Знаковые события

1895 — в Париже состоялась первая в истории публичная демонстрация кинофильма. Это был фильм братьев Люмьер «Выход рабочих с фабрики».

1902 — Британия и Персия заключили договор о соединении телеграфной линией Европы и Индии.


1904 — в лондонской газете «Иллюстрейтед Миррор» впервые в мире опубликована цветная фотография.


#Biography #Birth_Date #Events #22марта
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4