[Совет по Java #053]
Тема:
Проблема: Статический метод
Если два элемента стрима отображаются на один и тот же ключ, коллектор выбрасывает
Решение: Используйте перегруженную версию
Наиболее частые стратегии: оставить первое значение (
Также существует
Объяснение: Базовая версия
Указывая
#Java #советы
Тема:
Collectors.toMap при дублирующихся ключах выбрасывает IllegalStateException.Проблема: Статический метод
Collectors.toMap(Function keyMapper, Function valueMapper) создает коллектор, который собирает элементы стрима в HashMap. Если два элемента стрима отображаются на один и тот же ключ, коллектор выбрасывает
IllegalStateException с сообщением "duplicate key". Это поведение часто оказывается неожиданным для разработчиков, которые полагаются на уникальность ключей в данных, но из-за ошибок в данных или бизнес-логике дубликаты возникают. В результате приложение падает в рантайме, и диагностика может быть затруднена, особенно в больших стримах. Даже если вероятность дубликатов мала, надежность кода требует явного определения стратегии разрешения конфликтов.Решение: Используйте перегруженную версию
Collectors.toMap(keyMapper, valueMapper, mergeFunction), где mergeFunction — это BinaryOperator, определяющий, какое значение сохранить при конфликте. Наиболее частые стратегии: оставить первое значение (
(oldValue, newValue) -> oldValue), взять последнее ((old, new) -> new), объединить значения (например, конкатенировать строки или суммировать числа). Для сложной агрегации используйте Collectors.groupingBy в связке с downstream-коллектором. Также существует
Collectors.toConcurrentMap для потокобезопасных карт.import java.util.*;
import java.util.stream.*;
public class ToMapDuplicate {
public static void main(String[] args) {
List<String> items = Arrays.asList("apple", "banana", "apple", "cherry");
//Антипаттерн: выбросит IllegalStateException
try {
Map<String, Integer> bad = items.stream()
.collect(Collectors.toMap(s -> s, String::length));
} catch (IllegalStateException e) {
System.err.println("Duplicate key: " + e.getMessage());
}
//Решение 1: оставить первое значение
Map<String, Integer> first = items.stream()
.collect(Collectors.toMap(
s -> s,
String::length,
(oldVal, newVal) -> oldVal
));
System.out.println("First: " + first); // {banana=6, apple=5, cherry=6}
//Решение 2: взять последнее значение (часто для перезаписи)
Map<String, Integer> last = items.stream()
.collect(Collectors.toMap(
s -> s,
String::length,
(old, newVal) -> newVal
));
System.out.println("Last: " + last);
//Решение 3: объединить значения (например, список длин)
Map<String, List<Integer>> grouped = items.stream()
.collect(Collectors.toMap(
s -> s,
s -> new ArrayList<>(List.of(s.length())),
(list1, list2) -> { list1.addAll(list2); return list1; }
));
System.out.println("Grouped: " + grouped);
//Альтернатива: groupingBy для агрегации
Map<String, Long> countByKey = items.stream()
.collect(Collectors.groupingBy(
s -> s,
Collectors.counting()
));
System.out.println("Counts: " + countByKey);
}
}
Объяснение: Базовая версия
toMap вызывает Map.merge(key, value, throwingMerger()), где throwingMerger просто бросает IllegalStateException. Это сделано для того, чтобы предотвратить случайную потерю данных без явного указания стратегии. Указывая
mergeFunction, вы берете на себя ответственность за разрешение конфликтов. Выбор стратегии зависит от бизнес-правил: для уникальных идентификаторов лучше перезаписывать последним значением; для агрегации — использовать groupingBy с downstream; для подсчета частоты — groupingBy с counting(). #Java #советы
👍5
Что выведет код?
#Tasks
import java.util.*;
import java.util.stream.*;
public class Task240626 {
static class Person240626 {
int id;
String name;
Person240626(int id, String name) {
this.id = id;
this.name = name;
}
}
public static void main(String[] args) {
List<Person240626> people = Arrays.asList(
new Person240626(1, "Alice"),
new Person240626(2, "Bob"),
new Person240626(1, "Charlie")
);
try {
Map<Integer, String> map = people.stream()
.collect(
Collectors.toMap(p -> p.id, p -> p.name)
);
System.out.println("Success");
} catch (Exception e) {
System.out.println(e.getClass().getSimpleName());
}
}
}
#Tasks
👍2
Варианты ответа:
Anonymous Quiz
47%
Success
35%
IllegalStateException
18%
IllegalArgumentException
0%
NullPointerException
👍4
Что такое 🤓
Ответ:
Начиная с Java 12 (preview) и финал в Java 14, switch может быть выражением, возвращающим значение.
Используется -> вместо : и yield для возврата значения из блока.
Пример:
String result = switch (day) { case MON -> "Work"; case SAT, SUN -> "Weekend"; default -> throw ...; };.
Также поддерживается блок: case MON -> { yield "Work"; }. Это делает код лаконичнее, устраняет fall-through (прорыв) и позволяет использовать switch в функциональном стиле.
Важно, что для выражения должны быть покрыты все возможные значения (или default).
#собеседование
switch-выражения (Switch Expressions)? Ответ:
Используется -> вместо : и yield для возврата значения из блока.
Пример:
String result = switch (day) { case MON -> "Work"; case SAT, SUN -> "Weekend"; default -> throw ...; };.
Также поддерживается блок: case MON -> { yield "Work"; }. Это делает код лаконичнее, устраняет fall-through (прорыв) и позволяет использовать switch в функциональном стиле.
Важно, что для выражения должны быть покрыты все возможные значения (или default).
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологии сегодня — 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июня
Шамиль Гимбатович Алиев (род. 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
Ключевое отличие от
Внутреннее устройство
Поле
Механика write(String) и путь данных
Накопление в буфере
Путь данных при
Никаких системных вызовов, никакого кодирования. Пять символов копируются в
Сброс буфера: flushBuffer()
Путь данных при заполнении буфера:
Ключевой момент:
Метод newLine(): платформенная независимость
#Java #для_новичков #beginner #IO #NIO #BufferedWriter
Глава 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
Путь данных в памяти: детальный разбор
Сценарий: запись списка строк
Память в процессе:
Никаких новых аллокаций в цикле, кроме возможных расширений
Сценарий: буфер заполнен
Роль garbage collector
Жизненный цикл буферов
Анализ памяти:
Общий пик памяти: ~72 KB на буферы + строки. Для больших файлов это незначительно.
Проблема: очень длинные строки
При превышении размера буфера
Практический пример: запись списка строк в файл
Сравнение с небуферизованной записью
С
#Java #для_новичков #beginner #IO #NIO #BufferedWriter
Сценарий: запись списка строк
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 heapByteBuffer внутри StreamEncoder — буфер для кодирования, ~24 KB heapString из 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
Что выведет код?
#Tasks
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
👍3
https://habr.com/ru/articles/1051878/
Так ребят, новая статья на Хабре🤓
Читаем, если есть вопросы - задаем, ну и конечно же оцениваем!
Всех обнял, приподнял 🤝
Так ребят, новая статья на Хабре
Читаем, если есть вопросы - задаем, ну и конечно же оцениваем!
Всех обнял, приподнял 🤝
Please open Telegram to view this post
VIEW IN TELEGRAM
Хабр
Анатомия Spring Proxy: кто и зачем подменяет ваши бины
Продолжаю рассказ о том как безработный Java - разработчик ищет себе занятия...)) В этот раз, благодаря вопросам ребят, которых вынужденно менторю (кстати пользуясь случаем, всем благодарен, ценю) , я...
👍9🔥3
Что такое 🤓
Ответ:
Records (Java 14 preview, финал в Java 16) — это неизменяемые (immutable) классы-носители данных.
Объявляются как record Point(int x, int y) {}.
Компилятор автоматически генерирует: конструктор, геттеры (с теми же именами), equals(), hashCode(), toString().
Можно добавить компактный конструктор для валидации. Records не могут наследоваться, но могут реализовывать интерфейсы.
Идеальны для DTO, value objects, кортежей. Упрощают создание классов-данных, уменьшая шаблонный код.
#собеседование
record (Record-классы)? Ответ:
Records
Объявляются как record Point(int x, int y) {}.
Компилятор автоматически генерирует: конструктор, геттеры (с теми же именами), equals(), hashCode(), toString().
Можно добавить компактный конструктор для валидации. Records не могут наследоваться, но могут реализовывать интерфейсы.
Идеальны для DTO, value objects, кортежей. Упрощают создание классов-данных, уменьшая шаблонный код.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологии сегодня — 26 июня
ℹ️ Кто родился в этот день
Уи́льям То́мсон, лорд Ке́львин (Ке́лвин) (англ. William Thomson, 1st Baron Kelvin; 26 июня 1824 года, Белфаст, Ирландия — 17 декабря 1907 года, Ларгс, Шотландия) — британский физик, механик и инженер. Известен своими работами в области термодинамики, механики, электродинамики.
Роберт Колман Ри́чардсон (англ. Robert Coleman Richardson; 26 июня 1937, Вашингтон — 19 февраля 2013) — американский физик, лауреат Нобелевской премии по физике 1996 года, совместно с Дугласом Ошеровым и Дэвидом Ли, «за открытие сверхтекучести гелия-3».
🌐 Знаковые события
1954 — произведён энергетический пуск первой в мире атомной электростанции.
1997 — основана антивирусная компания «Лаборатория Касперского».
#Biography #Birth_Date #Events #26июня
Уи́льям То́мсон, лорд Ке́львин (Ке́лвин) (англ. William Thomson, 1st Baron Kelvin; 26 июня 1824 года, Белфаст, Ирландия — 17 декабря 1907 года, Ларгс, Шотландия) — британский физик, механик и инженер. Известен своими работами в области термодинамики, механики, электродинамики.
Роберт Колман Ри́чардсон (англ. Robert Coleman Richardson; 26 июня 1937, Вашингтон — 19 февраля 2013) — американский физик, лауреат Нобелевской премии по физике 1996 года, совместно с Дугласом Ошеровым и Дэвидом Ли, «за открытие сверхтекучести гелия-3».
1954 — произведён энергетический пуск первой в мире атомной электростанции.
1997 — основана антивирусная компания «Лаборатория Касперского».
#Biography #Birth_Date #Events #26июня
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
[Совет по Java #054]
Тема:
Проблема: Метод
При обработке упорядоченных стримов (например, из
Решение: Используйте перегруженную версию
Объяснение:
Передавая
#Java #советы
Тема:
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, мы явно указываем, что карта должна сохранять порядок вставки. Порядок вставки определяется порядком появления ключей в стриме. Для упорядоченных стримов (полученных из List, SortedSet или после sorted()) это дает предсказуемый результат. Для параллельных стримов сохранение порядка не гарантируется, даже с LinkedHashMap, потому что порядок обработки недетерминирован. Также важно, что LinkedHashMap немного дороже по памяти, чем HashMap, но эта цена оправдана, когда порядок важен.#Java #советы
👍3
Что выведет код?
#Tasks
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
👍3
Что такое pattern matching для 🤓
Ответ:
Начиная с Java 16, instanceof может объявлять переменную одновременно с проверкой: if (obj instanceof String s) { ... }.
Если объект является экземпляром String, переменная s инициализируется автоматически, и её можно использовать в блоке.
Это сокращает код и устраняет необходимость явного приведения.
В Java 17+ pattern matching расширен на switch. Упрощает работу с полиморфными структурами, делая код более безопасным (переменная недоступна вне области).
#собеседование
instanceof? Ответ:
Если объект является экземпляром String, переменная s инициализируется автоматически, и её можно использовать в блоке.
Это сокращает код и устраняет необходимость явного приведения.
В Java 17+ pattern matching расширен на switch. Упрощает работу с полиморфными структурами, делая код более безопасным (переменная недоступна вне области).
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6