Часть 3. Расширение: фильтрация и сортировка жанров
Задача: только жанры классики, отсортированные
Важно: sorted() в промежуточной операции работает, но для больших данных лучше сортировать после collect, если порядок критичен.
Часть 4. Задача с исключением: безопасный парсинг годов
Поступают строки годов из внешнего источника (файл, API, пользовательский ввод). Нужно получить список валидных целых чисел, игнорируя ошибки парсинга.
Входные данные:
Плохой подход: try-catch в цикле с изменяемым списком
Проблемы: изменяемый список, скрытое игнорирование ошибок, сложно тестировать.
Хороший подход: flatMap + Optional
Создайте вспомогательный метод для безопасного парсинга:
Использование в Stream:
Что происходит:
safeParseYear возвращает Optional<Integer> — явное указание на возможность отсутствия значения
Optional.stream() (Java 9+) создаёт поток из 0 или 1 элемента
flatMap «выпрямляет» потоки: Stream<Optional<Integer>> → Stream<Integer>
Невалидные строки превращаются в пустые потоки и исчезают из результата
Для Java 8 (без Optional.stream()):
#Java #для_новичков #beginner #stream_api #практика
Задача: только жанры классики, отсортированные
public Set<String> getClassicGenresSorted() {
return books.stream()
.filter(book -> book.getYear() < 1950) // только старые книги
.flatMap(book -> book.getGenres().stream())
.filter(genre -> !genre.equals("Фэнтези")) // исключаем современное
.sorted() // сортировка (временно в Stream)
.collect(Collectors.toCollection(LinkedHashSet::new)); // сохраняем порядок
}Важно: sorted() в промежуточной операции работает, но для больших данных лучше сортировать после collect, если порядок критичен.
Часть 4. Задача с исключением: безопасный парсинг годов
Поступают строки годов из внешнего источника (файл, API, пользовательский ввод). Нужно получить список валидных целых чисел, игнорируя ошибки парсинга.
Входные данные:
["1999", "invalid", "2005", "nineteen", "2020", ""]
Плохой подход: try-catch в цикле с изменяемым списком
// Не делайте так
List<Integer> years = new ArrayList<>();
for (String s : yearStrings) {
try {
years.add(Integer.parseInt(s));
} catch (NumberFormatException e) {
// игнорируем — но где гарантия, что мы ничего не пропустили?
}
}
Проблемы: изменяемый список, скрытое игнорирование ошибок, сложно тестировать.
Хороший подход: flatMap + Optional
Создайте вспомогательный метод для безопасного парсинга:
// В отдельном классе-утилите или в Library
private static Optional<Integer> safeParseYear(String yearString) {
try {
return Optional.of(Integer.parseInt(yearString));
} catch (NumberFormatException e) {
return Optional.empty();
}
}
Использование в Stream:
public List<Integer> parseValidYears(List<String> yearStrings) {
return yearStrings.stream()
.flatMap(s -> safeParseYear(s).stream()) // Optional → Stream (0 или 1 элемента)
.collect(Collectors.toList());
}Что происходит:
safeParseYear возвращает Optional<Integer> — явное указание на возможность отсутствия значения
Optional.stream() (Java 9+) создаёт поток из 0 или 1 элемента
flatMap «выпрямляет» потоки: Stream<Optional<Integer>> → Stream<Integer>
Невалидные строки превращаются в пустые потоки и исчезают из результата
Для Java 8 (без Optional.stream()):
.flatMap(s -> safeParseYear(s).map(Stream::of).orElseGet(Stream::empty))
#Java #для_новичков #beginner #stream_api #практика
👍2
Часть 5. Интеграция в проект «Библиотека»
Задача 1: обновление метода добавления книги с валидацией жанров
В Library добавьте проверку, что жанр книги существует в библиотеке:
Улучшение: кэшировать getAllGenresFunctional() при частых проверках.
Задача 2: статистика по жанрам
Результат: { "Роман"=15, "Детектив"=8, "Фантастика"=12 }
Задача 3: книги с неизвестными годами
Используем safeParseYear для обработки внешних данных при импорте:
Практические задания
Задача 1: рефакторинг существующего кода
Найдите в проекте «Библиотека» методы, которые:
собирают данные в Set или List через циклы и add/addAll
фильтруют коллекции вручную
Перепишите их через flatMap, filter, collect. Добавьте peek для отладки, затем удалите.
Задача 2: поиск книг по нескольким жанрам
Реализуйте метод findBooksByAnyGenre(List<String> targetGenres) — книги, имеющие хотя бы один жанр из списка.
Подсказка: anyMatch внутри filter.
Реализуйте метод findBooksByAllGenres(List<String> targetGenres) — книги, имеющие все жанры из списка.
Подсказка: containsAll или targetGenres.stream().allMatch(...).
Задача 3: отчёт по авторам и их жанрам
Создайте Map<String, Set<String>> — автор → все жанры его книг.
Используйте flatMap для «размножения» пары (автор, жанр), затем groupingBy.
Задача 4: импорт с валидацией (звёздочка)
Создайте метод importFromCsv(List<String> lines), где каждая строка: "title;author;year;genre1,genre2".
Требования:
пропускать строки с невалидным годом (через safeParseYear)
пропускать строки с пустым названием или автором
собрать статистику: сколько строк успешно, сколько с ошибкой
вернуть ImportResult с List<Book> и List<String> errors
Используйте flatMap для преобразования строки в Optional<Book> → Stream<Book>.
#Java #для_новичков #beginner #stream_api #практика
Задача 1: обновление метода добавления книги с валидацией жанров
В Library добавьте проверку, что жанр книги существует в библиотеке:
public boolean isValidGenre(String genre) {
return getAllGenresFunctional().contains(genre);
}
public void addBookWithGenreValidation(Book book) {
for (String genre : book.getGenres()) {
if (!isValidGenre(genre) && !books.isEmpty()) {
System.out.println("Предупреждение: новый жанр '" + genre + "'");
}
}
addBook(book);
}Улучшение: кэшировать getAllGenresFunctional() при частых проверках.
Задача 2: статистика по жанрам
public Map<String, Long> getGenreStatistics() {
return books.stream()
.flatMap(book -> book.getGenres().stream())
.collect(Collectors.groupingBy(
genre -> genre,
Collectors.counting()
));
}Результат: { "Роман"=15, "Детектив"=8, "Фантастика"=12 }
Задача 3: книги с неизвестными годами
Используем safeParseYear для обработки внешних данных при импорте:
public List<Book> importBooksFromRawData(List<String[]> rawData) {
return rawData.stream()
.flatMap(row -> {
Optional<String> title = Optional.ofNullable(row[0]);
Optional<String> author = Optional.ofNullable(row[1]);
Optional<Integer> year = safeParseYear(row[2]);
List<String> genres = row.length > 3
? Arrays.asList(row[3].split(","))
: Collections.emptyList();
// создаём книгу только если все обязательные поля валидны
return title.flatMap(t ->
author.flatMap(a ->
year.map(y -> new Book(t, a, y, genres))
)
).stream();
})
.collect(Collectors.toList());
}Практические задания
Задача 1: рефакторинг существующего кода
Найдите в проекте «Библиотека» методы, которые:
собирают данные в Set или List через циклы и add/addAll
фильтруют коллекции вручную
Перепишите их через flatMap, filter, collect. Добавьте peek для отладки, затем удалите.
Задача 2: поиск книг по нескольким жанрам
Реализуйте метод findBooksByAnyGenre(List<String> targetGenres) — книги, имеющие хотя бы один жанр из списка.
Подсказка: anyMatch внутри filter.
Реализуйте метод findBooksByAllGenres(List<String> targetGenres) — книги, имеющие все жанры из списка.
Подсказка: containsAll или targetGenres.stream().allMatch(...).
Задача 3: отчёт по авторам и их жанрам
Создайте Map<String, Set<String>> — автор → все жанры его книг.
// Ожидаемый результат:
// { "Толстой"=["Роман", "Исторический"],
// "Оруэлл"=["Антиутопия", "Сатира"] }
Используйте flatMap для «размножения» пары (автор, жанр), затем groupingBy.
Задача 4: импорт с валидацией (звёздочка)
Создайте метод importFromCsv(List<String> lines), где каждая строка: "title;author;year;genre1,genre2".
Требования:
пропускать строки с невалидным годом (через safeParseYear)
пропускать строки с пустым названием или автором
собрать статистику: сколько строк успешно, сколько с ошибкой
вернуть ImportResult с List<Book> и List<String> errors
Используйте flatMap для преобразования строки в Optional<Book> → Stream<Book>.
#Java #для_новичков #beginner #stream_api #практика
👍3
Что выведет код?
#Tasks
public class Task260225 {
public static void main(String[] args) {
float a = 0.1f;
double b = 0.1;
System.out.println(a == 0.1);
System.out.println(b == 0.1);
System.out.println(a == 0.1f);
System.out.println(a == (float)0.1);
}
}#Tasks
👍2
Варианты ответа:
Anonymous Quiz
4%
false true false true
36%
false true true true
44%
true true true true
16%
false false true true
👍2
Что такое сериализация (Serialization)? 🤓
Ответ:
Сериализация — это процесс преобразования состояния объекта в поток байтов для сохранения в файл, передачи по сети или хранения в БД.
Десериализация — обратный процесс восстановления объекта из байтов.
Для сериализации объект должен реализовать маркерный интерфейс Serializable. Ключевое слово transient исключает поле из сериализации. Нужно быть осторожным с версионированием классов — поле serialVersionUID помогает контролировать совместимость версий.
#собеседование
Ответ:
Десериализация — обратный процесс восстановления объекта из байтов.
Для сериализации объект должен реализовать маркерный интерфейс Serializable. Ключевое слово transient исключает поле из сериализации. Нужно быть осторожным с версионированием классов — поле serialVersionUID помогает контролировать совместимость версий.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологий сегодня — 27 Февраля
ℹ️ Кто родился в этот день
Ю́лий Бори́сович Харито́н (14 [27] февраля 1904, Санкт-Петербург — 18 декабря 1996, Саров) — советский и российский физик и физикохимик. Деятель науки и техники — ядерщик. Академик АН СССР и РАН (1953). Один из руководителей советского проекта атомной бомбы.
А́лан Ха́рви Гут (Гус) (англ. Alan Harvey Guth; род. 27 февраля 1947, Нью-Брансуик, округ Мидлсекс, Нью-Джерси, США) — американский физик и космолог, предложивший идею космической инфляции. Его теория требует сложных численных расчётов и стала одним из драйверов развития вычислительной космологии и высокопроизводительных вычислений, где активно используются методы моделирования, статистики и обработки больших данных.
🌐 Знаковые события
1932 — Джеймс Чедвик открыл нейтрон.
#Biography #Birth_Date #Events #27февраля
Ю́лий Бори́сович Харито́н (14 [27] февраля 1904, Санкт-Петербург — 18 декабря 1996, Саров) — советский и российский физик и физикохимик. Деятель науки и техники — ядерщик. Академик АН СССР и РАН (1953). Один из руководителей советского проекта атомной бомбы.
А́лан Ха́рви Гут (Гус) (англ. Alan Harvey Guth; род. 27 февраля 1947, Нью-Брансуик, округ Мидлсекс, Нью-Джерси, США) — американский физик и космолог, предложивший идею космической инфляции. Его теория требует сложных численных расчётов и стала одним из драйверов развития вычислительной космологии и высокопроизводительных вычислений, где активно используются методы моделирования, статистики и обработки больших данных.
1932 — Джеймс Чедвик открыл нейтрон.
#Biography #Birth_Date #Events #27февраля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Итак, на фоне уже явных сообщений о блокировке телеграмма, раздумываю о переносе канала.
Недавно обнаружил что можно создать канал в max. Нужен ли он?
Хотел спросить вашего мнения:
- нужно ли вообще переносить канал или вы согласны читать его под vpn/санкциями/прочей херней
- если переносить - то как назвать новый канал. Вопрос возник так как мы давно уже не для новичков канал))
Предложите варианты))
- или пора каналу стать прошлым и мне сконцентрироваться на ютубе/рутубе и обучающих роликах, которые дают наибольшую конверсию?
Давайте хорошенько обсудим эти вопросы. Помогите мне принять решение, от него зависит будущее канала.
✌️
Недавно обнаружил что можно создать канал в max. Нужен ли он?
Хотел спросить вашего мнения:
- нужно ли вообще переносить канал или вы согласны читать его под vpn/санкциями/прочей херней
- если переносить - то как назвать новый канал. Вопрос возник так как мы давно уже не для новичков канал))
Предложите варианты))
- или пора каналу стать прошлым и мне сконцентрироваться на ютубе/рутубе и обучающих роликах, которые дают наибольшую конверсию?
Давайте хорошенько обсудим эти вопросы. Помогите мне принять решение, от него зависит будущее канала.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥3😱3
[Совет по Java #010]
Тема: Ключевое слово finally выполняется всегда, даже если в try или catch был return. Но если в finally тоже будет return, он перекроет предыдущий — так не делайте.
Проблема: Блок finally гарантированно выполняется после try (и catch, если было исключение) независимо от того, был ли в них оператор return, break, continue или выброшено исключение.
Это фундаментальное свойство, используемое для очистки ресурсов. Однако если в самом finally поместить return, он перезапишет результат, возвращаемый из try/catch, и "проглотит" любое исключение. Такое поведение крайне неочевидно и приводит к трудноотлаживаемым багам, когда метод возвращает не то значение или не бросает ожидаемое исключение.
Решение: Никогда не используйте return в блоке finally.
Блок finally должен содержать только код очистки (закрытие ресурсов, счетчики, разблокировки) и не должен вмешиваться в поток возврата значения или исключения. Если вам нужно обработать результат или исключение, делайте это в try или catch, а finally оставляйте для побочных эффектов.
Объяснение: Спецификация Java гарантирует, что блок finally выполняется перед тем, как метод вернет управление.
Если finally содержит return, то значение, вычисленное в try (или выброшенное исключение), отбрасывается, и метод завершается с тем значением, которое указано в finally. Это же касается и исключений — если в finally нет throw, то любое исключение из try/catch считается обработанным. Такое поведение противоречит интуиции и здравому смыслу.
Разработчик использует finally исключительно для освобождения ресурсов (или с 2011 года — try-with-resources), никогда не помещая туда управляющие операторы, влияющие на результат метода.
#Java #советы
Тема: Ключевое слово finally выполняется всегда, даже если в try или catch был return. Но если в finally тоже будет return, он перекроет предыдущий — так не делайте.
Проблема: Блок finally гарантированно выполняется после try (и catch, если было исключение) независимо от того, был ли в них оператор return, break, continue или выброшено исключение.
Это фундаментальное свойство, используемое для очистки ресурсов. Однако если в самом finally поместить return, он перезапишет результат, возвращаемый из try/catch, и "проглотит" любое исключение. Такое поведение крайне неочевидно и приводит к трудноотлаживаемым багам, когда метод возвращает не то значение или не бросает ожидаемое исключение.
Решение: Никогда не используйте return в блоке finally.
Блок finally должен содержать только код очистки (закрытие ресурсов, счетчики, разблокировки) и не должен вмешиваться в поток возврата значения или исключения. Если вам нужно обработать результат или исключение, делайте это в try или catch, а finally оставляйте для побочных эффектов.
import java.io.*;
public class FinallyReturn {
//Антипаттерн: return в finally
public static int badExample() {
try {
System.out.println("Try");
return 42; // Этот return будет проигнорирован
} finally {
System.out.println("Finally");
return 100; // Перекрывает return из try
}
}
//Еще хуже: finally "проглатывает" исключение
public static int badWithException() {
try {
throw new RuntimeException("Ошибка в try");
} finally {
return 200; // Исключение ПРОПАДАЕТ!
}
}
//Правильно: finally без return
public static int goodExample() {
try {
System.out.println("Try");
return 42; // Нормальный выход
} finally {
System.out.println("Finally");
// Здесь только очистка, без return
}
}
//Правильно с исключением
public static int goodWithException() throws IOException {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
return Integer.parseInt(reader.readLine());
} finally {
if (reader != null) {
try {
reader.close(); // Только закрытие, return нет
} catch (IOException e) {
// Логируем, но не перезаписываем исходное исключение
}
}
}
}
// Демонстрация
public static void main(String[] args) {
System.out.println("badExample(): " + badExample());
// Вывод: Try, Finally, 100 (а не 42!)
System.out.println("badWithException(): " + badWithException());
// Исключение не выбрасывается, выводит 200
System.out.println("goodExample(): " + goodExample());
// Вывод: Try, Finally, 42 (корректно)
}
}
Объяснение: Спецификация Java гарантирует, что блок finally выполняется перед тем, как метод вернет управление.
Если finally содержит return, то значение, вычисленное в try (или выброшенное исключение), отбрасывается, и метод завершается с тем значением, которое указано в finally. Это же касается и исключений — если в finally нет throw, то любое исключение из try/catch считается обработанным. Такое поведение противоречит интуиции и здравому смыслу.
Разработчик использует finally исключительно для освобождения ресурсов (или с 2011 года — try-with-resources), никогда не помещая туда управляющие операторы, влияющие на результат метода.
#Java #советы
👍6
Что выведет код?
#Tasks
public class Task270226 {
public static void main(String[] args) {
System.out.println(test());
}
static String test() {
try {
System.exit(0);
return "try";
} catch (Exception e) {
return "catch";
} finally {
return "finally";
}
}
}#Tasks
👍2
🔥3👍1
Что такое клоннирование (Cloning)? Как правильно клонировать объекты? 🤓
Ответ:
Клонирование — создание точной копии объекта.
В Java для этого используется метод clone() класса Object. Чтобы объект можно было клонировать, класс должен реализовать маркерный интерфейс Cloneable (иначе будет CloneNotSupportedException).
Метод clone() делает поверхностное копирование (shallow copy) — копирует примитивы и ссылки, но не сами объекты по ссылкам.
Для глубокого копирования (deep copy) нужно переопределить clone() и вручную клонировать вложенные объекты.
Альтернативы: конструктор копирования, статический фабричный метод, сериализация.
#собеседование
Ответ:
В Java для этого используется метод clone() класса Object. Чтобы объект можно было клонировать, класс должен реализовать маркерный интерфейс Cloneable (иначе будет CloneNotSupportedException).
Метод clone() делает поверхностное копирование (shallow copy) — копирует примитивы и ссылки, но не сами объекты по ссылкам.
Для глубокого копирования (deep copy) нужно переопределить clone() и вручную клонировать вложенные объекты.
Альтернативы: конструктор копирования, статический фабричный метод, сериализация.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
https://t.me/Java_for_beginner_dev/4379
Чет мало мнений! Давайте все высказывайтесь?
Да и предложите название уж))
Чет мало мнений! Давайте все высказывайтесь?
Да и предложите название уж))
Telegram
Java for Beginner
Итак, на фоне уже явных сообщений о блокировке телеграмма, раздумываю о переносе канала.
Недавно обнаружил что можно создать канал в max. Нужен ли он?
Хотел спросить вашего мнения:
- нужно ли вообще переносить канал или вы согласны читать его под vpn/…
Недавно обнаружил что можно создать канал в max. Нужен ли он?
Хотел спросить вашего мнения:
- нужно ли вообще переносить канал или вы согласны читать его под vpn/…
👍1
История технологий сегодня — 28 Февраля
ℹ️ Кто родился в этот день
То́мас Нью́комен (англ. Thomas Newcomen; крещён 28 февраля 1664, Дартмут — 7 августа 1729, Лондон) — английский изобретатель; один из создателей первого теплового (парового) двигателя, известного как паровая машина Ньюкомена.
Леон Н.Купер (англ. Leon Neil Cooper; при рождении — Леон Н. Купчик; 28 февраля 1930, Нью-Йорк, Нью-Йорк — 23 октября 2024, Провиденс) — американский физик, лауреат Нобелевской премии по физике 1972 года (совместно с Джоном Бардиным и Джоном Шриффером) «за создание теории сверхпроводимости, обычно называемой БКШ-теорией». Именем Купера названы электронные пары Купера и BCM теория синаптической пластичности.
🌐 Знаковые события
1956 — в США патентуется сетевой кабель для компьютеров.
1956 — Джей Форрестер получает патент на магнитно‑ядерную память (core memory). Магнитное сердечниковое ОЗУ стало стандартной памятью компьютеров 1950–60‑х и фактически сделало надёжные электронные компьютеры массовыми; без неё не было бы ни ранних мейнфреймов, ни многих космических систем.
#Biography #Birth_Date #Events #28февраля
То́мас Нью́комен (англ. Thomas Newcomen; крещён 28 февраля 1664, Дартмут — 7 августа 1729, Лондон) — английский изобретатель; один из создателей первого теплового (парового) двигателя, известного как паровая машина Ньюкомена.
Леон Н.Купер (англ. Leon Neil Cooper; при рождении — Леон Н. Купчик; 28 февраля 1930, Нью-Йорк, Нью-Йорк — 23 октября 2024, Провиденс) — американский физик, лауреат Нобелевской премии по физике 1972 года (совместно с Джоном Бардиным и Джоном Шриффером) «за создание теории сверхпроводимости, обычно называемой БКШ-теорией». Именем Купера названы электронные пары Купера и BCM теория синаптической пластичности.
1956 — в США патентуется сетевой кабель для компьютеров.
1956 — Джей Форрестер получает патент на магнитно‑ядерную память (core memory). Магнитное сердечниковое ОЗУ стало стандартной памятью компьютеров 1950–60‑х и фактически сделало надёжные электронные компьютеры массовыми; без неё не было бы ни ранних мейнфреймов, ни многих космических систем.
#Biography #Birth_Date #Events #28февраля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
С 21.02 по 27.02
Предыдущий пост(с 14.02 по 20.02)
Воскресный мотивационный пост:
ГЛОБАЛИЗАЦИЯ ЗАКАНЧИВАЕТСЯ
Запись встреч/видео:
7. Введение в распределённую трассировку. OpenTelemetry & Jaeger.
Обучающие статьи:
Раздел 8. Stream API и функциональный стиль
Глава 3: Чистые преобразования и борьба с исключениями
Side Effects — главный враг предсказуемости
(Практика): Чистая агрегация уникальных жанров
Советы по Java:
[Совет по Java #008]
Не ловите Exception или Throwable без крайней необходимости. Ловите максимально конкретные исключения.
[Совет по Java #009]
Используйте Collections.emptyList(), Collections.singletonList() вместо создания новых коллекций, когда нужно вернуть пустой или одноэлементный список.
[Совет по Java #010]
Ключевое слово finally выполняется всегда, даже если в try или catch был return.
Полезные статьи и видео:
JDBC для профи: пулы, batch, транзакции и скрытые риски
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
Предыдущий пост(с 14.02 по 20.02)
Воскресный мотивационный пост:
ГЛОБАЛИЗАЦИЯ ЗАКАНЧИВАЕТСЯ
Запись встреч/видео:
7. Введение в распределённую трассировку. OpenTelemetry & Jaeger.
Обучающие статьи:
Раздел 8. Stream API и функциональный стиль
Глава 3: Чистые преобразования и борьба с исключениями
Side Effects — главный враг предсказуемости
(Практика): Чистая агрегация уникальных жанров
Советы по Java:
[Совет по Java #008]
Не ловите Exception или Throwable без крайней необходимости. Ловите максимально конкретные исключения.
[Совет по Java #009]
Используйте Collections.emptyList(), Collections.singletonList() вместо создания новых коллекций, когда нужно вернуть пустой или одноэлементный список.
[Совет по Java #010]
Ключевое слово finally выполняется всегда, даже если в try или catch был return.
Полезные статьи и видео:
JDBC для профи: пулы, batch, транзакции и скрытые риски
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
👍2
https://t.me/Java_for_beginner_dev/4379
Кто еще не оставил свое мнение? Не стесняйтесь! Для меня и канала это очень важно!
🤝
Кто еще не оставил свое мнение? Не стесняйтесь! Для меня и канала это очень важно!
🤝
Telegram
Java for Beginner
Итак, на фоне уже явных сообщений о блокировке телеграмма, раздумываю о переносе канала.
Недавно обнаружил что можно создать канал в max. Нужен ли он?
Хотел спросить вашего мнения:
- нужно ли вообще переносить канал или вы согласны читать его под vpn/…
Недавно обнаружил что можно создать канал в max. Нужен ли он?
Хотел спросить вашего мнения:
- нужно ли вообще переносить канал или вы согласны читать его под vpn/…
👍2
История технологий сегодня — 29 Февраля/01 марта
ℹ️ Кто родился в этот день
Сеймур Пейперт (Seymour Papert [ˈsimɔɹ ˈpæpɚt]; 29 февраля 1928, Претория, Южная Африка — 31 июля 2016, Блу-Хилл, Мэн, США) — математик, программист, психолог и педагог. Один из основоположников теории искусственного интеллекта, создатель языка Logo (1968), автор конструкционистской теории обучения[6].
Герман Хо́ллерит (англ. Herman Hollerith; 29 февраля 1860 — 17 ноября 1929) — американский инженер и изобретатель. Считается отцом современных автоматических вычислений. Известен как создатель электрической табулирующей системы.
🌐 Знаковые события
1888 — американский инженер Герман Холлерит изобрёл табулятор, первую электрическую счётную машину.
1936 — Нильс Бор предложил теорию составного ядра атома.
1966 — советская автоматическая межпланетная станция Венера-3 впервые в мире достигла поверхности Венеры.
#Biography #Birth_Date #Events #29февраля #01марта
Сеймур Пейперт (Seymour Papert [ˈsimɔɹ ˈpæpɚt]; 29 февраля 1928, Претория, Южная Африка — 31 июля 2016, Блу-Хилл, Мэн, США) — математик, программист, психолог и педагог. Один из основоположников теории искусственного интеллекта, создатель языка Logo (1968), автор конструкционистской теории обучения[6].
Герман Хо́ллерит (англ. Herman Hollerith; 29 февраля 1860 — 17 ноября 1929) — американский инженер и изобретатель. Считается отцом современных автоматических вычислений. Известен как создатель электрической табулирующей системы.
1888 — американский инженер Герман Холлерит изобрёл табулятор, первую электрическую счётную машину.
1936 — Нильс Бор предложил теорию составного ядра атома.
1966 — советская автоматическая межпланетная станция Венера-3 впервые в мире достигла поверхности Венеры.
#Biography #Birth_Date #Events #29февраля #01марта
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
История технологий сегодня — 02 марта
ℹ️ Кто родился в этот день
Князь Бори́с Бори́сович Голи́цын (18 февраля [2 марта] 1862, Санкт-Петербург — 4 [17] мая 1916, Петергоф, Петроградская губерния) — русский физик и геофизик из рода Голицыных, один из основоположников сейсмологии, изобретатель первого электромагнитного сейсмографа (1906).
🌐 Знаковые события
1969 — Первый испытательный полёт французского сверхзвукового пассажирского самолёта «Конкорд».
#Biography #Birth_Date #Events #02марта
Князь Бори́с Бори́сович Голи́цын (18 февраля [2 марта] 1862, Санкт-Петербург — 4 [17] мая 1916, Петергоф, Петроградская губерния) — русский физик и геофизик из рода Голицыных, один из основоположников сейсмологии, изобретатель первого электромагнитного сейсмографа (1906).
1969 — Первый испытательный полёт французского сверхзвукового пассажирского самолёта «Конкорд».
#Biography #Birth_Date #Events #02марта
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
Раздел 8. Stream API и функциональный стиль в Java
Глава 4: Искусство агрегации. Коллекторы и группировки
Коллектор — это рецепт агрегации
Предыдущие главы посвящены преобразованиям потоков: фильтрации, отображению, уплощению. Но поток — эфемерная абстракция. Чтобы извлечь из него ценность, нужно свернуть его в конкретную структуру данных: список, множество, карту, число, строку. Эту свёртку выполняет Collector — центральный интерфейс терминальных операций агрегации.
Collector — не просто утилита для создания List. Это декларативный рецепт, описывающий, как создать контейнер для результатов, как наполнять его элементами, как объединять частичные результаты при параллельном выполнении, и как выполнить финальное преобразование. Понимание его компонентов раскрывает полную мощь Stream API.
Анатомия Collector
Интерфейс Collector<T, A, R> параметризован тремя типами: T — тип элементов входного потока, A — тип промежуточного контейнера аккумуляции, R — тип конечного результата.
Четыре функциональных компонента определяют поведение:
Supplier<A> — фабрика начального состояния. Вызывается один раз для каждого сегмента обработки (при параллельном выполнении — для каждого потока). Создаёт пустой контейнер, готовый к наполнению.
BiConsumer<A, T> accumulator — функция накопления. Добавляет элемент потока в контейнер. Вызывается для каждого элемента, не требует возврата значения — мутирует контейнер.
BinaryOperator<A> — функция слияния. Объединяет два контейнера в один при параллельном выполнении. Критична для корректности parallelStream: без неё частичные результаты останутся разрозненными.
Function<A, R> finisher — финальное преобразование. Превращает контейнер аккумуляции в конечный результат. Для toList() это тождественное преобразование (list -> list), но для сложных коллекторов может быть нетривиальным: например, collectingAndThen оборачивает результат в unmodifiable коллекцию.
Характеристики коллектора: оптимизационные подсказки
Третий параметр Collector — Set<Characteristics> — метаданные, влияющие на исполнение:
CONCURRENT — сигнализирует, что один контейнер может безопасно наполняться из нескольких потоков одновременно. При наличии этой характеристики фреймворк создаёт единственный контейнер и вызывает accumulator из множества потоков без предварительного разделения. Пример: Collector.of(ConcurrentHashMap::new, ..., ..., Characteristics.CONCURRENT).
UNORDERED — гарантия, что порядок элементов в результате не важен. Позволяет оптимизировать параллельное выполнение, устраняя накладные расходы на сохранение порядка при слиянии сегментов. toSet() имеет эту характеристику, toList() — нет.
IDENTITY_FINISH — утверждение, что finisher является тождественным преобразованием (A совпадает с R). Фреймворк может пропустить вызов finisher, возвращая контейнер напрямую. Это оптимизация, но также контракт: если объявить эту характеристику и предоставить нетривиальный finisher, получим ClassCastException при попытке привести A к R.
#Java #для_новичков #beginner #stream_api #Collectors #toMap
Глава 4: Искусство агрегации. Коллекторы и группировки
Коллектор — это рецепт агрегации
Предыдущие главы посвящены преобразованиям потоков: фильтрации, отображению, уплощению. Но поток — эфемерная абстракция. Чтобы извлечь из него ценность, нужно свернуть его в конкретную структуру данных: список, множество, карту, число, строку. Эту свёртку выполняет Collector — центральный интерфейс терминальных операций агрегации.
Collector — не просто утилита для создания List. Это декларативный рецепт, описывающий, как создать контейнер для результатов, как наполнять его элементами, как объединять частичные результаты при параллельном выполнении, и как выполнить финальное преобразование. Понимание его компонентов раскрывает полную мощь Stream API.
Анатомия Collector
Интерфейс Collector<T, A, R> параметризован тремя типами: T — тип элементов входного потока, A — тип промежуточного контейнера аккумуляции, R — тип конечного результата.
Четыре функциональных компонента определяют поведение:
Supplier<A> — фабрика начального состояния. Вызывается один раз для каждого сегмента обработки (при параллельном выполнении — для каждого потока). Создаёт пустой контейнер, готовый к наполнению.
// Для toList(): () -> new ArrayList<T>()
// Для toSet(): () -> new HashSet<T>()
// Для toMap(): () -> new HashMap<K, V>()
BiConsumer<A, T> accumulator — функция накопления. Добавляет элемент потока в контейнер. Вызывается для каждого элемента, не требует возврата значения — мутирует контейнер.
// Для toList(): (list, element) -> list.add(element)
// Для toMap(): (map, element) -> map.put(keyExtractor.apply(element), valueExtractor.apply(element))
BinaryOperator<A> — функция слияния. Объединяет два контейнера в один при параллельном выполнении. Критична для корректности parallelStream: без неё частичные результаты останутся разрозненными.
// Для toList(): (left, right) -> { left.addAll(right); return left; }
// Для toSet(): (left, right) -> { left.addAll(right); return left; }Function<A, R> finisher — финальное преобразование. Превращает контейнер аккумуляции в конечный результат. Для toList() это тождественное преобразование (list -> list), но для сложных коллекторов может быть нетривиальным: например, collectingAndThen оборачивает результат в unmodifiable коллекцию.
// collectingAndThen(toList(), Collections::unmodifiableList)
// finisher: list -> Collections.unmodifiableList(list)
Характеристики коллектора: оптимизационные подсказки
Третий параметр Collector — Set<Characteristics> — метаданные, влияющие на исполнение:
CONCURRENT — сигнализирует, что один контейнер может безопасно наполняться из нескольких потоков одновременно. При наличии этой характеристики фреймворк создаёт единственный контейнер и вызывает accumulator из множества потоков без предварительного разделения. Пример: Collector.of(ConcurrentHashMap::new, ..., ..., Characteristics.CONCURRENT).
UNORDERED — гарантия, что порядок элементов в результате не важен. Позволяет оптимизировать параллельное выполнение, устраняя накладные расходы на сохранение порядка при слиянии сегментов. toSet() имеет эту характеристику, toList() — нет.
IDENTITY_FINISH — утверждение, что finisher является тождественным преобразованием (A совпадает с R). Фреймворк может пропустить вызов finisher, возвращая контейнер напрямую. Это оптимизация, но также контракт: если объявить эту характеристику и предоставить нетривиальный finisher, получим ClassCastException при попытке привести A к R.
#Java #для_новичков #beginner #stream_api #Collectors #toMap
👍4
Конструирование собственного коллектора
Понимание компонентов позволяет создавать специализированные коллекторы. Рассмотрим задачу: собрать строки в единую строку с ограничением длины, добавляя "[truncated]" при превышении.
Этот коллектор демонстрирует все компоненты: мутабельный контейнер (StringBuilderWithFlag), накопление с условной логикой, сложное слияние при параллелизме, финальное преобразование. Характеристика UNORDERED разрешает оптимизации, но требует корректной реализации combiner для любого порядка элементов.
toMap: мощь и ловушки
Коллектор toMap — один из наиболее полезных и опасных. Он превращает поток пар ключ-значение в Map, но содержит скрытые предположения, нарушение которых ведёт к исключениям.
Ловушка первая: коллизии ключей
При отсутствии функции разрешения коллизий toMap бросает IllegalStateException, если встречает дубликат ключа:
Решение — явная функция разрешения (oldValue, newValue) -> ...:
Последний паттерн настолько распространён, что имеет специализированную реализацию: groupingBy(Book::author, toList()).
#Java #для_новичков #beginner #stream_api #Collectors #toMap
Понимание компонентов позволяет создавать специализированные коллекторы. Рассмотрим задачу: собрать строки в единую строку с ограничением длины, добавляя "[truncated]" при превышении.
public static Collector<String, ?, String> joiningWithLimit(int maxLength) {
class StringBuilderWithFlag {
StringBuilder builder = new StringBuilder();
boolean truncated = false;
}
return Collector.of(
StringBuilderWithFlag::new, // supplier
(container, str) -> { // accumulator
if (container.truncated) return;
if (container.builder.length() + str.length() > maxLength) {
container.builder.append("[truncated]");
container.truncated = true;
} else {
if (container.builder.length() > 0) container.builder.append(", ");
container.builder.append(str);
}
},
(left, right) -> { // combiner
if (left.truncated) return left;
if (right.truncated) {
left.builder.append("[truncated]");
left.truncated = true;
return left;
}
if (left.builder.length() + right.builder.length() > maxLength) {
left.builder.append(", ").append(right.builder).append("[truncated]");
left.truncated = true;
} else {
if (left.builder.length() > 0) left.builder.append(", ");
left.builder.append(right.builder);
}
return left;
},
container -> container.builder.toString(), // finisher
Characteristics.UNORDERED // порядок не важен
);
}
// Использование
String summary = tags.stream()
.collect(joiningWithLimit(100));Этот коллектор демонстрирует все компоненты: мутабельный контейнер (StringBuilderWithFlag), накопление с условной логикой, сложное слияние при параллелизме, финальное преобразование. Характеристика UNORDERED разрешает оптимизации, но требует корректной реализации combiner для любого порядка элементов.
toMap: мощь и ловушки
Коллектор toMap — один из наиболее полезных и опасных. Он превращает поток пар ключ-значение в Map, но содержит скрытые предположения, нарушение которых ведёт к исключениям.
Ловушка первая: коллизии ключей
При отсутствии функции разрешения коллизий toMap бросает IllegalStateException, если встречает дубликат ключа:
// Опасно: бросит исключение при повторяющемся авторе
Map<String, Book> bookByAuthor = books.stream()
.collect(toMap(Book::author, book -> book)); // Crash на второй книге того же автора
Решение — явная функция разрешения (oldValue, newValue) -> ...:
// Сохраняем первую встреченную книгу автора
Map<String, Book> firstByAuthor = books.stream()
.collect(toMap(
Book::author,
book -> book,
(existing, replacement) -> existing // Игнорируем повторы
));
// Сохраняем последнюю, обновляем
Map<String, Book> lastByAuthor = books.stream()
.collect(toMap(
Book::author,
book -> book,
(oldBook, newBook) -> newBook // Перезаписываем
));
// Агрегируем: список всех книг автора
Map<String, List<Book>> allByAuthor = books.stream()
.collect(toMap(
Book::author,
book -> new ArrayList<>(List.of(book)), // Создаём список из одной книги
(existingList, newList) -> {
existingList.addAll(newList); // Добавляем к существующему
return existingList;
}
));
Последний паттерн настолько распространён, что имеет специализированную реализацию: groupingBy(Book::author, toList()).
#Java #для_новичков #beginner #stream_api #Collectors #toMap
👍3🔥2