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
История технологий сегодня — 1 апреля

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

Не нашел...(


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

1940 — в Нью-Джерси впервые демонстрируется электронный микроскоп.

1960 — запущен спутник TIROS-1, впервые обеспечивший телевещание из космоса.

1972 — компания Intel представила микропроцессор 8008.

1976 — Стив Джобс, Стив Возняк и Рональд Уэйн основывают Apple Computer Company.

2004 — открылась почта Gmail от Google.


#Biography #Birth_Date #Events #01апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
[Совет по Java #021]

Тема: Использование intern() в (String.intern()) для уникальных строк может забить PermGen/Metaspace и вызвать утечку памяти.

Проблема: Метод String.intern() помещает строку в пул, управляемый JVM, и возвращает канонический экземпляр.

В ранних версиях Java пул находился в PermGen (Permanent Generation) — области памяти фиксированного размера (обычно 64-96 МБ). При интенсивном интернировании уникальных строк (например, полученных из внешних источников или сгенерированных динамически) пул быстро переполняется, вызывая OutOfMemoryError: PermGen space.

Начиная с Java 8, PermGen заменен на Metaspace (неограниченный по умолчанию, но ограниченный физической памятью). Однако проблема остается: интернированные строки никогда не собираются сборщиком мусора, если на них есть ссылки из пула. Даже после того, как исходная строка становится недоступной, интернированный экземпляр продолжает жить в пуле, что приводит к утечке памяти. Кроме того, операция intern() синхронизирована и в высококонкурентной среде становится узким местом.

Решение: Не используйте intern() для дедупликации строк, особенно если строки уникальны или их количество велико.

Для кэширования повторяющихся строк применяйте ConcurrentHashMap<String, String> или ConcurrentHashMap<String, WeakReference<String>> с возможностью ручного контроля размера.

Альтернатива — использовать String как есть, полагаясь на то, что JVM сама оптимизирует хранение литералов и констант. Для ограниченных наборов (например, коды ошибок, статусы) используйте enum. Если интернирование необходимо для экономии памяти при огромном количестве дубликатов, настройте размер StringTable через -XX:StringTableSize=N и используйте intern() только для строк с высокой степенью повторяемости.

import java.util.concurrent.ConcurrentHashMap;

public class StringInternRisk {

//Антипаттерн: интернирование всех строк
public static String dangerousIntern(String value) {
return value.intern(); // Попадает в Metaspace, никогда не освободится
}

//Решение: ручной пул с контролем
private static final ConcurrentHashMap<String, String> STRING_POOL = new ConcurrentHashMap<>();

public static String safeDeduplicate(String value) {
// putIfAbsent атомарно добавляет, если отсутствует
String existing = STRING_POOL.putIfAbsent(value, value);
return existing != null ? existing : value;
}

// Вариант с автоматической очисткой через WeakReference
private static final ConcurrentHashMap<String, WeakReference<String>> WEAK_POOL = new ConcurrentHashMap<>();

// Для ограниченных наборов — enum
public enum Status {
NEW, PROCESSING, COMPLETED;
// вместо "NEW".intern() используйте Status.NEW.name()
}

public static void main(String[] args) {
String s1 = new String("Hello");
String s2 = new String("Hello");

// Рискованно
String interned = s1.intern();
System.out.println(s1 == s2); // false
System.out.println(s1 == interned); // true (попал в пул)

// Безопасная альтернатива
String dedup = safeDeduplicate(s2);
System.out.println(s1 == dedup); // false, но equals true — корректно

// Демонстрация утечки: цикл с уникальными строками быстро заполнит Metaspace
for (int i = 0; i < 1_000_000; i++) {
String unique = Integer.toString(i);
// unique.intern(); // Раскомментировать — опасно, приведет к OOM
}
}
}


Объяснение: Пул строк — это хэш-таблица (StringTable) фиксированного размера.

При интернировании строка добавляется в эту таблицу, и сборщик мусора не удаляет ее, даже если исходный объект больше не используется.

В Java 8+ Metaspace может расти до предела физической памяти, но при интенсивном интернировании уникальных строк рост становится бесконтрольным, и приложение падает с OutOfMemoryError: Metaspace.


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

import java.util.ArrayList;
import java.util.List;

public class Task010426 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();

for (int i = 0; i < 10_000; i++) {
String s = new String("data_" + i);
String interned = s.intern();
list.add(interned);
}

String a = new String("data_5000");
String b = a.intern();

System.out.println(a == b);
System.out.println(a == list.get(5000));
System.out.println(b == list.get(5000));
}
}


