👍2
Что такое 🤓
Ответ:
StackOverflowError — ошибка (Error), возникающая, когда стек вызовов потоков исчерпал доступную память.
Обычно это результат бесконечной рекурсии (метод вызывает сам себя без условий выхода) или очень глубокой рекурсии (например, обход большого дерева без оптимизации).
Диагностировать можно:
1) посмотреть stack trace — последние вызовы повторяются.
2) увеличить размер стека (флаг -Xss).
3) переписать рекурсию на итерацию или хвостовую рекурсию (Java не оптимизирует её сама).
Также может возникать при большом количестве вложенных вызовов (например, парсинг глубокого JSON).
#собеседование
StackOverflowError и как его диагностировать? Ответ:
StackOverflowError — ошибка (Error), возникающая, когда стек вызовов потоков исчерпал доступную память.
Обычно это результат бесконечной рекурсии (метод вызывает сам себя без условий выхода) или очень глубокой рекурсии (например, обход большого дерева без оптимизации).
Диагностировать можно:
1) посмотреть stack trace — последние вызовы повторяются.
2) увеличить размер стека (флаг -Xss).
3) переписать рекурсию на итерацию или хвостовую рекурсию (Java не оптимизирует её сама).
Также может возникать при большом количестве вложенных вызовов (например, парсинг глубокого JSON).
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологии сегодня — 16 июня
ℹ️ Кто родился в этот день
Алекса́ндр Алекса́ндрович Фри́дман (4 (16) июня 1888[3], Санкт-Петербург — 16 сентября 1925, Ленинград) — русский и советский математик, гидромеханик, физик-теоретик и геофизик. Основоположник современной физической космологии, автор исторически первой нестационарной модели Вселенной (Вселенная Фридмана), один из создателей современной динамической метеорологии. Основные работы посвящены проблемам динамической метеорологии (теории атмосферных вихрей и порывистости ветра, теории разрывов непрерывности в атмосфере, атмосферной турбулентности), гидродинамике сжимаемой жидкости, физике атмосферы и релятивистской космологии. В июле 1925 года с научными целями совершил полёт на аэростате вместе с пилотом Павлом Федосеенко, достигнув рекордной по тому времени для СССР высоты 7400 м. Фридман одним из первых освоил математический аппарат теории гравитации Эйнштейна и начал читать в университете курс тензорного исчисления как вводную часть к курсу общей теории относительности. В 1923 году вышла в свет его книга «Мир как пространство и время» (переиздана в 1965 году), познакомившая широкую публику с новой физикой.
Юлиус Плю́ккер (нем. Julius Plücker; 16 июня или 16 июля 1801 года, Эльберфельд — 22 мая 1868 года, Бонн) — немецкий математик и физик, работавший в области аналитической геометрии, был пионером в области исследования катодных лучей, что впоследствии привело к открытию электрона. Также занимался исследованиями кривых Ламе.
🌐 Знаковые события
1911 — основана корпорация IBM.
1963 — стартовал космический корабль «Восток-6» с Валентиной Терешковой, первой в мире женщиной-космонавтом.
#Biography #Birth_Date #Events #16июня
Алекса́ндр Алекса́ндрович Фри́дман (4 (16) июня 1888[3], Санкт-Петербург — 16 сентября 1925, Ленинград) — русский и советский математик, гидромеханик, физик-теоретик и геофизик. Основоположник современной физической космологии, автор исторически первой нестационарной модели Вселенной (Вселенная Фридмана), один из создателей современной динамической метеорологии. Основные работы посвящены проблемам динамической метеорологии (теории атмосферных вихрей и порывистости ветра, теории разрывов непрерывности в атмосфере, атмосферной турбулентности), гидродинамике сжимаемой жидкости, физике атмосферы и релятивистской космологии. В июле 1925 года с научными целями совершил полёт на аэростате вместе с пилотом Павлом Федосеенко, достигнув рекордной по тому времени для СССР высоты 7400 м. Фридман одним из первых освоил математический аппарат теории гравитации Эйнштейна и начал читать в университете курс тензорного исчисления как вводную часть к курсу общей теории относительности. В 1923 году вышла в свет его книга «Мир как пространство и время» (переиздана в 1965 году), познакомившая широкую публику с новой физикой.
Юлиус Плю́ккер (нем. Julius Plücker; 16 июня или 16 июля 1801 года, Эльберфельд — 22 мая 1868 года, Бонн) — немецкий математик и физик, работавший в области аналитической геометрии, был пионером в области исследования катодных лучей, что впоследствии привело к открытию электрона. Также занимался исследованиями кривых Ламе.
1911 — основана корпорация IBM.
1963 — стартовал космический корабль «Восток-6» с Валентиной Терешковой, первой в мире женщиной-космонавтом.
#Biography #Birth_Date #Events #16июня
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
[Совет по Java #050]
Тема:
Проблема:
Использование
Решение: Используйте
Объяснение: Создатели Java (в частности, Брайан Гетц) неоднократно подчеркивали, что
#Java #советы
Тема:
Optional не предназначен для полей класса и для параметров методов.Проблема:
Optional был создан как ограниченный механизм для возвращаемых значений методов, чтобы явно указать возможность отсутствия результата. Использование
Optional в полях класса нарушает сериализацию: Optional не реализует Serializable, и многие фреймворки (Hibernate, Jackson, сериализация Java) работают с ним некорректно или требуют дополнительной настройки. Кроме того, поле-Optional создает избыточность — само поле уже может быть null, а его обертка добавляет еще один уровень. Использование Optional в параметрах методов делает API громоздким: вызывающий код вынужден создавать Optional.of() или Optional.empty(), что усложняет чтение и не дает реальных преимуществ.Решение: Используйте
Optional только для возвращаемых типов методов, которые могут не возвращать значение. Для полей класса используйте null-допустимые типы с аннотациями (@Nullable, @NotNull) или библиотеки вроде Lombok. Для параметров методов используйте перегрузки методов или явную проверку на null. Если параметр может быть опциональным, лучше применить паттерн Builder или передавать отдельный флаг.import java.util.Optional;
import java.io.Serializable;
public class OptionalUsage {
//Антипаттерн: Optional как поле класса
static class BadEntity implements Serializable {
private Optional<String> name = Optional.empty(); // Не сериализуется!
private Optional<Integer> age; // Hibernate не поймет
// getter/setter
}
//Правильно: просто nullable поле
static class GoodEntity implements Serializable {
private String name; // null = отсутствует
private Integer age; // null = отсутствует
}
//Антипаттерн: Optional в параметре метода
public static void badMethod(Optional<String> param) {
// Вызывающему нужно писать badMethod(Optional.of("text"))
if (param.isPresent()) { /* ... */ }
}
//Решение 1: перегрузка метода
public static void goodMethod() {
// без параметра
}
public static void goodMethod(String param) {
// с параметром (может быть null)
}
//Решение 2: проверка на null
public static void betterMethod(String param) {
if (param != null) { /* ... */ }
}
//Единственное правильное место: возвращаемое значение
public static Optional<String> findUserById(long id) {
// поиск в БД
return id > 0 ? Optional.of("User") : Optional.empty();
}
public static void main(String[] args) {
// Использование Optional из возврата
findUserById(10).ifPresent(System.out::println);
// Перегрузка вместо Optional параметра
goodMethod(); // без параметра
goodMethod("text"); // с параметром
}
}
Объяснение: Создатели Java (в частности, Брайан Гетц) неоднократно подчеркивали, что
Optional предназначен исключительно для возвращаемых значений. Он не должен использоваться в полях, параметрах методов, коллекциях и как ключ в Map. Причина: Optional не сериализуем (есть обходные пути, но они хрупкие), и его использование в полях вводит в заблуждение — поле уже может быть null, а обертка не добавляет безопасности. Для параметров методов Optional создает лишний объект и не улучшает читаемость. Вместо этого используйте явную проверку на null, аннотации @Nullable или @NotNull, а для возврата — Optional.#Java #советы
👍5
Что выведет код?
#Tasks
import java.io.*;
import java.util.Optional;
class Data160626 implements Serializable {
Optional<String> value = Optional.of("secret");
}
public class Task160626 {
public static void main(String[] args) throws Exception {
Data160626 d = new Data160626();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(d);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
Data160626 d2 = (Data160626) ois.readObject();
System.out.println(d2.value.get());
}
}
#Tasks
👍3
Варианты ответа:
Anonymous Quiz
31%
secret
8%
null
8%
Optional[secret]
54%
java.io.NotSerializableException
👍3
Вот это и случилось))) Ютуб канал перегнал по популярности телеграмм-канал.
Что думаете? Помоему закономерно, хотя труда вложенного в телеге гораздо больше....
Хотя если оглянуться то и 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