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
import java.util.*;

public class ImmutableCollections {

public static void main(String[] args) {
//Антипаттерн: попытка модифицировать иммутабельные коллекции

// Collections.emptyList()
List<String> empty = Collections.emptyList();
try {
empty.add("item"); // UnsupportedOperationException
} catch (UnsupportedOperationException e) {
System.out.println("Cannot add to emptyList: " + e);
}

// List.of() (Java 9+)
List<String> of = List.of("A", "B", "C");
try {
of.add("D"); // UnsupportedOperationException
} catch (UnsupportedOperationException e) {
System.out.println("Cannot add to List.of: " + e);
}

try {
of.set(0, "Z"); // Тоже исключение! Даже замена элемента запрещена
} catch (UnsupportedOperationException e) {
System.out.println("Cannot set in List.of: " + e);
}

// Collections.singletonList()
List<String> singleton = Collections.singletonList("only");
try {
singleton.add("second"); // UnsupportedOperationException
} catch (UnsupportedOperationException e) {
System.out.println("Cannot add to singletonList: " + e);
}

//Правильное использование: read-only операции
List<String> readOnly = List.of("Red", "Green", "Blue");
for (String color : readOnly) {
System.out.print(color + " ");
}
System.out.println();
String first = readOnly.get(0);
boolean contains = readOnly.contains("Green");

//Решение 1: создание изменяемой копии
List<String> mutable = new ArrayList<>(readOnly);
mutable.add("Yellow");
mutable.set(0, "Cyan");
System.out.println("Mutable copy: " + mutable);

//Решение 2: создание изменяемой пустой коллекции
List<String> mutableEmpty = new ArrayList<>();
mutableEmpty.add("item"); // Работает

//Решение 3: защитное копирование в API
public static List<String> getInternalList() {
// Возвращаем иммутабельный список, чтобы защитить внутреннее состояние
return List.of("internal1", "internal2");
}

// Получатель, который хочет модифицировать:
List<String> fromApi = getInternalList();
List<String> myWorkingCopy = new ArrayList<>(fromApi);
myWorkingCopy.add("myItem");

// Различия между видами иммутабельных списков
List<String> oldStyleEmpty = Collections.emptyList(); // Пустой, иммутабельный
List<String> newStyleEmpty = List.of(); // То же самое, но короче

List<String> oldStyleSingle = Collections.singletonList("one");
List<String> newStyleSingle = List.of("one");

// List.of() не допускает null
try {
List.of("a", null, "b"); // NullPointerException
} catch (NullPointerException e) {
System.out.println("List.of() rejects nulls");
}

// Collections.emptyList() допускает null? Нет, при добавлении, но сам список может содержать null?
// Сам список пуст, но методы типа contains(null) работают без исключения
System.out.println("emptyList contains null: " + Collections.emptyList().contains(null)); // false
}
}


Объяснение: Иммутабельные коллекции (не путать с неизменяемыми обертками Collections.unmodifiableList()) спроектированы для максимальной производительности и безопасности памяти.

List.of() возвращает специализированные компактные реализации: для 0-2 элементов используются поля без массива, для большего количества — массив, но всегда без поддержки модификаций.

Все методы, изменяющие коллекцию, наследуются от AbstractList (в случае emptyList) или явно переопределены на выбрасывание исключения.


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

import java.util.*;

public class Task050526 {
public static void main(String[] args) {
List<String> list1 = Collections.emptyList();
List<String> list2 = List.of();
List<String> list3 = new ArrayList<>(List.of("a", "b"));
List<String> list4 = list3.subList(0, 2);

list1.add("x");
list2.add("x");
list3.add("x");
list4.add("x");

System.out.println("Done");
}
}


#Tasks
👍4
Что такое Random класс? 🤓

Ответ:

java.util.Random
— это класс для генерации псевдослучайных чисел с более гибкими возможностями, чем Math.random().

Позволяет создавать экземпляры с заданным seed'ом (при одинаковом seed последовательность будет одинаковой).

Основные методы: nextInt() (любое целое), nextInt(int bound) (от 0 до bound-1), nextLong(), nextDouble(), nextBoolean(), nextBytes().

