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

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

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

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

Шамиль Гимбатович Алиев (род. 25 июня 1943, Тануси, Хунзахский район) — доктор технических наук, профессор. Заслуженный деятель наук Дагестанской АССР. Разработчик ракетного оружия и космических технологий. Известен как один из авторов монографий «Низкочастотное излучение развитых кавитационных течений», «Фундаментальные технические комплексы. Теория аналитического проектирования» и др. Разработчик торпед, установленных на атомной подводной лодке «Курск». Знаток проблем устойчивости вихревой пелены за крылом конечного размаха. Со второй половины 1980-х годов на крупнейших выставках оружия (на Международной Морской выставке в Сиднее в 2004 году и др.) позиционируется как «идеолог и конструктор надводного и подводного оружия аэрокосмического комплекса России» и «разработчик торпедного оружия России».

Алексе́й Алексе́евич Абрико́сов (25 июня 1928, Москва — 29 марта 2017, Пало-Алто, США) — советскийроссийский и американский физик-теоретик. Лауреат Нобелевской премии по физике(2003, совместно с Виталием Гинзбургом и Энтони Леггетом). В 2003 году, совместно с В. Л. Гинзбургом и Э. Леггетом, получил Нобелевскую премию по физике за «основополагающие работы по теории сверхпроводников и сверхтекучих жидкостей».

Йоханнес Ханс Даниель Йе́нсен (нем. Johannes Hans Daniel Jensen; 25 июня 1907, Гамбург — 11 февраля 1973, Гейдельберг) — немецкий учёный, физик-ядерщик, лауреат Нобелевской премии по физике в 1963 году. Половина премии, совместно с Марией Гёпперт-Майер, «за открытия, касающиеся оболочечной структуры ядра». Вторую половину премии получил Юджин Вигнер.

Герман Юлиус Оберт (нем. Hermann Julius Oberth, 25 июня 1894 — 28 декабря 1989) — немецкий учёный и инженер в области космонавтики и ракетостроения, один из основоположников современной ракетной техники.


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

1966 — запускается первый советский метеоспутник «Космос-122».

1974 — запуск советской орбитальной космической станции «Салют-3».

1998 — официально вышла операционная система «Windows 98».


#Biography #Birth_Date #Events #25июня
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Раздел 11. Работа с файлами, I/O и сетью (NIO.2)

Глава 1. Классический Java I/O (java.io)

BufferedWriter – запись строк. Буферизация и путь данных в памяти JVM

BufferedWriter — декоратор над Writer, добавляющий внутреннюю буферизацию символьного вывода. Он решает проблему, зеркальную BufferedReader: накладные расходы системных вызовов при частых мелких операциях записи. Вместо немедленной отправки каждого символа или строки в underlying Writer, BufferedWriter накапливает данные в массиве char[] в heap и сбрасывает их пачками.

Ключевое отличие от BufferedOutputStream: BufferedWriter работает с символами char (16 бит), а не байтами. Это означает, что его внутренний буфер хранит char[], а преобразование в байты происходит позже — в underlying OutputStreamWriter, который кодирует символы в UTF-8 или другую кодировку.