#Tasks
👍1
👍2
Что такое анонимные классы (Anonymous classes)? 🤓

Ответ:

Анонимные классы
— это локальные внутренние классы без имени, которые объявляются и инстанцируются одновременно в одном выражении.

Они используются, когда нужен одноразовый объект с небольшими изменениями, чаще всего для реализации интерфейсов или расширения классов (например, Runnable, компараторы, обработчики событий).

Синтаксис: new Interface() { ... } или new Class() { ... }.

Анонимные классы имеют доступ к final или effectively final переменным окружающего контекста.



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

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

Уо́лтер Пе́рси Кра́йслер (англ. Walter Percy Chrysler; 2 апреля 1875, Уомего, Канзас — 18 августа 1940, Кингс-Пойнт, Нью-Йорк) — американский автомобилестроитель, промышленник, основатель корпорации Chrysler.


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

1966 — советский спутник «Луна-10» стал первым в мире космическим аппаратом, облетевшим Луну.


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

Глава 8: За пределами коллекций. Бесконечность и I/O

Бесконечные стримы и ленивая генерация

Ранее Stream API рассматривался как инструмент обработки конечных коллекций данных. Но фундаментальная мощь потоков — в их способности моделировать бесконечные последовательности, вычисляемые по требованию. Это сдвигает фокус с "данных в памяти" к "процессу генерации", открывая паттерны для числовых последовательностей, генераторов уникальных идентификаторов, обработки потоковых источников вроде сетевых соединений.


Stream.iterate: рекурсия с состоянием

Метод Stream.iterate создаёт поток, где каждый следующий элемент вычисляется из предыдущего.

Перегрузка Java 8 принимает начальное значение и унарную функцию:
// Натуральные числа: 0, 1, 2, 3...
Stream<Integer> natural = Stream.iterate(0, n -> n + 1);

// Степени двойки: 1, 2, 4, 8...
Stream<Integer> powersOfTwo = Stream.iterate(1, n -> n * 2);

// Фибоначчи: пара (a, b) -> (b, a+b)
Stream<long[]> fibonacci = Stream.iterate(
new long[]{0, 1},
f -> new long[]{f[1], f[0] + f[1]}
);


Ключевая особенность: iterate сохраняет состояние между элементами. Это делает его непараллелизуемым — каждый элемент зависит от предыдущего, разделение невозможно. Попытка вызвать .parallel() на таком потоке не даст выигрыша, а может замедлить из-за накладных расходов.


Java 9+: iterate с предикатом остановки

Перегрузка с тремя параметрами добавляет условие продолжения:
// Числа от 0 до 99
Stream<Integer> limited = Stream.iterate(
0, // seed
n -> n < 100, // hasNext (предикат продолжения)
n -> n + 1 // next (функция следующего)
);


Это заменяет паттерн iterate(...).limit(n) более семантически ясным конструктом. Предикат проверяется перед генерацией каждого элемента, включая seed. Если hasNext(seed) ложно, поток пуст.


Stream.generate: чистая генерация без состояния

Stream.generate принимает Supplier — функцию без аргументов, возвращающую значение. Каждый вызов независим, что теоретически позволяет параллелизм (хотя реализация в OpenJDK не делит такие потоки эффективно).
// Постоянное значение
Stream<String> constants = Stream.generate(() -> "repeat");

// Случайные числа
Stream<Double> randoms = Stream.generate(Math::random);

// Уникальные ID через атомарный счётчик
AtomicLong idGenerator = new AtomicLong(0);
Stream<String> uniqueIds = Stream.generate(() -> "ID-" + idGenerator.incrementAndGet());