Для многопоточных сценариев есть потокобезопасный ThreadLocalRandom.


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

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

Рольф Максимилиан Зиверт ( швед. [ˈrɔlf maksɪˈmǐːlɪan ˈsǐːvɛʈ] ; 6 мая 1896 — 3 октября 1966)шведский медицинский физик, основной вклад которого был в изучение биологических эффектов ионизирующего излучения. Зиверт (Zv), единица СИ, представляющая собой стохастический риск для здоровья, связанный с ионизирующим излучением, названа в его честь. Его называют «отцом радиационной защиты».

Андре Вейль ( / v eɪ / ;французский: [ɑ̃dʁe vɛj] ; 6 мая 1906 — 6 августа 1998)французский математик, известный своими основополагающими работами в области теории чисел и алгебраической геометрии. Он был одним из самых влиятельных математиков двадцатого века. Его влияние обусловлено как его оригинальным вкладом в удивительно широкий спектр математических теорий, так и следом, который он оставил в математической практике и стиле, как через некоторые из своих собственных работ, так и через группу Бурбаки, одним из главных основателей которой он был.


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

1949 – EDSAC, первый практический электронный цифровой компьютер с хранимой программой, совершает свою первую операцию.

1998 – Стив Джобс из Apple Inc. представляет первый iMac.

2002 – Основание SpaceX .


#Biography #Birth_Date #Events #06мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Раздел 9. Исключения, логирование, отладка

Глава 2. Логирование (Logging)

Почему System.out.println — антипаттерн для production-приложений


System.out.println — это комбинация трех элементов стандартной библиотеки Java: статического поля out класса java.lang.System, экземпляра java.io.PrintStream, и метода println этого экземпляра. Разберем каждый компонент.
Класс System содержит три статических поля для стандартных потоков ввода-вывода: in типа InputStream, out и err типа PrintStream. Поле out инициализируется JVM при старте виртуальной машины и представляет собой поток вывода, обычно связанный с консолью терминала или процесса-родителя. Поле err аналогично, но предназначено для вывода ошибок и обычно направлено в тот же физический поток, что и out, хотя может быть перенаправлено операционной системой отдельно.

PrintStream — это класс-обертка над байтовым потоком OutputStream, добавляющий удобные методы для вывода примитивных типов, строк и объектов. Ключевая особенность: PrintStream никогда не выбрасывает IOException. Вместо этого он устанавливает внутренний флаг ошибки trouble, который можно проверить методом checkError(). Это магическое подавление исключений делает System.out.println непригодным для сценариев, где критична надежность доставки сообщения — например, при записи в файл логов, где переполнение диска должно быть явно обнаружено и обработано.


Как работает под капотом

Инициализация потока

При старте JVM вызывается нативный метод initializeSystemClass(), который создает файловые дескрипторы для стандартных потоков через java.io.FileDescriptor. Для System.out создается FileOutputStream, обернутый в BufferedOutputStream, затем в PrintStream. Эта цепочка оберток обеспечивает буферизацию вывода и удобный API.
// Упрощенный псевдокод инициализации из OpenJDK
FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
BufferedOutputStream bufOut = new BufferedOutputStream(fdOut, 128);
System.out = new PrintStream(bufOut, true, charset); // autoFlush = true


Параметр autoFlush = true означает, что PrintStream будет принудительно сбрасывать буфер после каждого вызова println, printf или format, а также при записи массива байт. Это гарантирует немедленный вывод, но создает значительные накладные расходы на синхронизацию и системные вызовы.

Механика println

Метод println(String x) выполняет следующую последовательность:
Блокировка потока через synchronized(this) — PrintStream синхронизирован, что обеспечивает потокобезопасность, но создает contention при высокой конкуренции.
Вызов print(x), который преобразует строку в байты с использованием кодировки платформы по умолчанию (обычно UTF-8).
Запись байт в underlying BufferedOutputStream.
Вызов newLine() для записи разделителя строки, зависящего от платформы (\n для Unix, \r\n для Windows).
Если autoFlush включен, принудительный сброс буфера через flush().
Каждый вызов println порождает минимум один системный вызов write на уровне ОС после сброса буфера. При тысячах запросов в секунду это становится узким местом.


