Вот это и случилось))) Ютуб канал перегнал по популярности телеграмм-канал.
Что думаете? Помоему закономерно, хотя труда вложенного в телеге гораздо больше....
Хотя если оглянуться то и 70 видео сами себя не записали...
😎
Что думаете? Помоему закономерно, хотя труда вложенного в телеге гораздо больше....
Хотя если оглянуться то и 70 видео сами себя не записали...
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11🍾2
Что такое 🤓
Ответ:
OutOfMemoryError выбрасывается, когда JVM не может выделить память для нового объекта.
Виды:
1) Java heap space — кончилась память в куче (heap).
2) Metaspace / PermGen — кончилась память для метаданных классов.
3) GC overhead limit exceeded — GC слишком много работает (более 98% времени) и освобождает мало.
4) Unable to create new native thread — невозможно создать новый поток (мало памяти ОС).
5) Requested array size exceeds VM limit — массив больше допустимого.
Причины и решения разные: увеличение heap, утечки памяти, настройка GC.
#собеседование
OutOfMemoryError? Какие бывают виды? Ответ:
OutOfMemoryError выбрасывается, когда JVM не может выделить память для нового объекта.
Виды:
1) Java heap space — кончилась память в куче (heap).
2) Metaspace / PermGen — кончилась память для метаданных классов.
3) GC overhead limit exceeded — GC слишком много работает (более 98% времени) и освобождает мало.
4) Unable to create new native thread — невозможно создать новый поток (мало памяти ОС).
5) Requested array size exceeds VM limit — массив больше допустимого.
Причины и решения разные: увеличение heap, утечки памяти, настройка GC.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологии сегодня — 17 июня
ℹ️ Кто родился в этот день
Сергей Олимпиевич Максимович (5 [17] июня 1876, Санкт-Петербург — 27 декабря 1941, Ленинград) — русский и советский учёный и изобретатель, один из пионеров в области цветной фотографии и цветной кинематографии. Открыватель эффекта Максимовича — Калье (1907).
🌐 Знаковые события
1970 — Эдвин Лэнд запатентовал камеру Polaroid.
1988 — Microsoft выпустила операционную систему «MS DOS 4.0».
#Biography #Birth_Date #Events #17июня
Сергей Олимпиевич Максимович (5 [17] июня 1876, Санкт-Петербург — 27 декабря 1941, Ленинград) — русский и советский учёный и изобретатель, один из пионеров в области цветной фотографии и цветной кинематографии. Открыватель эффекта Максимовича — Калье (1907).
1970 — Эдвин Лэнд запатентовал камеру Polaroid.
1988 — Microsoft выпустила операционную систему «MS DOS 4.0».
#Biography #Birth_Date #Events #17июня
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Раздел 11. Работа с файлами, I/O и сетью (NIO.2)
Глава 1. Классический Java I/O (java.io)
Символьные потоки: Reader и Writer. Unicode, кодировки и путь данных в памяти
Байтовые потоки (
Символьные потоки (
Unicode — стандарт кодирования символов, охватывающий большинство письменных систем мира. Java приняла Unicode с самого начала: тип
Архитектура Reader и Writer
Ключевое отличие от байтовых потоков: методы
Кодировки: мост между байтами и символами
Символьные потоки не существуют в вакууме. Файлы, сетевые соединения, базы данных хранят и передают байты. Преобразование между байтами и символами выполняется через кодировку (charset) — таблицу соответствия последовательностей байт кодовым точкам Unicode.
UTF-8: доминирующая кодировка
UTF-8 — переменная длина кодирования Unicode:
U+0000..U+007F: 1 байт (ASCII-совместимость)
U+0080..U+07FF: 2 байта
U+0800..U+FFFF: 3 байта (большинство BMP-символов)
U+10000..U+10FFFF: 4 байта (суррогатные пары)
Преимущества UTF-8: ASCII-совместимость, компактность для латинских текстов, самосинхронизация (можно определить границу символа в произвольной позиции). Недостаток: переменная длина усложняет индексацию по символам —
UTF-16: внутреннее представление Java
Java использует UTF-16 для внутреннего представления
Это критично для символьных потоков:
Путь данных в памяти: от байтов файла до char[] в heap
Чтение текстового файла: FileReader
Путь данных при чтении:
Декодирование и память
Буферы
#Java #для_новичков #beginner #IO #NIO #Reader #Writer
Глава 1. Классический Java I/O (java.io)
Символьные потоки: Reader и Writer. Unicode, кодировки и путь данных в памяти
Байтовые потоки (
InputStream/OutputStream) оперируют единицей данных в 8 бит — байтом. Они не интерпретируют содержимое: байт 0x41 может быть буквой 'A' в ASCII, частью многобайтовой последовательности UTF-8, или элементом бинарного протокола. Символьные потоки (
Reader/Writer) оперируют единицей в 16 бит — char Java, который представляет кодовую точку Unicode в диапазоне U+0000..U+FFFF. Это различие коренным образом меняет архитектуру, семантику и путь данных через память JVM.Unicode — стандарт кодирования символов, охватывающий большинство письменных систем мира. Java приняла Unicode с самого начала: тип
char — беззнаковое 16-битное целое, String — неизменяемая последовательность char. Однако Unicode эволюционировал: первоначальная спецификация Unicode 1.0 предполагала 16-битное пространство (65 536 символов), но оказалось недостаточным. Unicode 2.0 ввел дополнительные плоскости за пределами Basic Multilingual Plane (BMP), и для их представления потребовались суррогатные пары — две 16-битные char, кодирующие одну кодовую точку в диапазоне U+10000..U+10FFFF. Это означает, что один "символ" в человеческом понимании может занимать один или два char в Java.Архитектура Reader и Writer
Reader — абстрактный класс для чтения символов. Его методы зеркалируют InputStream, но работают с char вместо byte:public abstract class Reader implements Readable, Closeable {
// Чтение одного символа (char как int для EOF-различения)
public int read() throws IOException
// Чтение в массив char[]
public int read(char[] cbuf) throws IOException
// Чтение в массив с офсетом
public abstract int read(char[] cbuf, int off, int len) throws IOException
// Пропуск символов
public long skip(long n) throws IOException
// Готовность к чтению без блокировки
public boolean ready() throws IOException
// Поддержка mark/reset
public boolean markSupported()
public void mark(int readAheadLimit) throws IOException
public void reset() throws IOException
// Закрытие
public abstract void close() throws IOException
}
Writer — абстрактный класс для записи символов:public abstract class Writer implements Appendable, Closeable, Flushable {
// Запись одного символа
public void write(int c) throws IOException
// Запись массива char[]
public void write(char[] cbuf) throws IOException
// Запись части массива
public abstract void write(char[] cbuf, int off, int len) throws IOException
// Запись строки
public void write(String str) throws IOException
// Запись части строки
public void write(String str, int off, int len) throws IOException
// Добавление (append)
public Writer append(CharSequence csq) throws IOException
// Сброс
public abstract void flush() throws IOException
// Закрытие
public abstract void close() throws IOException
}Ключевое отличие от байтовых потоков: методы
read() и write(int) работают с char (16 бит), а не с byte (8 бит). Возвращаемое значение read() — int в диапазоне 0..65535 для валидных символов и -1 для EOF. Это сохраняет контракт различения валидных данных от признака конца потока, но для 16-битных char вместо 8-битных byte.Кодировки: мост между байтами и символами
Символьные потоки не существуют в вакууме. Файлы, сетевые соединения, базы данных хранят и передают байты. Преобразование между байтами и символами выполняется через кодировку (charset) — таблицу соответствия последовательностей байт кодовым точкам Unicode.
UTF-8: доминирующая кодировка
UTF-8 — переменная длина кодирования Unicode:
U+0000..U+007F: 1 байт (ASCII-совместимость)
U+0080..U+07FF: 2 байта
U+0800..U+FFFF: 3 байта (большинство BMP-символов)
U+10000..U+10FFFF: 4 байта (суррогатные пары)
Преимущества UTF-8: ASCII-совместимость, компактность для латинских текстов, самосинхронизация (можно определить границу символа в произвольной позиции). Недостаток: переменная длина усложняет индексацию по символам —
str.charAt(n) — O(1), но str.codePointAt(n) требует проверки суррогатов.UTF-16: внутреннее представление Java
Java использует UTF-16 для внутреннего представления
String и char[]. Каждый char — 16 бит. Символы BMP (U+0000..U+FFFF) представляются одним char. Символы за пределами BMP — суррогатной парой: старший суррогат (U+D800..U+DBFF) + младший суррогат (U+DC00..U+DFFF).// Пример: эмодзи U+1F600 (😀) — суррогатная пара в Java
String emoji = "😀";
System.out.println(emoji.length()); // 2 — два char
System.out.println(emoji.codePointAt(0)); // 128512 — U+1F600
// Итерация по кодовым точкам, а не char
for (int cp : emoji.codePoints().toArray()) {
System.out.println("Code point: U+" + Integer.toHexString(cp));
}
Это критично для символьных потоков:
Reader.read() возвращает int с кодовой точкой, корректно обрабатывая суррогатные пары. read(char[]) заполняет массив char, где суррогатные пары занимают два элемента.Путь данных в памяти: от байтов файла до char[] в heap
Чтение текстового файла: FileReader
try (FileReader reader = new FileReader("text.txt")) {
int charValue;
while ((charValue = reader.read()) != -1) {
processChar((char) charValue);
}
}Путь данных при чтении:
[Диск: файл в байтах UTF-8]
-> [Page Cache ОС: байты файла]
-> [FileInputStream (underlying FileReader): чтение байтов]
-> [InputStreamReader: декодирование байт -> char]
-> [CharsetDecoder UTF-8: конечный автомат для мультибайтовых последовательностей]
-> [char[] буфер декодера в heap]
-> [FileReader.read(): возврат char как int]
-> [Java-код: processChar()]
FileReader — конкретный подкласс InputStreamReader, который автоматически открывает FileInputStream и использует кодировку платформы по умолчанию. Это опасно: кодировка по умолчанию зависит от ОС и locale, что делает поведение непредсказуемым при переносе между системами.// Антипаттерн: зависимость от кодировки платформы
FileReader reader = new FileReader("text.txt"); // Неявная кодировка!
// Правильно: явное указание кодировки
InputStreamReader reader = new InputStreamReader(
new FileInputStream("text.txt"), StandardCharsets.UTF_8);
Декодирование и память
InputStreamReader использует CharsetDecoder из java.nio.charset. Декодер поддерживает внутренний буфер байт для неполных мультибайтовых последовательностей (например, первые 2 байта 3-байтового UTF-8 символа в конце блока чтения) и буфер char для выходных символов.// Упрощенная логика декодирования
ByteBuffer in = ByteBuffer.allocate(8192); // Входные байты из потока
CharBuffer out = CharBuffer.allocate(8192); // Выходные символы
// Чтение байт из FileInputStream
int bytesRead = fileInputStream.read(in.array());
in.position(0).limit(bytesRead);
// Декодирование
CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
CoderResult result = decoder.decode(in, out, false);
// Извлечение символов
char[] chars = new char[out.position()];
out.flip().get(chars);
Буферы
ByteBuffer и CharBuffer — объекты в heap. CharsetDecoder — тоже объект в heap. При каждом создании InputStreamReader выделяется память для этих структур. При массовом открытии текстовых файлов без закрытия это создает давление на GC.#Java #для_новичков #beginner #IO #NIO #Reader #Writer
👍4
Путь данных при записи: от char[] в heap до байтов файла
Запись текстового файла: FileWriter
Путь данных при записи:
plain
Кодирование UTF-8 из char требует:
ASCII (U+0000..U+007F): 1 байт на символ
BMP non-ASCII (U+0080..U+FFFF): 2-3 байта
Суррогатные пары: 4 байта
Строка "Hello, 世界! 🌍" в Java:
'H', 'e', 'l', 'l', 'o', ',', ' ', '!': 8 символов ASCII → 8 байт UTF-8
'世' (U+4E16): 3 байта UTF-8
'界' (U+754C): 3 байта UTF-8
'🌍' (U+1F30D): суррогатная пара, 4 байта UTF-8
Итого: 8 + 3 + 3 + 4 = 18 байт UTF-8 для 11 "символов" в человеческом понимании, 12
Роль garbage collector
Жизненный цикл объектов кодирования
При обработке тысяч файлов этот код создает тысячи временных объектов. Они короткоживущие и эффективно собираются minor GC, но при высокой частоте могут вызвать частые паузы young generation.
Оптимизация: переиспользование Reader/Writer
Для потоковой обработки текста из одного источника переиспользование буферов снижает нагрузку на GC:
Проблема: большие строки и heap
BufferedReader и BufferedWriter: буферизация символьных потоков
Аналогично байтовым потокам, символьные потоки имеют буферизованные обертки:
java
Каждая
#Java #для_новичков #beginner #IO #NIO #Reader #Writer
Запись текстового файла: FileWriter
try (FileWriter writer = new FileWriter("output.txt")) {
writer.write("Hello, 世界! 🌍");
}Путь данных при записи:
plain
[Java-код: String "Hello, 世界! 🌍"]
-> [String.getBytes() или прямая работа с char[]]
-> [FileWriter (наследник OutputStreamWriter)]
-> [CharsetEncoder UTF-8: кодирование char -> байты]
-> [ByteBuffer буфер кодера в heap]
-> [FileOutputStream (underlying): запись байт]
-> [Page Cache ОС: dirty pages]
-> [Фоновая запись на диск]
Кодирование UTF-8 из char требует:
ASCII (U+0000..U+007F): 1 байт на символ
BMP non-ASCII (U+0080..U+FFFF): 2-3 байта
Суррогатные пары: 4 байта
Строка "Hello, 世界! 🌍" в Java:
'H', 'e', 'l', 'l', 'o', ',', ' ', '!': 8 символов ASCII → 8 байт UTF-8
'世' (U+4E16): 3 байта UTF-8
'界' (U+754C): 3 байта UTF-8
'🌍' (U+1F30D): суррогатная пара, 4 байта UTF-8
Итого: 8 + 3 + 3 + 4 = 18 байт UTF-8 для 11 "символов" в человеческом понимании, 12
char в JavaРоль garbage collector
Жизненный цикл объектов кодирования
public void processTextFiles(List<String> paths) throws IOException {
for (String path : paths) {
// Каждая итерация создает:
// - FileInputStream (heap)
// - InputStreamReader (heap)
// - CharsetDecoder (heap)
// - ByteBuffer/CharBuffer внутренние (heap)
// - char[] для чтения (heap)
try (InputStreamReader reader = new InputStreamReader(
new FileInputStream(path), StandardCharsets.UTF_8)) {
char[] buffer = new char[4096];
int charsRead;
while ((charsRead = reader.read(buffer)) != -1) {
process(buffer, charsRead);
}
} // close() освобождает ресурсы, объекты становятся недостижимыми
// GC собирает все созданные объекты при следующей minor collection
}
}При обработке тысяч файлов этот код создает тысячи временных объектов. Они короткоживущие и эффективно собираются minor GC, но при высокой частоте могут вызвать частые паузы young generation.
Оптимизация: переиспользование Reader/Writer
Для потоковой обработки текста из одного источника переиспользование буферов снижает нагрузку на GC:
// Переиспользуемый буфер
private static final ThreadLocal<char[]> CHAR_BUFFER =
ThreadLocal.withInitial(() -> new char[8192]);
public void processStream(InputStream in) throws IOException {
char[] buffer = CHAR_BUFFER.get();
try (InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8)) {
int charsRead;
while ((charsRead = reader.read(buffer)) != -1) {
process(buffer, charsRead);
}
}
// reader и его декодер собираются GC
// buffer остается в ThreadLocal, не подлежит GC
}
Проблема: большие строки и heap
// Антипаттерн: чтение всего файла в одну строку
String content = new String(Files.readAllBytes("huge.txt"), StandardCharsets.UTF_8);
Files.readAllBytes возвращает byte[] размером с файл. new String(...) создает char[] размером с количество символов (для ASCII — тот же размер, для UTF-8 с мультибайтом — меньше). Для файла 100MB это 100MB в byte[] + ~100MB в char[] = 200MB heap на один вызов. Если файл содержит преимущественно ASCII, byte[] и char[] примерно равны. Если содержит много 3-байтовых UTF-8 символов, char[] будет в 3 раза меньше byte[].BufferedReader и BufferedWriter: буферизация символьных потоков
Аналогично байтовым потокам, символьные потоки имеют буферизованные обертки:
try (BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream("text.txt"), StandardCharsets.UTF_8), 8192)) {
String line;
while ((line = br.readLine()) != null) {
processLine(line);
}
}
BufferedReader содержит char[] cb в heap — буфер символов. readLine() накапливает символы до \n или \r\n, создавая новую String при каждом вызове. Эти строки — долгоживущие объекты, которые GC не собирает до потери ссылки.java
// Путь данных readLine():
// 1. Чтение блока символов в cb[8192] из underlying Reader
// 2. Поиск \n в cb
// 3. new String(cb, start, end - start) — создание String в heap
// 4. Возврат String
// 5. Следующий вызов: повторение
Каждая
String — отдельный объект в heap с собственным char[] (или byte[] в современных JDK с компакт-строками). При чтении файла 100MB по строкам в 100 символов создается ~1 000 000 объектов String. Это создает массивное давление на GC.#Java #для_новичков #beginner #IO #NIO #Reader #Writer
👍4
Что выведет код?
#Tasks
import java.io.*;
public class Task170626 {
public static void main(String[] args) throws IOException {
StringReader sr = new StringReader("ABCDEFG");
BufferedReader br = new BufferedReader(sr);
System.out.print((char) br.read());
br.mark(2);
System.out.print((char) br.read());
System.out.print((char) br.read());
br.reset();
System.out.print((char) br.read());
System.out.print((char) br.read());
}
}
#Tasks
👍2
👍3
Что такое 🤓
Ответ:
SoftReference — объект будет удалён только при нехватке памяти (для кэшей).
WeakReference — объект будет удалён при ближайшей сборке, если нет сильных ссылок (WeakHashMap).
WeakHashMap автоматически удаляет записи, когда ключ становится слабодостижимым.
SoftReference используется в реализациях кэшей, например, Guava Cache с softValues().
Разница:
Weak — идеальны для карт метаданных (удаляются агрессивно),
Soft — для кэшей (удаляются только под давлением памяти).
Оба помогают избежать утечек памяти.
#собеседование
soft и weak ссылки в контексте коллекций? Ответ:
SoftReference — объект будет удалён только при нехватке памяти (для кэшей).
WeakReference — объект будет удалён при ближайшей сборке, если нет сильных ссылок (WeakHashMap).
WeakHashMap автоматически удаляет записи, когда ключ становится слабодостижимым.
SoftReference используется в реализациях кэшей, например, Guava Cache с softValues().
Разница:
Weak — идеальны для карт метаданных (удаляются агрессивно),
Soft — для кэшей (удаляются только под давлением памяти).
Оба помогают избежать утечек памяти.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Открытый урок: как на самом деле работают транзакции в Postgres | MVCC, уровни изоляции и блокировки
Прошу прощения за звук, Егора почти не слышно...🤷♀️
В этом открытом уроке разбираю, как на самом деле работают транзакции в PostgreSQL и почему одного @Transactional недостаточно для защиты от проблем конкурентного доступа.
Поговорим не только о теории, но и о том, что реально происходит внутри PostgreSQL и Spring-приложений.
В уроке:
• Что такое MVCC и зачем PostgreSQL хранит несколько версий строк
• Почему читатели не блокируют писателей
• Dirty Read, Non-repeatable Read, Phantom Read, Lost Update и Write Skew
• READ COMMITTED, REPEATABLE READ и SERIALIZABLE в PostgreSQL
• Как работают снимки данных (snapshots)
• Строковые, табличные и индексные блокировки
• FOR UPDATE и FOR SHARE
• Почему SELECT может не видеть строку, а INSERT уже конфликтует по UNIQUE индексу
• Optimistic Locking (@Version) в Hibernate
• Pessimistic Locking (PESSIMISTIC_WRITE, PESSIMISTIC_FORCE_INCREMENT)
• Как выбирать стратегию блокировок для реальных задач
• Практические примеры на Spring Boot + PostgreSQL
Этот урок является частью моего подхода к менторингу Java Backend-разработчиков, где основной акцент делается не на запоминании аннотаций, а на понимании механизмов, которые стоят за ними.
Ссылка на Youtube
Ссылка на Рутьюб
Смотрите, ставьте лайки, подписывайтесь на каналы!✌️
Жду ваших реакций и оценок🙂
Прошу прощения за звук, Егора почти не слышно...
В этом открытом уроке разбираю, как на самом деле работают транзакции в PostgreSQL и почему одного @Transactional недостаточно для защиты от проблем конкурентного доступа.
Поговорим не только о теории, но и о том, что реально происходит внутри PostgreSQL и Spring-приложений.
В уроке:
• Что такое MVCC и зачем PostgreSQL хранит несколько версий строк
• Почему читатели не блокируют писателей
• Dirty Read, Non-repeatable Read, Phantom Read, Lost Update и Write Skew
• READ COMMITTED, REPEATABLE READ и SERIALIZABLE в PostgreSQL
• Как работают снимки данных (snapshots)
• Строковые, табличные и индексные блокировки
• FOR UPDATE и FOR SHARE
• Почему SELECT может не видеть строку, а INSERT уже конфликтует по UNIQUE индексу
• Optimistic Locking (@Version) в Hibernate
• Pessimistic Locking (PESSIMISTIC_WRITE, PESSIMISTIC_FORCE_INCREMENT)
• Как выбирать стратегию блокировок для реальных задач
• Практические примеры на Spring Boot + PostgreSQL
Этот урок является частью моего подхода к менторингу Java Backend-разработчиков, где основной акцент делается не на запоминании аннотаций, а на понимании механизмов, которые стоят за ними.
Ссылка на Youtube
Ссылка на Рутьюб
Смотрите, ставьте лайки, подписывайтесь на каналы!
Жду ваших реакций и оценок
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
История технологии сегодня — 18 июня
ℹ️ Кто родился в этот день
Вита́лий Ио́сифович Гольда́нский (18 июня 1923, Витебск — 14 января 2001, Москва) — советский и российский учёный, физик-ядерщик и физикохимик, общественный деятель, народный депутат СССР. В 1970—1973 Гольданский показал неприменимость классического закона Аррениуса для скоростей химических реакций при низких температурах: им был открыт квантовый предел скорости реакций, протекающих за счёт туннелирования даже вблизи абсолютного нуля. Он также известен как основоположник химической физики позитрона и позитрония, показал возможность полимеризации под действием ударных волн, что было признано как научное открытие.
🌐 Знаковые события
1959 — Запуск ракеты-носителя «Восток-Л» с советской автоматической станцией «Луна-2А».
#Biography #Birth_Date #Events #18июня
Вита́лий Ио́сифович Гольда́нский (18 июня 1923, Витебск — 14 января 2001, Москва) — советский и российский учёный, физик-ядерщик и физикохимик, общественный деятель, народный депутат СССР. В 1970—1973 Гольданский показал неприменимость классического закона Аррениуса для скоростей химических реакций при низких температурах: им был открыт квантовый предел скорости реакций, протекающих за счёт туннелирования даже вблизи абсолютного нуля. Он также известен как основоположник химической физики позитрона и позитрония, показал возможность полимеризации под действием ударных волн, что было признано как научное открытие.
1959 — Запуск ракеты-носителя «Восток-Л» с советской автоматической станцией «Луна-2А».
#Biography #Birth_Date #Events #18июня
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
[Совет по Java #051]
Тема:
Проблема: При работе со стримами, содержащими
Такой код громоздок, содержит неявный вызов
Решение: Используйте
Для Java 8 используйте
Это естественно интегрируется с
Объяснение:
Это делает код более декларативным: вы говорите "для каждого Optional преврати его в поток значений (ноль или одно), и объедини их".
Такой подход устраняет необходимость явной проверки
#Java #советы
Тема:
flatMap на стриме может заменить filter + map, если внутри есть Optional.Проблема: При работе со стримами, содержащими
Optional, распространенной практикой является фильтрация существующих значений с последующим извлечением: stream.filter(Optional::isPresent).map(Optional::get).Такой код громоздок, содержит неявный вызов
get(), который ассоциируется с плохим тоном, и создает промежуточную операцию. Кроме того, это нарушает принцип "не используйте Optional как контейнер, который нужно разворачивать вручную". Вместо этого можно применить flatMap, который умеет сворачивать Optional в стрим из одного элемента или пустой стрим.Решение: Используйте
flatMap(Optional::stream) (доступно с Java 9). Для Java 8 используйте
flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty)). Этот подход объединяет фильтрацию и преобразование в одну операцию, делая код лаконичнее и выразительнее. Optional.stream() возвращает стрим из одного элемента, если значение присутствует, или пустой стрим, если отсутствует. Это естественно интегрируется с
flatMap, который разворачивает каждый Optional в ноль или один элемент итогового стрима.import java.util.*;
import java.util.stream.*;
public class OptionalFlatMap {
public static void main(String[] args) {
List<Optional<String>> list = Arrays.asList(
Optional.of("Java"),
Optional.empty(),
Optional.of("Kotlin"),
Optional.empty()
);
//Антипаттерн: filter + map
List<String> bad = list.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
System.out.println("Filter+map: " + bad);
//Решение: flatMap с Optional.stream (Java 9+)
List<String> good = list.stream()
.flatMap(Optional::stream) // Преобразует каждый Optional в стрим
.collect(Collectors.toList());
System.out.println("flatMap: " + good); // [Java, Kotlin]
// Для Java 8: альтернатива
List<String> java8 = list.stream()
.flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))
.collect(Collectors.toList());
System.out.println("Java 8 flatMap: " + java8);
// Работает и с другими Optional-подобными типами
List<OptionalInt> optionalInts = Arrays.asList(
OptionalInt.of(10),
OptionalInt.empty(),
OptionalInt.of(20)
);
// flatMap для OptionalInt требует преобразования в IntStream
// Не так прямо, но идея та же.
}
}
Объяснение:
flatMap принимает функцию, возвращающую стрим, и объединяет все такие стримы в один. Optional.stream() (Java 9+) преобразует Optional<T> в Stream<T> из одного элемента или пустой стрим. Это делает код более декларативным: вы говорите "для каждого Optional преврати его в поток значений (ноль или одно), и объедини их".
Такой подход устраняет необходимость явной проверки
isPresent и вызова get, что уменьшает вероятность ошибок. Кроме того, он естественно сочетается с другими операциями стрима, например, с map после flatMap. Для Java 8 можно использовать аналогичную конструкцию с map и orElseGet. #Java #советы
👍4
Что выведет код?
#Tasks
import java.util.*;
public class Task180626 {
public static void main(String[] args) {
List<Optional<String>> list = Arrays.asList(
Optional.of("a"),
null,
Optional.of("b")
);
list.stream()
.flatMap(Optional::stream)
.forEach(System.out::print);
}
}
#Tasks
👍3
👍4
Что такое 🤓
Ответ:
Утечка памяти — ситуация, когда объекты больше не нужны приложению, но GC не может их удалить, потому что на них всё ещё есть достижимые ссылки.
В Java это не утечка в классическом смысле, а "удерживание ссылок". Причины: статические коллекции, не закрытые ресурсы, слушатели/обработчики, неправильное кэширование, потоки, ThreadLocal без remove().
Поиск: профайлеры (VisualVM, JProfiler) смотрит heap dump, определяют самые большие объекты и пути к корням GC (GC roots).
Также помогают детекторы утечек (Eclipse Memory Analyzer).
#собеседование
Memory Leak в Java? Как найти? Ответ:
Утечка памяти — ситуация, когда объекты больше не нужны приложению, но GC не может их удалить, потому что на них всё ещё есть достижимые ссылки.
В Java это не утечка в классическом смысле, а "удерживание ссылок". Причины: статические коллекции, не закрытые ресурсы, слушатели/обработчики, неправильное кэширование, потоки, ThreadLocal без remove().
Поиск: профайлеры (VisualVM, JProfiler) смотрит heap dump, определяют самые большие объекты и пути к корням GC (GC roots).
Также помогают детекторы утечек (Eclipse Memory Analyzer).
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
История технологии сегодня — 19 июня
ℹ️ Кто родился в этот день
Блез Паска́ль (фр. Blaise Pascal [blɛz pasˈkal]; 19 июня 1623, родной дом Блеза Паскаля[вд], Клермон-Ферран, Королевство Франция — 19 августа 1662, Париж, Королевство Франция) — французский математик, механик, физик, литератор, философ и теолог. Классик французской литературы, один из основателей математического анализа, теории вероятностей и проективной геометрии, создатель первых образцов счётной техники, автор основного закона гидростатики.
Оге Нильс Бор (дат. Aage Niels Bohr; 19 июня 1922, Копенгаген, Дания — 8 сентября 2009, там же) — датский учёный, физик-ядерщик. Член Датской королевской академии наук (1955), ряда других академий мира. Лауреат Нобелевской премии по физике (1975), как и его отец Нильс Бор.
🌐 Знаковые события
1999 — вышла первая версия (1.0 Beta) онлайн-шутера Counter-Strike.
#Biography #Birth_Date #Events #19июня
Блез Паска́ль (фр. Blaise Pascal [blɛz pasˈkal]; 19 июня 1623, родной дом Блеза Паскаля[вд], Клермон-Ферран, Королевство Франция — 19 августа 1662, Париж, Королевство Франция) — французский математик, механик, физик, литератор, философ и теолог. Классик французской литературы, один из основателей математического анализа, теории вероятностей и проективной геометрии, создатель первых образцов счётной техники, автор основного закона гидростатики.
Оге Нильс Бор (дат. Aage Niels Bohr; 19 июня 1922, Копенгаген, Дания — 8 сентября 2009, там же) — датский учёный, физик-ядерщик. Член Датской королевской академии наук (1955), ряда других академий мира. Лауреат Нобелевской премии по физике (1975), как и его отец Нильс Бор.
1999 — вышла первая версия (1.0 Beta) онлайн-шутера Counter-Strike.
#Biography #Birth_Date #Events #19июня
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
Раздел 11. Работа с файлами, I/O и сетью (NIO.2)
Глава 1. Классический Java I/O (java.io)
Правильная работа с текстовыми файлами: InputStreamReader и OutputStreamWriter
Классы
Эта неопределенность делает
InputStreamReader: декодирование байтов в символы
Конструктор принимает
Путь данных через память JVM
Путь данных детально:
Внутреннее устройство
Механика декодирования UTF-8
UTF-8 — кодировка переменной длины. Декодер должен обрабатывать мультибайтовые последовательности, разбитые между блоками чтения:
Это требует внутреннего состояния в
OutputStreamWriter: кодирование символов в байты
Путь данных через память JVM
Путь данных детально:
Кодирование и размер выходных данных
Строка "Hello, 世界! 🌍" содержит:
8 символов ASCII: 8 байт UTF-8
'世' (U+4E16): 3 байта UTF-8
'界' (U+754C): 3 байта UTF-8
'🌍' (U+1F30D): суррогатная пара, 4 байта UTF-8
Итого: 18 байт для 11 кодовых точек, 12
#Java #для_новичков #beginner #IO #NIO #InputStreamReader #OutputStreamWriter
Глава 1. Классический Java I/O (java.io)
Правильная работа с текстовыми файлами: InputStreamReader и OutputStreamWriter
Классы
FileReader и FileWriter — удобные обертки, но содержат фундаментальный архитектурный дефект: они используют кодировку платформы по умолчанию, определяемую системным свойством file.encoding. Это свойство зависит от операционной системы, locale пользователя и параметров запуска JVM.// Антипаттерн: неявная кодировка платформы
try (FileReader reader = new FileReader("text.txt")) {
// На Windows может использоваться windows-1251
// На Linux — UTF-8
// На macOS — UTF-8
// Результат непредсказуем при переносе между системами
}
Эта неопределенность делает
FileReader/FileWriter непригодными для переносимого кода. Файл, записанный на одной системе, может быть искажен при чтении на другой. Современная практика рекомендует явное указание кодировки UTF-8 для всех текстовых операций.InputStreamReader: декодирование байтов в символы
InputStreamReader — мост от байтовых потоков к символьным. Он читает байты из InputStream и декодирует их в символы char с использованием указанной кодировки.public InputStreamReader(InputStream in, Charset cs)
Конструктор принимает
InputStream — источник сырых байтов, и Charset — правило декодирования. StandardCharsets.UTF_8 — предопределенная константа, исключающая риск неподдерживаемой кодировки.Путь данных через память JVM
try (InputStreamReader reader = new InputStreamReader(
new FileInputStream("text.txt"), StandardCharsets.UTF_8)) {
int charValue;
while ((charValue = reader.read()) != -1) {
System.out.print((char) charValue);
}
}
Путь данных детально:
[Файл на диске: байты UTF-8]
-> [Page Cache ОС: байты файла]
-> [FileInputStream.read(byte[]) — системный вызов]
-> [Нативный буфер userspace]
-> [JNI: копирование в byte[] внутри InputStreamReader]
-> [InputStreamReader: накопление байт во внутреннем ByteBuffer]
-> [CharsetDecoder UTF-8: конечный автомат декодирования]
-> [CharBuffer: накопление декодированных символов]
-> [read(): возврат char как int]
-> [System.out.print(char): кодирование в байты платформы]
Внутреннее устройство
InputStreamReader из OpenJDK:// Упрощенная структура
public class InputStreamReader extends Reader {
private final StreamDecoder sd; // Делегат декодирования
// StreamDecoder содержит:
// - ByteBuffer: входные байты из потока
// - CharBuffer: выходные символы
// - CharsetDecoder: конечный автомат кодировки
}
StreamDecoder — внутренний класс, выполняющий реальную работу. Он управляет ByteBuffer для входных байт и CharBuffer для выходных символов. Буферы создаются при конструировании и живут до закрытия потока.Механика декодирования UTF-8
UTF-8 — кодировка переменной длины. Декодер должен обрабатывать мультибайтовые последовательности, разбитые между блоками чтения:
// Сценарий: 3-байтовый символ '世' (U+4E16, E4 B8 96) разбит между чтениями
// Первое чтение: получены байты [..., E4, B8] — неполная последовательность
// StreamDecoder сохраняет E4 B8 во внутреннем ByteBuffer, возвращает 0 символов
// Второе чтение: получен байт [96, ...] — завершение последовательности
// StreamDecoder комбинирует E4 B8 96, декодирует в U+4E16, возвращает '世'
Это требует внутреннего состояния в
StreamDecoder: неполные байтовые последовательности сохраняются между вызовами read(). Буфер для этих остатков — часть ByteBuffer в heap.OutputStreamWriter: кодирование символов в байты
OutputStreamWriter — зеркальный мост: принимает символы char или String, кодирует их в байты согласно указанной кодировке, и записывает в OutputStream.public OutputStreamWriter(OutputStream out, Charset cs)
Путь данных через память JVM
try (OutputStreamWriter writer = new OutputStreamWriter(
new FileOutputStream("output.txt"), StandardCharsets.UTF_8)) {
writer.write("Hello, 世界! 🌍");
}
Путь данных детально:
[Java-код: String "Hello, 世界! 🌍"]
-> [String.toCharArray() или прямой доступ к внутреннему char[]]
-> [OutputStreamWriter.write(char[], off, len)]
-> [StreamEncoder: кодирование char -> байты]
-> [CharsetEncoder UTF-8: конечный автомат]
-> [ByteBuffer: накопление закодированных байт]
-> [FileOutputStream.write(byte[]): системный вызов]
-> [Нативный буфер userspace]
-> [Ядро ОС: syscall write]
-> [Page Cache: dirty pages]
-> [Фоновая запись на диск]
StreamEncoder — внутренний аналог StreamDecoder. Он управляет CharBuffer для входных символов и ByteBuffer для выходных байт. При вызове write(String) символы сначала копируются в CharBuffer, затем кодер преобразует их в байты UTF-8.Кодирование и размер выходных данных
Строка "Hello, 世界! 🌍" содержит:
8 символов ASCII: 8 байт UTF-8
'世' (U+4E16): 3 байта UTF-8
'界' (U+754C): 3 байта UTF-8
'🌍' (U+1F30D): суррогатная пара, 4 байта UTF-8
Итого: 18 байт для 11 кодовых точек, 12
char в JavaStreamEncoder должен обрабатывать суррогатные пары корректно: старший суррогат без младшего не является валидным символом и должен либо ждать дополнительных данных, либо генерировать замену (replacement character U+FFFD).#Java #для_новичков #beginner #IO #NIO #InputStreamReader #OutputStreamWriter
👍3
Практический пример: чтение UTF-8 и вывод в консоль
Путь данных с BufferedReader
Каждая строка — отдельный объект
Роль garbage collector
Жизненный цикл объектов кодирования
При обработке тысяч файлов этот код создает тысячи временных объектов. Они короткоживущие и собираются minor GC, но при высокой частоте могут вызвать частые паузы young generation.
Оптимизация: переиспользование буферов
Здесь
Запись с явной кодировкой
Буферизация записи
Для эффективной записи
#Java #для_новичков #beginner #IO #NIO
import java.io.*;
import java.nio.charset.StandardCharsets;
public class Utf8FileProcessor {
public void readAndPrint(String path) throws IOException {
// InputStreamReader: байты из файла -> символы UTF-8
try (InputStreamReader reader = new InputStreamReader(
new FileInputStream(path), StandardCharsets.UTF_8)) {
char[] buffer = new char[1024];
int charsRead;
// Буферизованное чтение символов
while ((charsRead = reader.read(buffer)) != -1) {
// Создание String из char[] — новый объект в heap
String chunk = new String(buffer, 0, charsRead);
System.out.print(chunk);
}
}
// reader закрыт, StreamDecoder и его буферы освобождены
// buffer и chunk — недостижимы, GC собирает при следующей minor collection
}
// Альтернатива: BufferedReader для построчного чтения
public void readLines(String path) throws IOException {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(
new FileInputStream(path), StandardCharsets.UTF_8))) {
String line;
int lineNumber = 0;
while ((line = reader.readLine()) != null) {
lineNumber++;
System.out.printf("%d: %s%n", lineNumber, line);
// Каждая line — новая String в heap
}
}
// Все String из readLine() недостижимы, если не сохранены
}
}
Путь данных с BufferedReader
BufferedReader добавляет собственный char[] cb в heap — буфер символов размером 8192 по умолчанию. readLine() накапливает символы в этот буфер до \n, затем создает String:[BufferedReader.readLine()]
-> [Заполнение cb[8192] из underlying InputStreamReader]
-> [InputStreamReader: декодирование байт -> символы]
-> [Поиск \n или \r\n в cb]
-> [new String(cb, start, length): создание String в heap]
-> [String конструктор: копирование char[] (или byte[] в современных JDK)]
-> [Возврат String]
Каждая строка — отдельный объект
String в heap. При чтении файла 100MB с ~1 000 000 строк создается 1 000 000 объектов String. Это создает значительное давление на GC, хотя строки короткоживущие и эффективно собираются minor GC.Роль garbage collector
Жизненный цикл объектов кодирования
public void processManyFiles(List<String> paths) throws IOException {
for (String path : paths) {
// Каждая итерация создает:
// - FileInputStream (heap)
// - InputStreamReader (heap)
// - StreamDecoder (heap)
// - ByteBuffer, CharBuffer внутренние (heap)
// - CharsetDecoder (heap)
// - char[] buffer (heap)
// - String chunk (heap, при каждом read)
try (InputStreamReader reader = new InputStreamReader(
new FileInputStream(path), StandardCharsets.UTF_8)) {
char[] buffer = new char[4096];
int charsRead;
while ((charsRead = reader.read(buffer)) != -1) {
process(new String(buffer, 0, charsRead));
}
}
// Все объекты становятся недостижимыми
// GC собирает их при следующей minor collection
}
}При обработке тысяч файлов этот код создает тысячи временных объектов. Они короткоживущие и собираются minor GC, но при высокой частоте могут вызвать частые паузы young generation.
Оптимизация: переиспользование буферов
// Переиспользуемый буфер для чтения
private static final ThreadLocal<char[]> CHAR_BUFFER =
ThreadLocal.withInitial(() -> new char[8192]);
public void processFileOptimized(String path) throws IOException {
char[] buffer = CHAR_BUFFER.get();
try (InputStreamReader reader = new InputStreamReader(
new FileInputStream(path), StandardCharsets.UTF_8)) {
int charsRead;
while ((charsRead = reader.read(buffer)) != -1) {
// String всё еще создается, но buffer переиспользуется
process(new String(buffer, 0, charsRead));
}
}
}
Здесь
char[] buffer переиспользуется между вызовами, устраняя одну аллокацию на файл. Однако new String(...) при каждом чтении всё еще создает объекты. Для полного устранения аллокаций требуется обработка in-place в char[] без создания String.Запись с явной кодировкой
public void writeUtf8File(String path, List<String> lines) throws IOException {
// OutputStreamWriter: символы -> байты UTF-8
try (OutputStreamWriter writer = new OutputStreamWriter(
new FileOutputStream(path), StandardCharsets.UTF_8)) {
for (String line : lines) {
writer.write(line); // Кодирование char[] -> байты UTF-8
writer.write(System.lineSeparator());
}
writer.flush(); // Сброс внутренних буферов в FileOutputStream
} // close() с неявным flush()
// StreamEncoder и его буферы освобождены
}Буферизация записи
Для эффективной записи
OutputStreamWriter оборачивается в BufferedWriter:try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(path), StandardCharsets.UTF_8))) {
for (String line : lines) {
writer.write(line);
writer.newLine(); // Платформенно-независимый разделитель
}
}
BufferedWriter содержит char[] cb в heap — буфер символов. Запись накапливается в этом буфере и сбрасывается в OutputStreamWriter при заполнении или вызове flush(). Это устраняет частые вызовы кодера и underlying потока.#Java #для_новичков #beginner #IO #NIO
👍3
Что выведет код?
#Tasks
import java.io.*;
import java.nio.charset.StandardCharsets;
public class Task190626 {
public static void main(String[] args) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(baos, StandardCharsets.US_ASCII);
writer.write('€');
writer.flush();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
InputStreamReader reader = new InputStreamReader(bais, StandardCharsets.US_ASCII);
int ch = reader.read();
System.out.println(ch);
}
}
#Tasks
👍2
👍3
Что такое 🤓
Ответ:
JNI (Java Native Interface) — это фреймворк, позволяющий Java-коду вызывать и быть вызванным нативными приложениями (C/C++).
Используется для доступа к системным функциям, устройствам, оптимизации.
Проблемы:
1) потеря переносимости (нужно компилировать под каждую ОС/архитектуру).
2) сложность отладки (ошибки в нативном коде могут крашнуть JVM).
3) утечки памяти в нативной части не отслеживаются GC.
4) накладные расходы на маршалинг данных.
5) несовместимость с модульной системой Java 9+.
Альтернативы: Project Panama (Foreign Function API) в новых версиях Java.
#собеседование
JNI? Какие проблемы при его использовании? Ответ:
Используется для доступа к системным функциям, устройствам, оптимизации.
Проблемы:
1) потеря переносимости (нужно компилировать под каждую ОС/архитектуру).
2) сложность отладки (ошибки в нативном коде могут крашнуть JVM).
3) утечки памяти в нативной части не отслеживаются GC.
4) накладные расходы на маршалинг данных.
5) несовместимость с модульной системой Java 9+.
Альтернативы: Project Panama (Foreign Function API) в новых версиях Java.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5