generate идеален для стохастических или внешне определяемых последовательностей, где нет рекуррентной зависимости. Но бесконечность требует ограничения: limit, takeWhile или короткое замыкание терминальной операцией.


takeWhile и dropWhile: предикатные границы

Java 9 добавила методы takeWhile и dropWhile, критически отличные от filter по семантике:
filter проверяет каждый элемент независимо, пропуская или отбрасывая по условию
takeWhile пропускает элементы, пока предикат истинен, и останавливает поток при первом ложном
dropWhile отбрасывает элементы, пока предикат истинен, и продолжает с первого ложного

// Сортированный поток температур
IntStream temperatures = IntStream.of(15, 18, 22, 25, 19, 12, 8);

// takeWhile: температура ниже 25
temperatures.takeWhile(t -> t < 25)
.forEach(System.out::println); // 15, 18, 22 — остановка на 25

// dropWhile: пропускаем прохладную погоду
temperatures.dropWhile(t -> t < 20)
.forEach(System.out::println); // 22, 25, 19, 12, 8


Ключевое отличие takeWhile от filter — short-circuit поведение. filter(t -> t < 25) обработал бы все элементы, включая 19, 12, 8. takeWhile останавливается, предполагая, что последовательность упорядочена и дальнейшие элементы не интересны.

Это критично для бесконечных потоков:
// Бесконечная последовательность, ограниченная условием
Stream.iterate(1, n -> n * 2)
.takeWhile(n -> n < 1000) // 1, 2, 4, 8, ..., 512 — остановка
.forEach(System.out::println);


Без takeWhile пришлось бы использовать limit, требующий знания количества элементов заранее, или filter, не останавливающийся.


#Java #для_новичков #beginner #stream_api
👍6
Сценарий: генерация уникальных идентификаторов

Комбинация generate с takeWhile или limit создаёт контролируемые генераторы:

// UUID с проверкой уникальности в пределах сессии
Set<String> usedIds = ConcurrentHashMap.newKeySet();
Stream<String> uniqueIds = Stream.generate(UUID::randomUUID)
.map(UUID::toString)
.filter(usedIds::add) // add возвращает false если уже есть, фильтруем дубликаты
.limit(1000); // строго 1000 уникальных

// Или с takeWhile для условной остановки
Stream<String> idsUntilPattern = Stream.generate(this::generateId)
.takeWhile(id -> !id.contains("STOP")); // Генерация до спецпаттерна


Атомарные структуры (AtomicLong, ConcurrentHashMap) обеспечивают потокобезопасность при параллельном доступе, хотя generate в стандартной реализации не эффективно параллелится.


Сценарий: чтение потоковых данных