Внутреннее устройство
// Упрощенная структура из OpenJDK
public class BufferedWriter extends Writer {
// Внутренний буфер символов в heap JVM
private char[] cb;

// Текущая позиция записи в буфере
private int nChars;

// Ссылка на underlying Writer
private Writer out;

// Разделитель строки для newLine()
private String lineSeparator;

// Конструкторы
public BufferedWriter(Writer out) {
this(out, defaultCharBufferSize); // 8192 по умолчанию
}

public BufferedWriter(Writer out, int sz) {
super(out);
if (sz <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
this.out = out;
cb = new char[sz]; // Выделение в heap: 8192 * 2 = 16384 байт
nChars = 0;
lineSeparator = System.lineSeparator(); // Платформенный разделитель
}
}


Поле cb — массив char[] размером 8192 по умолчанию, что занимает 16 KB в heap. lineSeparator инициализируется значением System.lineSeparator(), которое равно \n на Unix/Linux/macOS и \r\n на Windows.
Механика write(String) и путь данных


Накопление в буфере
public void write(String s, int off, int len) throws IOException {
// Если строка не влезает в оставшийся буфер — сброс
if (len >= cb.length - nChars) {
flushBuffer(); // Сброс накопленного в underlying Writer
}

if (len >= cb.length) {
// Строка больше буфера — запись напрямую, минуя буфер
writeDirect(s, off, len);
} else {
// Копирование строки в буфер
s.getChars(off, off + len, cb, nChars); // Быстрое копирование из String
nChars += len;
}
}


Путь данных при write("Hello"):
[Java: bw.write("Hello")]
-> [BufferedWriter: len=5 < cb.length - nChars?]
-> [s.getChars(0, 5, cb, nChars)] // Копирование char[] из String в buf
-> [System.arraycopy: копирование 5 char в cb]
-> [nChars += 5]
-> [Возврат]

Никаких системных вызовов, никакого кодирования. Пять символов копируются в cb через System.arraycopy — нативный метод, оптимизированный JVM.


Сброс буфера: flushBuffer()
private void flushBuffer() throws IOException {
if (nChars > 0) {
out.write(cb, 0, nChars); // Запись в underlying Writer
nChars = 0; // Сброс позиции
}
}


Путь данных при заполнении буфера:
[BufferedWriter: flushBuffer()]
-> [OutputStreamWriter.write(cb, 0, nChars)]
-> [StreamEncoder: кодирование char[] -> байты UTF-8]
-> [ByteBuffer: накопление закодированных байт]
-> [FileOutputStream.write(byte[]): системный вызов]
-> [Нативный буфер userspace]
-> [Ядро ОС: syscall write]
-> [Page Cache: dirty pages]

Ключевой момент: BufferedWriter не знает о кодировке. Он накапливает char[], а кодирование в байты происходит в OutputStreamWriter. Это означает, что буфер BufferedWriter содержит символы, а буфер StreamEncoder — байты. Два уровня буферизации создают двойное копирование при сбросе.


Метод newLine(): платформенная независимость
public void newLine() throws IOException {
write(lineSeparator); // Запись \n или \r\n из поля lineSeparator
}


newLine()
записывает разделитель строки, определенный при конструировании. Это позволяет генерировать файлы с правильными разделителями для целевой платформы, независимо от платформы выполнения.
// На Unix: запись \n
// На Windows: запись \r\n
// Результат одинаков для кода, различается для файла



#Java #для_новичков #beginner #IO #NIO #BufferedWriter
👍4
Путь данных в памяти: детальный разбор

Сценарий: запись списка строк
public void writeLines(String path, List<String> lines) throws IOException {
// cb[8192] создается в heap при конструировании BufferedWriter
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(path), StandardCharsets.UTF_8))) {

for (String line : lines) {
writer.write(line); // Копирование в cb
writer.newLine(); // Копирование \n или \r\n в cb
// Системный вызов отсутствует, пока cb не заполнен
}

// Явный flush для гарантии сброса
writer.flush();

} // close() с неявным flush()
}

Память в процессе:
cb[8192] — буфер BufferedWriter, 16 KB heap
ByteBuffer внутри StreamEncoder — буфер для кодирования, ~24 KB heap
String из lines — удерживаются списком, не создаются заново
Никаких новых аллокаций в цикле, кроме возможных расширений ByteBuffer


Сценарий: буфер заполнен

// Допустим, cb заполнен на 8188 символов
// Запись строки "Hello" (5 символов + 1 \n = 6)

writer.write("Hello"); // 8188 + 5 = 8193 > 8192 — сброс!
writer.newLine(); // \n записывается в пустой cb


[write("Hello")]
-> [len=5 >= cb.length - nChars? 5 >= 4? да]
-> [flushBuffer()]
-> [out.write(cb, 0, 8188)] // Сброс 8188 символов в OutputStreamWriter
-> [StreamEncoder: кодирование 8188 char в байты UTF-8]
-> [FileOutputStream: системный вызов]
-> [nChars = 0]
-> [s.getChars(0, 5, cb, 0)] // "Hello" в cb[0..4]
-> [nChars = 5]

[newLine()]
-> [write("\n")] // или "\r\n"
-> [s.getChars(0, 1, cb, 5)] // \n в cb[5]
-> [nChars = 6]



Роль garbage collector

Жизненный цикл буферов
public void processAndWrite(String inputPath, String outputPath) throws IOException {
// Все объекты создаются в heap
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(inputPath), StandardCharsets.UTF_8));
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(outputPath), StandardCharsets.UTF_8))) {

String line;
while ((line = reader.readLine()) != null) {
String processed = processLine(line); // Новая String в heap
writer.write(processed); // Копирование в cb
writer.newLine();
// processed становится мусором, если не сохранена
}

} // Все потоки закрыты, все буферы освобождены

// reader.cb, writer.cb, ByteBuffer'ы StreamEncoder — недостижимы
// GC собирает все при следующей minor collection
}


Анализ памяти:

reader.cb[8192] — 16 KB, освобожден при закрытии
writer.cb[8192] — 16 KB, освобожден при закрытии
ByteBuffer декодера — ~16 KB, освобожден
ByteBuffer кодера — ~24 KB, освобожден
line — собирается GC каждую итерацию
processed — собирается GC, если не сохранена
Общий пик памяти: ~72 KB на буферы + строки. Для больших файлов это незначительно.