#Java #для_новичков #beginner #logging #System_out_println
👍2🔥2
Кодировка и платформенная зависимость

PrintStream использует кодировку, определенную при создании. Для System.out JVM выбирает кодировку на основе системных свойств, переменных окружения или параметров запуска. Это создает платформенную зависимость: один и тот же символ может быть закодирован по-разному на Windows и Linux, что приводит к искажению логов при агрегации из разных источников. Профессиональные логгеры явно указывают UTF-8 и гарантируют консистентность кодировки независимо от платформы.


Проблема отсутствия уровней логирования

System.out.println выводит всё в одном потоке без разделения по важности. В production-системе разработчикам нужно различать рутинную информацию, детальную отладку, предупреждения и критические ошибки. Без уровней невозможно отфильтровать шум: при включении отладочного вывода консоль заполняется мегабайтами данных, среди которых теряются реальные проблемы.

Профессиональные фреймворки логирования предоставляют иерархию уровней — TRACE, DEBUG, INFO, WARN, ERROR — каждый из которых включает себя и все последующие. Это позволяет в development выводить DEBUG, в staging — INFO, а в production — только WARN и выше, без модификации кода. Конфигурация уровней выполняется внешним файлом, что позволяет оперативно изменять детализацию без перекомпиляции или перезапуска приложения.
С System.out.println единственный способ "отключить" отладку — удалить или закомментировать строки. Это нарушает принцип единственной ответственности: код смешивает бизнес-логику и управление выводом. При необходимости временно включить отладку для диагностики проблемы в production требуется redeploy, что недопустимо для высокодоступных систем.


Невозможность отключения вывода и накладные расходы

Каждый вызов System.out.println неизбежно выполняется. Даже если вывод перенаправлен в /dev/null, форматирование строки происходит в памяти JVM. Конкатенация строк через оператор + создает промежуточные объекты StringBuilder и String, нагружая garbage collector.
// Эта строка форматируется всегда, даже если вывод не нужен
System.out.println("User " + userId + " performed " + operation + " at " + Instant.now());


При отключенном логировании профессиональные фреймворки полностью исключают накладные расходы. SLF4J использует guard-метод logger.isDebugEnabled(), а параметризованные сообщения logger.debug("User {} not found", userId) выполняют подстановку только при активном уровне. Это критично для горячих путей выполнения, где лишние аллокации приводят к stop-the-world паузам сборщика мусора.


Отсутствие структурированного вывода

Вывод System.out.println — плоский текст без метаданных. Production-системы требуют временной метки с миллисекундной точностью, имени потока, имени класса и метода, номера строки, уровня серьезности. Ручное добавление этих полей к каждому вызову создает неподдерживаемый код, где бизнес-логика утопает в шаблонном форматировании.
// Антипаттерн: ручное форматирование метаданных
System.out.println("[" + Thread.currentThread().getName() + "] [" +
LocalDateTime.now() + "] [INFO] [" + getClass().getName() +
"] User " + userId + " not found");


Без структуры логи невозможно эффективно анализировать инструментами агрегации. ELK (Elasticsearch, Logstash, Kibana), Splunk, Grafana Loki ожидают машиночитаемый формат, обычно JSON, с предсказуемыми полями. Плоский текст требует сложного парсинга регулярными выражениями, что медленно, ненадежно и создает технический долг при изменении формата.


#Java #для_новичков #beginner #logging #System_out_println
👍3🔥1
Проблемы с производительностью

System.out направлен в PrintStream, который синхронизирован на уровне экземпляра. Каждый вызов println захватывает монитор объекта, блокируя конкурентные потоки. При высокой нагурке это создает серьезный contention: десятки потоков ожидают освобождения монитора для записи одного сообщения.