Бесконечные стримы моделируют внешние источники с неизвестным объёмом:
```
// Симуляция чтения из сокета: байты до терминатора
Stream<Byte> socketStream = Stream.generate(() -> readFromSocket())
.takeWhile(b -> b != -1); // -1 как EOF

// Обработка пакетов до специального маркера
Stream<Packet> packetStream = Stream.generate(this::readNextPacket)
.takeWhile(p -> !p.isTerminator());

Важно: такие потоки требуют управления ресурсами. Stream.generate не знает о необходимости закрыть сокет. Использование в try-with-resources или явное закрытие источника в Supplier — ответственность разработчика.


Практика: числовые последовательности с ленивостью

Сравним подходы к генерации последовательностей:
// Плохо: немедленное создание списка
List<Integer> eager = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
if (isPrime(i)) eager.add(i);
}

// Хорошо: ленивый поток, элементы вычисляются по требованию
IntStream primes = IntStream.iterate(2, n -> n + 1)
.filter(this::isPrime)
.takeWhile(n -> n < 1000000);

// Потребление только первых 10, остальные никогда не вычислены
primes.limit(10).forEach(System.out::println);


Ленивость позволяет работать с "потенциально бесконечными" последовательностями, фактически обрабатывая только необходимый минимум.


Ограничения бесконечных потоков

Параллелизм: iterate не параллелится, generate — плохо. Бесконечные потоки — последовательная абстракция.
Состояние: iterate требует небольшого состояния (предыдущий элемент), но не масштабируется. Сложное состояние в Supplier требует синхронизации.
Ресурсы: бесконечность — концептуальная. Реальные источники (сокеты, файлы) требуют закрытия. Stream API не управляет жизненным циклом внешних ресурсов автоматически.


#Java #для_новичков #beginner #stream_api
👍5
Не знаю как вы, а я рад 🤪😄
Please open Telegram to view this post
VIEW IN TELEGRAM
🤣10
Что выведет код?

import java.util.stream.Stream;

public class Task020426 {
public static void main(String[] args) {
Stream<Integer> stream = Stream.iterate(0, n -> n + 1)
.filter(n -> n % 2 == 0)
.map(n -> {
System.out.print(n + " ");
return n;
})
.limit(3);

stream.forEach(n -> {});
}
}


#Tasks
👍1
👍1
Вот можете изучить условия галер))
Что такое Method Reference (ссылки на методы)? 🤓

Ответ:

Method Reference
— это еще более краткая форма записи лямбда-выражения, когда вы просто вызываете существующий метод.

Синтаксис: ClassName::methodName.

Есть четыре типа:
ссылка на статический метод (Math::max),
ссылка на метод экземпляра конкретного объекта (System.out::println),
ссылка на метод экземпляра произвольного объекта конкретного типа (String::length),
ссылка на конструктор (ArrayList::new). Method Reference делают код еще более читаемым и лаконичным.



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

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

Не нашел((


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

1885 — немецкий изобретатель Готлиб Даймлер получил патент на свой первый двигатель — в половину лошадиной силы.

1973 – Мартин Купер из компании Motorola совершает первый звонок с мобильного телефона, используя портативное устройство, Джоэлу С. Энгелю из Bell Labs.

1981 – На выставке West Coast Computer Faire в Сан-Франциско был представлен Osborne 1, первый успешный портативный компьютер.

2010 – компания Apple Inc. выпустила первое поколение iPad , планшетного компьютера.


#Biography #Birth_Date #Events #03апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
[Совет по Java #022]

Тема: BigDecimal с конструктором от double теряет точность.

Проблема: Конструктор BigDecimal(double) принимает значение double с плавающей точкой, которое уже содержит погрешность из-за двоичного представления десятичных дробей.

Эта погрешность не исчезает при создании BigDecimal — она фиксируется и становится частью его масштаба.
Например, new BigDecimal(0.1) создает объект, равный 0.1000000000000000055511151231257827021181583404541015625, а не 0.1. Это приводит к неожиданным ошибкам при сравнении, сложении и других операциях, полностью нивелируя смысл использования BigDecimal для точных вычислений.
Ошибка коварна тем, что при выводе через System.out.println() может отобразиться округленное значение, создавая иллюзию корректности.

Решение: Используйте один из двух безопасных способов создания BigDecimal:

- BigDecimal.valueOf(double) — статический фабричный метод, который использует Double.toString() для преобразования и гарантирует точное представление десятичного значения.

- Конструктор BigDecimal(String) — самый надежный, но требует явного преобразования числа в строку.

- Никогда не используйте конструктор BigDecimal(double) для значений, которые не являются целыми или не могут быть точно представлены в двоичной системе.

import java.math.BigDecimal;

public class BigDecimalPrecision {

public static void main(String[] args) {
//Антипаттерн: конструктор от double
BigDecimal fromDouble = new BigDecimal(0.1);
System.out.println("new BigDecimal(0.1): " + fromDouble);
// Вывод: 0.1000000000000000055511151231257827021181583404541015625

//Ошибка в сравнении
BigDecimal expected = new BigDecimal("0.1");
System.out.println("Равны? " + fromDouble.equals(expected)); // false!

//Ошибка в арифметике
BigDecimal sum = new BigDecimal(0.1).add(new BigDecimal(0.2));
System.out.println("0.1 + 0.2 = " + sum);
// Вывод: 0.3000000000000000166533453693773481063544750213623046875

//Решение 1: BigDecimal.valueOf(double)
BigDecimal fromValueOf = BigDecimal.valueOf(0.1);
System.out.println("BigDecimal.valueOf(0.1): " + fromValueOf); // 0.1

//Решение 2: конструктор от String
BigDecimal fromString = new BigDecimal("0.1");
System.out.println("new BigDecimal(\"0.1\"): " + fromString); // 0.1

// Проверка равенства
System.out.println("valueOf == string: " + fromValueOf.equals(fromString)); // true

//Безопасная арифметика
BigDecimal safeSum = BigDecimal.valueOf(0.1).add(BigDecimal.valueOf(0.2));
System.out.println("Безопасная сумма: " + safeSum); // 0.3

// Для целых чисел конструктор от double безопасен
BigDecimal intValue = new BigDecimal(10.0);
System.out.println("Целое число: " + intValue); // 10
}
}


Объяснение: Ключевое различие между конструктором и фабричным методом в том, что BigDecimal.valueOf(double) сначала преобразует double в строку с помощью Double.toString(), которая использует алгоритм для получения минимального количества знаков, точно представляющих значение. Это устраняет избыточную погрешность.

Конструктор BigDecimal(String) является самым прозрачным — он парсит десятичную строку напрямую, что идеально для значений, поступающих из пользовательского ввода или API. Для целых чисел (например, 10.0) погрешность отсутствует, но безопаснее использовать BigDecimal.valueOf(10) или BigDecimal.TEN.

Статический анализ кода (SonarQube, SpotBugs) автоматически подсвечивает использование конструктора BigDecimal(double) как критический дефект.


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

import java.math.BigDecimal;

public class Task030426 {
public static void main(String[] args) {
BigDecimal bd1 = new BigDecimal(0.1);
BigDecimal bd2 = BigDecimal.valueOf(0.1);
BigDecimal bd3 = new BigDecimal("0.1");

System.out.println(bd1.equals(bd2));
System.out.println(bd1.equals(bd3));
System.out.println(bd2.equals(bd3));
System.out.println(bd1.compareTo(bd2));
}
}


#Tasks
👍2
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Как создать неизменяемый (immutable) класс? 🤓

Ответ:

Чтобы создать immutable класс, следуйте правилам:

1) Объявите класс как final (чтобы нельзя было наследовать).
2) Все поля сделайте private final.
3) Не предоставляйте сеттеры.
4) Инициализируйте все поля через конструктор, делая глубокие копии для изменяемых объектов (массивы, Date, List).
5) В геттерах для изменяемых полей возвращайте копии, а не оригинальные ссылки (Collections.unmodifiableList(), клонирование массива).

Пример: класс String.



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

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

Карл Вильгельм Сименс (4 апреля 1823 года — 19 ноября 1883 года)немецкий и британский инженер-механик, изобретатель и промышленник. Ему принадлежит ряд изобретений, в том числе регенеративного конденсатора для предварительного нагревания воды, употребляемой в пищу (1850 год), водомера (1851 год), пирометра (1860 год), гидравлического компрессора для уменьшения отката артиллерийских орудий (1867 год) и прочего.


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

1983 — состоялся первый полёт американского космического челнока «Челленджер».

1994 — основана компания
Netscape Communications (называвшаяся в то время «Mosaic Communications Corporation»).


#Biography #Birth_Date #Events #04апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
С 28.03 по 03.04
Предыдущий пост(с 21.03 по 27.03)

Воскресный мотивационный пост:
Не было мотивации, а вообще нужна?) (Признался что только один читает... Напишу ему в личку, наверно)

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

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

Глава 7: Stream API в экосистеме Java. Интеграционные паттерны
Рефакторинг legacy-кода в проекте «Библиотека»

Глава 8: За пределами коллекций. Бесконечность и I/O
Бесконечные стримы и ленивая генерация

[Совет по Java #020]
Тема: HashSet с изменяемыми объектами ломает контракт.

[Совет по Java #021]
Тема: Использование intern() в (String.intern()) для уникальных строк может забить PermGen/Metaspace и вызвать утечку памяти.

[Совет по Java #022]
Тема: BigDecimal с конструктором от double теряет точность.

Полезные статьи и видео:
Хватит винить кривые руки. Твой язык программирования энергетически тебе не подходит

Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
👍2