Проблема: очень длинные строки

// Строка длиной 100 000 символов
String hugeLine = generateHugeLine();

// write() обнаруживает, что len >= cb.length
// Прямая запись, минуя буфер
writer.write(hugeLine);

При превышении размера буфера BufferedWriter не копирует строку в cb, а передает её напрямую в underlying Writer. Это экономит память (не дублирует строку в буфере), но лишает преимущества буферизации — системный вызов выполняется немедленно.

Практический пример: запись списка строк в файл

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;

public class LineWriter {

public void writeLines(String path, List<String> lines) throws IOException {
// Путь данных:
// String -> char[] -> cb[BufferedWriter] -> ByteBuffer[StreamEncoder] -> FileOutputStream -> page cache -> диск

try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(path), StandardCharsets.UTF_8))) {

for (String line : lines) {
writer.write(line); // Копирование в cb
writer.newLine(); // Платформенный разделитель
}

// Явный flush перед закрытием
writer.flush();

} // close() с неявным flush()

// Все буферы в heap освобождены, GC собирает
}

// Альтернатива: запись с заголовком и подвалом
public void writeReport(String path, String header,
List<String> data, String footer) throws IOException {
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(path), StandardCharsets.UTF_8))) {

writer.write(header);
writer.newLine();
writer.newLine(); // Пустая строка

for (String line : data) {
writer.write(line);
writer.newLine();
}

writer.newLine(); // Пустая строка перед подвалом
writer.write(footer);
writer.newLine();

}
}
}


Сравнение с небуферизованной записью
// Антипаттерн: запись без буферизации
public void writeUnbuffered(String path, List<String> lines) throws IOException {
try (OutputStreamWriter writer = new OutputStreamWriter(
new FileOutputStream(path), StandardCharsets.UTF_8)) {

for (String line : lines) {
writer.write(line); // Каждый символ = системный вызов!
writer.write('\n');
}
}
}


OutputStreamWriter
без BufferedWriter кодирует и записывает каждую порцию данных немедленно. Для строки "Hello" это означает: кодирование 5 символов в 5 байт UTF-8, системный вызов write(fd, buf, 5). Для 1 000 000 строк — 2 000 000 системных вызовов.

С BufferedWriter: накопление в cb, сброс при заполнении. Для средней строки 80 символов + 1 \n = 81 символ. Буфер 8192 вмещает ~100 строк. Системных вызовов: 1 000 000 / 100 = 10 000. Ускорение в 200 раз.


#Java #для_новичков #beginner #IO #NIO #BufferedWriter
👍4
Что выведет код?

import java.io.*;

public class Task250626 {
public static void main(String[] args) throws IOException {
File file = new File("test.txt");
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write(65);
}
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
System.out.println(br.readLine());
}
file.delete();
}
}


#Tasks
👍2
Варианты ответа:
Anonymous Quiz
45%
65
27%
A
18%
Пустая строка
9%
null
👍3
Что такое record (Record-классы)? 🤓

Ответ:

Records
(Java 14 preview, финал в Java 16) — это неизменяемые (immutable) классы-носители данных.

Объявляются как record Point(int x, int y) {}.

Компилятор автоматически генерирует: конструктор, геттеры (с теми же именами), equals(), hashCode(), toString().

Можно добавить компактный конструктор для валидации. Records не могут наследоваться, но могут реализовывать интерфейсы.

Идеальны для DTO, value objects, кортежей. Упрощают создание классов-данных, уменьшая шаблонный код.