Профессиональные логгеры используют асинхронные appenders, которые декопируют поток бизнес-логики от потока записи на диск. Сообщение помещается в lock-free очередь (RingBuffer в Log4j2, LinkedBlockingQueue в Logback), и поток немедленно продолжает выполнение. Отдельный поток-потребитель асинхронно сбрасывает очередь на диск. Это устраняет блокировки и повышает пропускную способность на порядки.
Кроме того, PrintStream с autoFlush = true выполняет системный вызов write после каждого сообщения. Системные вызовы дороги: они требуют переключения контекста из userspace в kernelspace, инвалидации кэшей TLB и ожидания завершения I/O. Буферизованные appenders логгеров накапливают данные и сбрасывают их пачками, минимизируя количество системных вызовов.


Нет маршрутизации и политик хранения

System.out направлен единственным потоком. Невозможно разделить потоки: ошибки в один файл для оперативного мониторинга, бизнес-события в другой для аудита, отладка во временный буфер с ограниченным размером. Нет ротации файлов по размеру или времени — логи растут бесконечно, заполняя диск и приводя к отказу системы.

Профессиональные логгеры предоставляют RollingFileAppender с политиками TimeBasedRollingPolicy и SizeBasedTriggeringPolicy. Файлы автоматически архивируются, сжимаются и удаляются по достижении возраста или общего объема. Это критично для долгоживущих production-систем, где логи за год могут занимать терабайты.
Нет возможности динамической маршрутизации на основе содержимого сообщения. Нельзя направить логи аутентификации в security-мониторинг, а логи производительности в APM-систему. Маркеры (Markers) в SLF4J и фильтры в Logback/Log4j2 решают эту задачу декларативно.


Нет контекста и корреляции

В распределенных системах критична возможность отследить запрос через все компоненты — от API-шлюза до базы данных. Это требует привязки контекстной информации к каждому лог-сообщению: request ID, user ID, session ID, trace ID в распределенной трассировке.

System.out.println не предоставляет механизма для автоматической вставки контекста. Ручное добавление к каждому вызову невозможно в многопоточной среде, где контекст различается между потоками. MDC (Mapped Diagnostic Context) в SLF4J использует ThreadLocal для неявной привязки контекста к потоку выполнения, что позволяет декларативно включать поля контекста в каждое сообщение через шаблон конфигурации.


#Java #для_новичков #beginner #logging #System_out_println
👍6
Что выведет код?

public class Task060526 {
private static String getValue() {
try {
return "try";
} finally {
System.out.print("finally ");
}
}

public static void main(String[] args) {
System.out.print(getValue() + " ");
System.out.println("main");
}
}


#Tasks
👍2
👍2
Что такое BigDecimal? Когда его использовать? 🤓

Ответ:

BigDecimal
— класс для работы с десятичными числами с произвольной точностью.

Используется, когда критична точность вычислений (финансовые расчеты, налоги, валюты). float и double имеют проблемы с точным представлением дробей (например, 0.1 + 0.2).

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

Минус: медленнее примитивов. Создавать через строки: new BigDecimal("0.1"), а не new BigDecimal(0.1).


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

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

Па́вел Серге́евич Алекса́ндров (25 апреля [7 мая] 1896, Богородск — 16 ноября 1982, Москва) — советский математик, академик АН СССР (1953, член-корреспондент с 1929) и АПН РСФСР/СССР (1945). Профессор МГУ (1929). Основные труды по топологии, теории множеств, теории функций вещественного переменного, геометрии, вариационному исчислению, математической логике, основаниям математики.

Эдвин Герберт Лэнд (англ. Edwin Herbert Land; 7 мая 1909, Бриджпорт, штат Коннектикут — 1 марта 1991, Кембридж, штат Массачусетс) — американский учёный-оптик и изобретатель, основатель корпорации Polaroid. Он стал первым, кто использовал принципы поляризации во многих потребительских товарах и изобрёл одноступенный фотопроцесс. По количеству полученных патентов на изобретения — 535 — уступал только Томасу Эдисону.


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

1895 — в Петербурге русский физик и электротехник Александр Попов продемонстрировал свой «Прибор для обнаружения и регистрирования электрических колебаний».

1997 — компания Intel официально представила микропроцессор Pentium II.