#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
[Совет по Java #054]

Тема: Collectors.groupingBy сохраняет порядок, если передать LinkedHashMap::new в качестве supplier.

Проблема: Метод Collectors.groupingBy(Function classifier) по умолчанию использует HashMap для накопления результатов, который не гарантирует никакого порядка ключей.

При обработке упорядоченных стримов (например, из List с определенной последовательностью) порядок ключей в результирующей Map может быть произвольным, что нарушает ожидания разработчика и может привести к непредсказуемому поведению при последующей итерации. Это особенно критично, если порядок группировки важен для бизнес-логики (например, группировка по датам в хронологическом порядке). Даже если стрим упорядочен, HashMap не сохраняет этот порядок, так как его структура основана на хэш-кодах.

Решение: Используйте перегруженную версию Collectors.groupingBy(classifier, supplier, downstream), передавая LinkedHashMap::new в качестве supplier. 

LinkedHashMap
 сохраняет порядок вставки ключей, а порядок вставки при группировке соответствует порядку, в котором ключи впервые встречаются в стриме (для упорядоченных стримов). Если нужен другой порядок (например, сортировка по ключу), используйте TreeMap::new и groupingBy с сортировкой.
import java.util.*;
import java.util.stream.*;

public class GroupingByOrder {

public static void main(String[] args) {
List<String> words = Arrays.asList("apple", "banana", "apple", "cherry", "banana");

//По умолчанию: HashMap — порядок не гарантирован
Map<String, Long> defaultMap = words.stream()
.collect(Collectors.groupingBy(
s -> s,
Collectors.counting()
));
System.out.println("Default (HashMap): " + defaultMap);
// Может вывести {banana=2, cherry=1, apple=2} (порядок зависит от хэшей)

//Сохранение порядка вставки (LinkedHashMap)
Map<String, Long> orderedMap = words.stream()
.collect(Collectors.groupingBy(
s -> s,
LinkedHashMap::new, // supplier для сохранения порядка
Collectors.counting()
));
System.out.println("Ordered (LinkedHashMap): " + orderedMap);
// Порядок: apple (первое вхождение), banana, cherry

//Для сортировки по ключу используем TreeMap
Map<String, Long> sortedMap = words.stream()
.collect(Collectors.groupingBy(
s -> s,
TreeMap::new,
Collectors.counting()
));
System.out.println("Sorted by key: " + sortedMap); // apple, banana, cherry

// Для группировки с downstream коллектором, сохраняющим порядок элементов
Map<String, List<String>> groupedList = words.stream()
.collect(Collectors.groupingBy(
s -> s,
LinkedHashMap::new,
Collectors.toList() // сохраняет порядок элементов внутри группы
));
System.out.println("Grouped with list order: " + groupedList);
// {apple=[apple, apple], banana=[banana, banana], cherry=[cherry]}
}
}


Объяснение:
 Collectors.groupingBy имеет три перегрузки: первая использует HashMap и ArrayList как downstream; вторая позволяет задать конкретную фабрику для результирующей Map; третья также позволяет задать downstream-коллектор.

Передавая LinkedHashMap::new, мы явно указываем, что карта должна сохранять порядок вставки. Порядок вставки определяется порядком появления ключей в стриме. Для упорядоченных стримов (полученных из ListSortedSet или после sorted()) это дает предсказуемый результат. Для параллельных стримов сохранение порядка не гарантируется, даже с LinkedHashMap, потому что порядок обработки недетерминирован. Также важно, что LinkedHashMap немного дороже по памяти, чем HashMap, но эта цена оправдана, когда порядок важен.

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

import java.util.*;
import java.util.stream.*;

public class Task260626 {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5);
Map<Integer, List<Integer>> map = numbers.stream()
.collect(Collectors.groupingBy(
n -> n % 2,
LinkedHashMap::new,
Collectors.toList()
));
System.out.println(map.keySet());
}
}


#Tasks
👍2
Варианты ответа:
Anonymous Quiz
50%
[1, 0]
25%
[0, 1]
0%
[0]
25%
[1]
👍3
Что такое pattern matching для instanceof? 🤓

Ответ:

Начиная с Java 16, instanceof может объявлять переменную одновременно с проверкой: if (obj instanceof String s) { ... }.

Если объект является экземпляром String, переменная s инициализируется автоматически, и её можно использовать в блоке.

Это сокращает код и устраняет необходимость явного приведения.

В Java 17+ pattern matching расширен на switch. Упрощает работу с полиморфными структурами, делая код более безопасным (переменная недоступна вне области).



#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Буду дальше немного красот публиковать, если вы не против 🤟

р. Мундыбаш
🔥91
«Голова Кита» село Турочак, Республика Алтай
🔥12🆒3
История технологии сегодня — 27 июня

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

Влади́мир Миха́йлович Петляко́в (15 (27) июня 1891, село Самбек, область Войска Донского, Российская империя — 12 января 1942, деревня Мамешево, Сергачский район, Горьковская область, РСФСР, СССР) — советский авиаконструктор.
Известные модели самолётов
Тяжелый бомбардировщик ТБ-3 (АНТ-6)
Пассажирский самолёт АНТ-14 «Правда»
Тяжелый бомбардировщик ТБ-4 (АНТ-16)
Агитационный самолёт АНТ-20 «Максим Горький»
Тяжёлый бомбардировщик дальнего действия Пе-8 (АНТ-42, ТБ-7)
Высотный истребитель ВИ-100
Пикирующий бомбардировщик Пе-2
Высотный истребитель Пе-3


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

1931 — в США изобретатель Игорь Сикорский подал патентную заявку на вариант одновинтового вертолёта с небольшим рулевым винтом.


#Biography #Birth_Date #Events #27июня
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Так ведь? 😂
🤣7
Начало реки Бия. Телецкое озеро
🔥13
Ахаха, я бы точно не расстроился 😂
🤣3🤓1