2003 — первое в XXI веке для земного наблюдателя прохождение Меркурия по диску Солнца, доступное для наблюдателей большей части Африки и Евразии.


#Biography #Birth_Date #Events #07мая
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍2
[Совет по Java #034]

Тема: Ленивая инициализация синглтона через double-checked locking требует volatile.

Проблема: Паттерн double-checked locking (DCL) предназначен для ленивой инициализации синглтона с минимальной синхронизацией.

Классическая реализация без volatile содержит скрытую гонку данных из-за переупорядочивания инструкций (instruction reordering). Процесс создания объекта включает три этапа: выделение памяти, инициализация полей, присвоение ссылки переменной.

Компилятор и процессор могут переставить инициализацию и запись ссылки. В результате один поток может увидеть ненулевой, но еще не проинициализированный объект (partially constructed object), что приведет к непредсказуемому поведению, NullPointerException или чтению значений по умолчанию вместо заданных конструктором. Без volatile JVM не гарантирует happens-before связи между записью и последующим чтением.

Решение: Объявите поле синглтона как private static volatile. Модификатор volatile запрещает переупорядочивание операций с этим полем, обеспечивая, что запись ссылки произойдет только после полной инициализации объекта.

Начиная с Java 5 (и нового memory model), volatile обеспечивает правильный DCL.

Альтернативы: инициализация при загрузке класса (eager initialization) или использование enum-синглтона. Для современных проектов предпочтительнее подход с внутренним статическим классом (Initialization-on-demand holder idiom), который не требует ручной синхронизации.

public class Singleton {

//Антипаттерн: double-checked locking без volatile
private static Singleton instance; // отсутствует volatile!

public static Singleton getInstanceBad() {
if (instance == null) { // Первая проверка
synchronized (Singleton.class) {
if (instance == null) { // Вторая проверка
instance = new Singleton(); // Может быть переупорядочено!
}
}
}
return instance;
}

//Решение: volatile гарантирует корректность
private static volatile Singleton instance;

public static Singleton getInstanceGood() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(); // Теперь безопасно
}
}
}
return instance;
}

//Лучшее решение без синхронизации: Initialization-on-demand holder
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}

public static Singleton getInstanceHolder() {
return Holder.INSTANCE; // Инициализация при первом обращении
}

//enum-синглтон (сериализация безопасна)
public enum EnumSingleton {
INSTANCE;
public void doSomething() { }
}

private Singleton() { }
}


Объяснение: Проблема DCL без volatile связана с тем, что запись ссылки instance = new Singleton() неатомарна.

Без volatile возможен следующий сценарий: поток A выполняет выделение памяти, записывает ссылку в instance, но инициализация конструктора еще не завершена. Поток B входит в метод, видит instance != null и возвращает недосозданный объект. volatile создает барьер памяти (memory barrier), который запрещает переупорядочивание и гарантирует, что все записи до момента присвоения будут видны всем потокам после.

В Java 5+ спецификация memory model была усилена, и DCL с volatile работает корректно. Однако идиома holder-класса предпочтительнее: она использует механизм потокобезопасной инициализации классов JVM, не требует явной синхронизации и короче.


#Java #советы
👍6
Немаленькое обновление devforge.ru

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

Погнали тестить 💃
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Что выведет код?

public class Task070926 {
static int a = getB();
static int b = 5;
static int getB() { return b; }

public static void main(String[] args) {
System.out.println("a=" + a + ", b=" + b);
}
}


#Tasks
👍4
👍4
Что такое WeakHashMap? Где применяется? 🤓

Ответ:

WeakHashMap
— это реализация Map, в которой ключи хранятся через слабые ссылки (WeakReference).

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

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


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

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

Кэйдзи Инафунэ (яп. 稲船 敬二 Инафунэ Кэйдзи, 8 мая 1965, Кисивада, Япония)японский игровой художник и продюсер компании Capcom, наиболее известный по созданию дизайна персонажей серии Mega Man, а также продюсированию игр Onimusha и Dead Rising.


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

1886 — Впервые производится Coca-cola — напиток, созданный доктором Джоном Пембертоном.


#Biography #Birth_Date #Events #08мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4