IDEA: Code with me
Парное программирование - agile практика, когда два человека сидят за одним компьютером и работают над задачей. Один пишет код, другой - наблюдает.
Если партнёры хорошо сработаются, то код получится проще, а ошибок будет меньше.
Intellij IDEA недавно выпустила классный плагин Code with me, и теперь парным программированием можно заняться и на удалёнке.
Найти его легко: File → Settings → Plugins → Marketplace → Code with me
Новая плашка появится рядом с иконками Run/Debug. Можно отправить ссылку коллеге и вместе работать над задачей👯
#idea
Парное программирование - agile практика, когда два человека сидят за одним компьютером и работают над задачей. Один пишет код, другой - наблюдает.
Если партнёры хорошо сработаются, то код получится проще, а ошибок будет меньше.
Intellij IDEA недавно выпустила классный плагин Code with me, и теперь парным программированием можно заняться и на удалёнке.
Найти его легко: File → Settings → Plugins → Marketplace → Code with me
Новая плашка появится рядом с иконками Run/Debug. Можно отправить ссылку коллеге и вместе работать над задачей👯
#idea
По статистике 64% приложений сидят на java 8, а самая популярная фича java 8 - это Stream API.
Самая запутанная часть Stream API - коллекторы, о них я написала лонгрид в 3 частях.
Часть 1: обзор и простые коллекторы
Часть 2: сложные коллекторы
Часть 3: особенности дизайна
Рассмотрим почти все, что есть в JDK. Без внимания останутся collectingAndThen и teeing(Java 12). Не нашла ни одного кейса, где они полезны🤷
Самая запутанная часть Stream API - коллекторы, о них я написала лонгрид в 3 частях.
Часть 1: обзор и простые коллекторы
Часть 2: сложные коллекторы
Часть 3: особенности дизайна
Рассмотрим почти все, что есть в JDK. Без внимания останутся collectingAndThen и teeing(Java 12). Не нашла ни одного кейса, где они полезны🤷
Коллекторы Stream API, часть 1: простые методы
В первой части повторим основы - из чего состоит стрим и что такое коллектор. Каждый код со Stream API состоит из 3х частей:
1️⃣ Получение стрима
2️⃣ Преобразования
3️⃣ Терминальная операция
1️⃣
Коллекторы - статические методы класса Collectors, которые возвращают аргумент для метода collect. Я буду опускать основной класс и вместо Collectors.counting() будут писать counting(). Чтобы было короче.
Чаще всего элементы стрима собирают в обычную коллекцию:
▪️toCollection, toList, toSet
▪️toUnmodifiableSet, toUnmodifiableList
▫️counting
▫️averagingToInt / Long / Double
▫️joining
▫️maxBy, minBy
▫️reducing
▫️summingInt / Long / Double
▫️summarizingInt / Long / Double
Интересны здесь только два метода:
🔸 joining
Соединяет элементы в одну строку:
Возвращает объект IntSummaryStatistics, который содержит минимум, максимум, среднее, количество элементов и их сумму.
Остальные методы сами по себе бесполезны, так как есть простые аналоги:
Они нужны в коллекторах groupingBy и partitioningBy, про них подробно поговорим завтра.
#core
В первой части повторим основы - из чего состоит стрим и что такое коллектор. Каждый код со Stream API состоит из 3х частей:
1️⃣ Получение стрима
2️⃣ Преобразования
3️⃣ Терминальная операция
1️⃣
list.stream()
2️⃣ .filter(e -> e != 3)
3️⃣ .count();
Терминальная операция collect собирает элементы стрима в другую структуру данных. Все подробности передаются через аргумент:collect(Collector collector) Коллекторы - статические методы класса Collectors, которые возвращают аргумент для метода collect. Я буду опускать основной класс и вместо Collectors.counting() будут писать counting(). Чтобы было короче.
Чаще всего элементы стрима собирают в обычную коллекцию:
▪️toCollection, toList, toSet
▪️toUnmodifiableSet, toUnmodifiableList
Set res=students.stream()Ещё одна группа - коллекторы, которые возвращают одно значение:
.filter(…).collect(toSet())
▫️counting
▫️averagingToInt / Long / Double
▫️joining
▫️maxBy, minBy
▫️reducing
▫️summingInt / Long / Double
▫️summarizingInt / Long / Double
Интересны здесь только два метода:
🔸 joining
Соединяет элементы в одну строку:
chars.stream().collect(joining("-"));
// ['a','b','c'] → a-b-c
🔸summarizingIntВозвращает объект IntSummaryStatistics, который содержит минимум, максимум, среднее, количество элементов и их сумму.
Остальные методы сами по себе бесполезны, так как есть простые аналоги:
list.stream().collect(counting())Коллекторы mapping, flatMapping и filtering применяют функцию к элементам перед отправкой в другой коллектор.
// аналог
list.stream().count()
Set<Long> ids = …Использовать их напрямую тоже смысла нет. Проще применить к элементам map, flatmap или filter, а потом собрать результаты:
collect(mapping(Student::id, toSet())
map(Student::id).collect(toSet())❓Зачем нужны эти методы?
Они нужны в коллекторах groupingBy и partitioningBy, про них подробно поговорим завтра.
#core
👍5❤1
Вы поручили джуниору задачу, в которой нужно написать пару строк на Stream API. Джуниор неопытный, но старательный, и принёс 5 вариантов решения. Все, кроме одного, приводят к одному результату. Какой код ошибочный?
Коллекторы Stream API, часть 2: сложные коллекторы
В этой части разберёмся в коллекторах toMap, groupingBy и partitioningBy. Уверена, года через 3 их будут спрашивать на занудных собеседованиях.
Будем тренироваться на классе Student из вопроса перед постом. У него есть id, имя, город и список оценок.
🔸toMap, toConcurrentMap
Цель понятна: уложить элементы стрима в map. Указываем функцию для ключа и для значения:
Если ключи повторяются, то вылетит IllegalStateException. Чтобы этого избежать, укажите третьим параметром, как объединять значения:
Похоже на группировку по городу, но это не она. В результате получается одно значение, а не группа.
🔸groupingBy
Настоящую группировку делает коллектор groupingBy:
▫️Города и количество студентов:
▫️ID студента и средняя оценка за экзамены:
...
Для этой задачи группировка не подходит. У одного студента только одна средняя оценка, количество итоговых элементов = количеству исходных. Группировать нечего, поэтому используем toMap:
🔸partitioningBy
Метод делит элементы на две группы по заданному условию. Результат - map с двумя ключами - true и false.
▫️Делим студентов на москвичей и жителей других городов:
Вы поручили джуниору посчитать среди студентов тех, кто не сдал ни одного экзамена. Вариант 3 предлагает применить к набору студентов метод Integer::longValue, что невозможно. Остальные варианты переводят каждого студента в число 1 и суммируют все значения. Ошибочный ответ - 3.
#core
В этой части разберёмся в коллекторах toMap, groupingBy и partitioningBy. Уверена, года через 3 их будут спрашивать на занудных собеседованиях.
Будем тренироваться на классе Student из вопроса перед постом. У него есть id, имя, город и список оценок.
🔸toMap, toConcurrentMap
Цель понятна: уложить элементы стрима в map. Указываем функцию для ключа и для значения:
collect(toMap(Student::id, Student::name)) Если ключи повторяются, то вылетит IllegalStateException. Чтобы этого избежать, укажите третьим параметром, как объединять значения:
collect(toMap(Student::city,["Москва":"Антон Аня Эдуард"]
Student::name,
(a,b) -> a+" "+b))
Похоже на группировку по городу, но это не она. В результате получается одно значение, а не группа.
🔸groupingBy
Настоящую группировку делает коллектор groupingBy:
Map<String, List<Student>>=…По умолчанию сгруппированные элементы объединяются в список. Чтобы получить что-нибудь другое, передайте в метод другой коллектор:
collect(groupingBy (Student::city))
groupingBy(Student::city, toSet())Здесь нам наконец пригодятся коллекторы из предыдущего поста, которые подставим во второй аргумент.
▫️Города и количество студентов:
groupingBy(Student::city, counting())▫️Города и имена студентов:
groupingBy(Student::city,Передаём в groupingBy функцию для ключей и коллектор mapping для значений. Он же принимает другой коллектор toSet, чтобы было понятно, куда складывать результат.
mapping(Student::name, toSet()))
▫️ID студента и средняя оценка за экзамены:
...
Для этой задачи группировка не подходит. У одного студента только одна средняя оценка, количество итоговых элементов = количеству исходных. Группировать нечего, поэтому используем toMap:
toMap(Student::id,Вместо расчёт() - километр кода. Подсчёт среднего недоступен в интерфейсе Stream, а удобных методов перевода List<Integer> в IntStream нет.
s -> s.marks().stream().расчёт())
🔸partitioningBy
Метод делит элементы на две группы по заданному условию. Результат - map с двумя ключами - true и false.
▫️Делим студентов на москвичей и жителей других городов:
Map<Boolean,Set<Student>>…Вместо toSet можно подставить другой коллектор. Посчитаем количество студентов:
partitioningBy(s-> s.city().equals("Moscow"), toSet())
partitioningBy(s-> s.city().equals("Moscow"), counting())
Не очень понятно, зачем нужен partitioningBy. groupingBy даёт такой же результат, но на 2 символа короче:groupingBy(s-> s.city().equals("Moscow"), counting())
❓Ответ на вопрос перед постомВы поручили джуниору посчитать среди студентов тех, кто не сдал ни одного экзамена. Вариант 3 предлагает применить к набору студентов метод Integer::longValue, что невозможно. Остальные варианты переводят каждого студента в число 1 и суммируют все значения. Ошибочный ответ - 3.
#core
👍3
Коллекторы Stream API, часть 3: дизайн
Вчера мы разбирали groupingBy и partitioningBy. У многих возникла мысль, что лучше держаться от группировок подальше. Коллекторы выглядят неважно относительно других методов Stream API:
▪️Многословные: collect(Collectors.toSet())
▪️Вложенные коллекторы
▪️Дублированные методы map, flatMap, max, min - 18 штук
Итог: плохая читаемость и желание написать всё через цикл for.
Почему так получилось? Разберёмся в этом посте.
Выделим три вопроса:
1️⃣ Почему вместо toSet() такой сложный collect(Collectors.toSet())?
2️⃣ Почему группировка - терминальная операция?
3️⃣ Зачем в классе 18 неполноценных методов и вложенные коллекторы?
Разберём по порядку.
1️⃣ Метод collect и класс Collectors.
Цель Stream API - удобная работа с данными. За интерфейсом Stream может быть любой источник данных: список, строка, коллекция или файл. Сторонние библиотеки могут реализовать свой источник данных и работать с ним стандартными средствами Stream API.
В обратную сторону это тоже работает. Пользователь может преобразовать стрим в свою структуру данных, для этого в интерфейсе Stream метод collect(Collector).
А ещё источник данных и конечная структура данных - разные сущности, поэтому в интерфейсе Stream нет методов toSet(), toList(). Single Responsibility.
2️⃣ Почему группировка - терминальная операция?
С точки зрения пользователя группировка - просто преобразование. После группировки элементы можно фильтровать, менять и так далее.
Дизайн Stream API для этого не подходит. Источник данных делится на части, элементы обрабатываются независимо, иногда в разных потоках.
Терминальная операция - единственное место, где потоки объединяются и вычисляется общий результат. Посчитать количество, найти элемент, объединить в коллекцию - это конечные точки в обработке.
Группировка работает со всеми элементами, и в терминах Stream API это терминальная операция, дальше работать со стримом нельзя.
3️⃣ Вложенные коллекторы и 18 методов для groupingBy
Кстати, разработчики JDK понимают, что группировка - это преобразование данных, а вовсе не финальная точка.
Что может понадобиться программисту?
🔸Указать итоговый тип данных.
🔸Преобразовать итоговые данные. Это сложно сделать напрямую, потому что универсального интерфейса для filter, map и average нет.
Для решения этих задач groupingBy получил аргумент-коллектор, а Collectors пополнился 18 методами-обёртками над map, flatMap, filter и average .
На мой взгляд получилось сложновато, но это спорный вопрос. А какие вам нравятся библиотеки?
💅 - Удобные методы для целевых кейсов, но с ограничениями
💪 - Максимум возможностей и кастомизации
#core
Вчера мы разбирали groupingBy и partitioningBy. У многих возникла мысль, что лучше держаться от группировок подальше. Коллекторы выглядят неважно относительно других методов Stream API:
▪️Многословные: collect(Collectors.toSet())
▪️Вложенные коллекторы
▪️Дублированные методы map, flatMap, max, min - 18 штук
Итог: плохая читаемость и желание написать всё через цикл for.
Почему так получилось? Разберёмся в этом посте.
Выделим три вопроса:
1️⃣ Почему вместо toSet() такой сложный collect(Collectors.toSet())?
2️⃣ Почему группировка - терминальная операция?
3️⃣ Зачем в классе 18 неполноценных методов и вложенные коллекторы?
Разберём по порядку.
1️⃣ Метод collect и класс Collectors.
Цель Stream API - удобная работа с данными. За интерфейсом Stream может быть любой источник данных: список, строка, коллекция или файл. Сторонние библиотеки могут реализовать свой источник данных и работать с ним стандартными средствами Stream API.
В обратную сторону это тоже работает. Пользователь может преобразовать стрим в свою структуру данных, для этого в интерфейсе Stream метод collect(Collector).
А ещё источник данных и конечная структура данных - разные сущности, поэтому в интерфейсе Stream нет методов toSet(), toList(). Single Responsibility.
2️⃣ Почему группировка - терминальная операция?
С точки зрения пользователя группировка - просто преобразование. После группировки элементы можно фильтровать, менять и так далее.
Дизайн Stream API для этого не подходит. Источник данных делится на части, элементы обрабатываются независимо, иногда в разных потоках.
Терминальная операция - единственное место, где потоки объединяются и вычисляется общий результат. Посчитать количество, найти элемент, объединить в коллекцию - это конечные точки в обработке.
Группировка работает со всеми элементами, и в терминах Stream API это терминальная операция, дальше работать со стримом нельзя.
3️⃣ Вложенные коллекторы и 18 методов для groupingBy
Кстати, разработчики JDK понимают, что группировка - это преобразование данных, а вовсе не финальная точка.
Что может понадобиться программисту?
🔸Указать итоговый тип данных.
🔸Преобразовать итоговые данные. Это сложно сделать напрямую, потому что универсального интерфейса для filter, map и average нет.
Для решения этих задач groupingBy получил аргумент-коллектор, а Collectors пополнился 18 методами-обёртками над map, flatMap, filter и average .
На мой взгляд получилось сложновато, но это спорный вопрос. А какие вам нравятся библиотеки?
💅 - Удобные методы для целевых кейсов, но с ограничениями
💪 - Максимум возможностей и кастомизации
#core
👍2❤1
Сегодня начнётся онлайн конференция JLove❤️
Бесплатная!
Расписание уже готово, не забудьте подставить свой часовой пояс.
С удовольствием рассказываю о конфе второй раз: классные эксперты и получасовые доклады на любой вкус. Плюс общение со спикерами в чате, группы по интересам, афтепати, призы и подарки.
Зарегистрироваться: jlove.konfy.care
Бесплатная!
Расписание уже готово, не забудьте подставить свой часовой пояс.
С удовольствием рассказываю о конфе второй раз: классные эксперты и получасовые доклады на любой вкус. Плюс общение со спикерами в чате, группы по интересам, афтепати, призы и подарки.
Зарегистрироваться: jlove.konfy.care
Паттерн проектирования, который в соответствии с принципом единственной обязанности передает другому объекту ответственность построения требуемых ему зависимостей внешнему, специально предназначенному для этого общему механизму
Anonymous Poll
40%
Dependency injection
9%
Dependency invertion
36%
Inversion of Control
16%
Factory Method
👍2
DI vs DI vs IoC
Знаете, почему сложно внедрять всякие принципы и лучшие практики? Они рождаются из конкретных ситуаций и решают конкретные проблемы. Чтобы передать эти ценнейшие знания, ситуацию приходится абстрагировать и в итоге получается набор терминов. Что с ними делать - непонятно, слишком абстрактно.
Сегодня разберём разницу между Dependency injection, Dependency invertion и Inversion of Control. Понимание пригодится на собеседованиях, при чтении статей по дизайну и архитектуре. Плюс поймёте, как хорошо вы программируете и какие проблемы решаете, даже не задумываясь.
Будем разбираться на простом примере.
Точка А: Сервис Service записывает логи в файл с помощью класса FileLogger:
1️⃣ Dependency injection
это когда компоненты создаются не внутри класса, а передаются в конструкторах или сеттерах. Перенесём инициализацию логгера в конструктор:
2️⃣ Dependency invertion
Буква D в аббревиатуре SOLID, формулировка состоит из двух частей:
▫️Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
▫️Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракции.
Суть: пусть сервис работает не с конкретным логгером, а с интерфейсом
✅ Реализацию легко заменить
✅ Оба класса проще тестировать
Почему используется слово "абстракция"? Группу методов можно выделить в интерфейс, в абстрактный класс и даже в обычный класс. Но интерфейс самый подходящий вариант.
3️⃣ IoC - Inversion of Control
В маленьких программах жизнь начинается в методе main(). Программист создаёт объекты, вызывает методы, все шаги явно прописаны.
Inversion of Control - это когда ход выполнения программы задаёт фреймворк. Spring смотрит на классы и аннотации, а затем создаёт объекты, связывает их вместе и не даёт программе завершиться.
✅ Низкая связность - код легко менять, тестировать и переиспользовать
Spring создаёт обёртки классов и работает через Dependency Injection. Можно и по-другому: через паттерн фабричный метод, стратегия или сервис локатор.
⚔️Историческая справка.
Сервис локатор иногда встречается в легаси проектах. Это когда компоненты создаются в классе ServiceLocator, а другие классы получают к ним доступ через статические методы.
🔸Dependency injection - класс не создаёт компоненты напрямую, они передаются через конструктор или сеттер
🔸Dependency invertion - класс работает с другими компонентами через интерфейс
🔸Inversion of Control - ход программы задаёт фреймворк. Соединять компоненты может Dependency injection, фабричный метод, стратегия или сервис локатор.
❗️Ответ на вопрос перед постом:
Это словоблудие относится к Dependency injection
#теория
Знаете, почему сложно внедрять всякие принципы и лучшие практики? Они рождаются из конкретных ситуаций и решают конкретные проблемы. Чтобы передать эти ценнейшие знания, ситуацию приходится абстрагировать и в итоге получается набор терминов. Что с ними делать - непонятно, слишком абстрактно.
Сегодня разберём разницу между Dependency injection, Dependency invertion и Inversion of Control. Понимание пригодится на собеседованиях, при чтении статей по дизайну и архитектуре. Плюс поймёте, как хорошо вы программируете и какие проблемы решаете, даже не задумываясь.
Будем разбираться на простом примере.
Точка А: Сервис Service записывает логи в файл с помощью класса FileLogger:
class FileLogger {…}
class Service {
FileLogger logger=new FileLogger();
}
Сделаем код чуть лучше:1️⃣ Dependency injection
это когда компоненты создаются не внутри класса, а передаются в конструкторах или сеттерах. Перенесём инициализацию логгера в конструктор:
class Service {
FileLogger logger;
Service (FileLogger logger) {
this.logger= logger;
}
}
✅ Класс не занимается инициализацией логгера2️⃣ Dependency invertion
Буква D в аббревиатуре SOLID, формулировка состоит из двух частей:
▫️Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
▫️Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракции.
Суть: пусть сервис работает не с конкретным логгером, а с интерфейсом
interface Logger {…}
class FileLogger implements Logger {…}
class Service {
Logger logger=new FileLogger();
}
✅ В интерфейсе доступно меньше методов, поэтому его проще использовать✅ Реализацию легко заменить
✅ Оба класса проще тестировать
Почему используется слово "абстракция"? Группу методов можно выделить в интерфейс, в абстрактный класс и даже в обычный класс. Но интерфейс самый подходящий вариант.
3️⃣ IoC - Inversion of Control
В маленьких программах жизнь начинается в методе main(). Программист создаёт объекты, вызывает методы, все шаги явно прописаны.
Inversion of Control - это когда ход выполнения программы задаёт фреймворк. Spring смотрит на классы и аннотации, а затем создаёт объекты, связывает их вместе и не даёт программе завершиться.
@Component class FileLogger {…}
@Component class Service {
@Autowired
FileLogger logger;
}
✅ Меньше скучного кода✅ Низкая связность - код легко менять, тестировать и переиспользовать
Spring создаёт обёртки классов и работает через Dependency Injection. Можно и по-другому: через паттерн фабричный метод, стратегия или сервис локатор.
⚔️Историческая справка.
Сервис локатор иногда встречается в легаси проектах. Это когда компоненты создаются в классе ServiceLocator, а другие классы получают к ним доступ через статические методы.
class ServiceLocator {
private static Logger logger=…
public static Logger getLogger() {
return logger;
}
}
public class Service {
private Logger logger = ServiceLocator.getLogger();
}
Резюме:🔸Dependency injection - класс не создаёт компоненты напрямую, они передаются через конструктор или сеттер
🔸Dependency invertion - класс работает с другими компонентами через интерфейс
🔸Inversion of Control - ход программы задаёт фреймворк. Соединять компоненты может Dependency injection, фабричный метод, стратегия или сервис локатор.
❗️Ответ на вопрос перед постом:
Это словоблудие относится к Dependency injection
#теория
👍4
IDEA: 4 метода для рефакторинга
IDEA - очень продвинутая IDE . Методов рефакторинга так много, что у них даже отдельная вкладка в меню. На каждом проекте точно пригодится:
1️⃣ Переименовать класс, метод, переменную или файл
Правой кнопкой по имени → Refactor → Rename
Имя изменится везде, где упоминается сущность.
2️⃣ Выделить константу
"Магические числа" в коде - плохая практика, лучше читаются именованные константы.
Правой кнопкой по числу → Refactor → Introduce Constant
Выделяем нужные строки → правый щелчок мышки → Refactor → Extract Method...
И наоборот
4️⃣ Убрать лишние методы и переменные, "уплотнить" код
Правый щёлк → Refactor → Inline Method/Inline Variable
IDEA - очень продвинутая IDE . Методов рефакторинга так много, что у них даже отдельная вкладка в меню. На каждом проекте точно пригодится:
1️⃣ Переименовать класс, метод, переменную или файл
Правой кнопкой по имени → Refactor → Rename
Имя изменится везде, где упоминается сущность.
2️⃣ Выделить константу
"Магические числа" в коде - плохая практика, лучше читаются именованные константы.
Правой кнопкой по числу → Refactor → Introduce Constant
❌ for(int i=0;i<100;i++)3️⃣ Перенести код в отдельный метод
✅ for(int i=0;i<HLIMIT;i++)
Выделяем нужные строки → правый щелчок мышки → Refactor → Extract Method...
И наоборот
4️⃣ Убрать лишние методы и переменные, "уплотнить" код
Правый щёлк → Refactor → Inline Method/Inline Variable
Switch: успеть до 30-ти
Сегодняшняя тема - история успеха оператора switch. Он появился в java 1.0, и с тех пор оставался в неизменном виде. В 2018 разработчики JDK смахнули пыль с кодовой базы switch, и теперь над ним идёт активная работа.
Почему о нём вспомнили, и как меняется switch? Рассмотрим по порядку.
1️⃣ Часть 1. Эпоха ООП
Java работает с объектами уже 25 лет. В этих условиях switch редко встречается в коде и часто считается плохой практикой.
Почему? Всё дело в сценарии использования:
Почему switch так себе вариант?
❌Сложный код. Работа со всеми состояниями в одной куче.
❌Дублирование кода. Если поле проверяется несколько раз, то менять такой код неудобно и легко ошибиться.
Для объекта с понятным набором состояний switch лучше заменить на полиморфные методы. Это несложный рефакторинг - пример1, пример2.
Цель ООП - смоделировать реальный мир через объекты. Главное здесь - объекты взаимодействуют и меняют состояние друг друга. В таких условиях switch проигрывает полиморфным методам и редко используется.
2️⃣ Часть 2. Эра функциональности
Сегодня для бизнеса недостаточно простой автоматизации. Основной задачей становится работа с данными.
Они не меняются, приходят из разных источников в разных форматах. Потоки данных идут через множество сервисов. Каждый сервис берёт данные, которые понимает, а остальные игнорирует. Строить иерархии классов для такой задачи кажется лишним и сложным.
Поэтому внедряются подходы из фунциональных языков. Один из них - pattern matching, а switch идеально подходит для его реализации. Паттерн - некоторое условие для переменной:
▫️Равна заданной константе
▫️Имеет определённый тип
▫️Подходит под регулярное выражение
Если произошёл мэтч, то для переменной сразу доступна доп.информация. Например, она приводится к нужному типу:
Switch 2000 работает с объектами, у которых меняется состояние. Вокруг этого строится бизнес-логика.
Switch 2021 работает с неизменными данными и помогает найти среди них подходящие. В следующем году выйдет java 17, и switch будет появляться в коде чаще.
Вот так один непопулярный оператор в JDK нашёл своё место в мире спустя 23 года⭐️
Сегодняшняя тема - история успеха оператора switch. Он появился в java 1.0, и с тех пор оставался в неизменном виде. В 2018 разработчики JDK смахнули пыль с кодовой базы switch, и теперь над ним идёт активная работа.
Почему о нём вспомнили, и как меняется switch? Рассмотрим по порядку.
1️⃣ Часть 1. Эпоха ООП
Java работает с объектами уже 25 лет. В этих условиях switch редко встречается в коде и часто считается плохой практикой.
Почему? Всё дело в сценарии использования:
switch (user.getState()) {
case NEW: …
case CONFIRMED: …
case BANNED: … }
Switch - это не просто набор нескольких if. У объекта user 3 статуса. Список чётко определен, статусы не пересекаются между собой.Почему switch так себе вариант?
❌Сложный код. Работа со всеми состояниями в одной куче.
❌Дублирование кода. Если поле проверяется несколько раз, то менять такой код неудобно и легко ошибиться.
Для объекта с понятным набором состояний switch лучше заменить на полиморфные методы. Это несложный рефакторинг - пример1, пример2.
Цель ООП - смоделировать реальный мир через объекты. Главное здесь - объекты взаимодействуют и меняют состояние друг друга. В таких условиях switch проигрывает полиморфным методам и редко используется.
2️⃣ Часть 2. Эра функциональности
Сегодня для бизнеса недостаточно простой автоматизации. Основной задачей становится работа с данными.
Они не меняются, приходят из разных источников в разных форматах. Потоки данных идут через множество сервисов. Каждый сервис берёт данные, которые понимает, а остальные игнорирует. Строить иерархии классов для такой задачи кажется лишним и сложным.
Поэтому внедряются подходы из фунциональных языков. Один из них - pattern matching, а switch идеально подходит для его реализации. Паттерн - некоторое условие для переменной:
▫️Равна заданной константе
▫️Имеет определённый тип
▫️Подходит под регулярное выражение
Если произошёл мэтч, то для переменной сразу доступна доп.информация. Например, она приводится к нужному типу:
switch (animal) {
case Cat c → c.putToBox();
case Dog d → d.train(); }
Итак, в чём разница между switch в 2000 и switch в 2021?Switch 2000 работает с объектами, у которых меняется состояние. Вокруг этого строится бизнес-логика.
Switch 2021 работает с неизменными данными и помогает найти среди них подходящие. В следующем году выйдет java 17, и switch будет появляться в коде чаще.
Вот так один непопулярный оператор в JDK нашёл своё место в мире спустя 23 года⭐️
👍2
Спасибо за этот год!
Завтра новый год, это отличный повод сказать нечто важное.
Ребята, вы супер! Спасибо, что читаете мои нудные посты без картинок, помогаете найти ошибки и задаёте интересные вопросы. Благодаря вам блог ещё жив❤️
В 2020 году на канале вышло 85 постов, которые в сумме набрали 475к просмотров! Я в шоке и постараюсь в 2021 не сбавлять обороты.
Желаю всем в следующем году +1 грейд, интересные проекты и яркую жизнь вне работы🔥
Завтра новый год, это отличный повод сказать нечто важное.
Ребята, вы супер! Спасибо, что читаете мои нудные посты без картинок, помогаете найти ошибки и задаёте интересные вопросы. Благодаря вам блог ещё жив❤️
В 2020 году на канале вышло 85 постов, которые в сумме набрали 475к просмотров! Я в шоке и постараюсь в 2021 не сбавлять обороты.
Желаю всем в следующем году +1 грейд, интересные проекты и яркую жизнь вне работы🔥
Гороскоп на 2021
Всем известно, что астрология играет важную роль в IT. Двухнедельный спринт - это ровно половина лунного цикла. Идеальный размер команды равен количеству планет солнечной системы. Премии рассчитываются по астральным коэффициентам.
Вот что говорят звёзды про 2021 год:
♈️ Овен
Металлический Бык симпатизирует Овнам, поэтому все инициативы будут удачны, особенно зимой, весной, летом и осенью. Будьте активны на ретро, предлагайте новые фичи и подходы, возьмите под наставничество стажёров. В сентябре ожидайте наплыв писем от HR.
♉️ Телец
В год Быка Тельцы нацелены на быстрый карьерный взлёт. Подтяните пробелы и обсудите с тимлидом возможности роста. В этом году звёзды раскрутили ваш потенциал до максимума. В августе будьте осторожнее с
♊️ Близнецы
Год будет спокойным и приятным. В прошлом году вы много работали, в 2021 выделяйте больше времени на отдых. Качество жизни и работы только улучшится. Самое время взяться за большие и фундаментальные книги, которые вы долго откладывали.
♋️ Рак
Откажитесь от лишней эмоциональности, она может помешать вашему развитию. Подтяните DevOps, в этом году он вам пригодится. Сложные задачи ждут вас в середине лета, но они дадут нужный стимул для дальнейшего роста.
♌️ Лев
В этом году удача не на вашей стороне, придётся много работать. Хотите успеха — начните сейчас, чтобы уже весной видеть первые результаты. Смотрите на вещи шире. Почитайте книжки по архитектуре, посмотрите видео с конференций HighLoad и ArchDays. В апреле высокий риск простудиться, одевайтесь теплее.
♍️ Дева
Год будет богат на свежие идеи и начинания. Начните то, что давно откладывали. Интересные идеи, вопросы и решения придут в самый неожиданный момент. Сохраняйте их сразу - запишите в блокнот, голосовое сообщение, как угодно, а то улетят. Обязательно делайте бэкапы и резервные копии.
♎️ Весы
В этом году у Весов будет шанс попробовать себя в руководящей роли. Готовьтесь заранее - почитайте статьи по управлению людьми и проектами. Подтяните тайм-менеджмент, иначе времени на хобби и внерабочие активности совсем не останется.
♏️ Скорпион
В этом году вы будете на переднем фронте. Вас ждут горячие фиксы и спасение команды перед дедлайном. Будет сложно, но Сатурн вам поможет. Помните об отдыхе и набирайтесь сил в спокойное время.
♐️ Стрелец
Пересмотрите приоритеты в жизни, попробуйте смежные IT направления. Возможно позиция тимлида, менеджера или аналитика раскроют вас с новой стороны. В этом году особую важность приобретут межличностные отношения. Октябрь станет самым прибыльным месяцем в году.
♑️ Козерог
Для вас 2021 год — это борьба со своими слабостями. Уделяйте больше внимания тестированию и самопроверке. Разберитесь с NoSQL: книга для начинающих, для продолжающих. Хорошей идеей будет сходить на каток и покататься на ватрушках.
♒️ Водолей
Лучшее время для решительных шагов — начало весны. Много возможностей принесёт нетворкинг - поддерживайте тёплые отношения с коллегами, участвуйте в конференциях, митапах и корпоративных мероприятиях. Идите в ногу со временем - освойте Kotlin и Cloud computing.
♓️ Рыбы
Наступает период, когда пора применить все накопленные знания. А возможности для этого обязательно будут. Меркурий помешает сделать важные задачи в срок, поэтому закладывайте на выполнение в 2 раза больше времени. Лето подкинет массу интересных вариантов для отдыха.
Дружите со звёздами, они плохого не посоветуют💫
Всем известно, что астрология играет важную роль в IT. Двухнедельный спринт - это ровно половина лунного цикла. Идеальный размер команды равен количеству планет солнечной системы. Премии рассчитываются по астральным коэффициентам.
Вот что говорят звёзды про 2021 год:
♈️ Овен
Металлический Бык симпатизирует Овнам, поэтому все инициативы будут удачны, особенно зимой, весной, летом и осенью. Будьте активны на ретро, предлагайте новые фичи и подходы, возьмите под наставничество стажёров. В сентябре ожидайте наплыв писем от HR.
♉️ Телец
В год Быка Тельцы нацелены на быстрый карьерный взлёт. Подтяните пробелы и обсудите с тимлидом возможности роста. В этом году звёзды раскрутили ваш потенциал до максимума. В августе будьте осторожнее с
git push --force.♊️ Близнецы
Год будет спокойным и приятным. В прошлом году вы много работали, в 2021 выделяйте больше времени на отдых. Качество жизни и работы только улучшится. Самое время взяться за большие и фундаментальные книги, которые вы долго откладывали.
♋️ Рак
Откажитесь от лишней эмоциональности, она может помешать вашему развитию. Подтяните DevOps, в этом году он вам пригодится. Сложные задачи ждут вас в середине лета, но они дадут нужный стимул для дальнейшего роста.
♌️ Лев
В этом году удача не на вашей стороне, придётся много работать. Хотите успеха — начните сейчас, чтобы уже весной видеть первые результаты. Смотрите на вещи шире. Почитайте книжки по архитектуре, посмотрите видео с конференций HighLoad и ArchDays. В апреле высокий риск простудиться, одевайтесь теплее.
♍️ Дева
Год будет богат на свежие идеи и начинания. Начните то, что давно откладывали. Интересные идеи, вопросы и решения придут в самый неожиданный момент. Сохраняйте их сразу - запишите в блокнот, голосовое сообщение, как угодно, а то улетят. Обязательно делайте бэкапы и резервные копии.
♎️ Весы
В этом году у Весов будет шанс попробовать себя в руководящей роли. Готовьтесь заранее - почитайте статьи по управлению людьми и проектами. Подтяните тайм-менеджмент, иначе времени на хобби и внерабочие активности совсем не останется.
♏️ Скорпион
В этом году вы будете на переднем фронте. Вас ждут горячие фиксы и спасение команды перед дедлайном. Будет сложно, но Сатурн вам поможет. Помните об отдыхе и набирайтесь сил в спокойное время.
♐️ Стрелец
Пересмотрите приоритеты в жизни, попробуйте смежные IT направления. Возможно позиция тимлида, менеджера или аналитика раскроют вас с новой стороны. В этом году особую важность приобретут межличностные отношения. Октябрь станет самым прибыльным месяцем в году.
♑️ Козерог
Для вас 2021 год — это борьба со своими слабостями. Уделяйте больше внимания тестированию и самопроверке. Разберитесь с NoSQL: книга для начинающих, для продолжающих. Хорошей идеей будет сходить на каток и покататься на ватрушках.
♒️ Водолей
Лучшее время для решительных шагов — начало весны. Много возможностей принесёт нетворкинг - поддерживайте тёплые отношения с коллегами, участвуйте в конференциях, митапах и корпоративных мероприятиях. Идите в ногу со временем - освойте Kotlin и Cloud computing.
♓️ Рыбы
Наступает период, когда пора применить все накопленные знания. А возможности для этого обязательно будут. Меркурий помешает сделать важные задачи в срок, поэтому закладывайте на выполнение в 2 раза больше времени. Лето подкинет массу интересных вариантов для отдыха.
Дружите со звёздами, они плохого не посоветуют💫
👍2
У аннотации Test определены все возможные Target. В какой строке будет ошибка компиляции (если будет)?
В какой строке будет ошибка компиляции (если будет)?
Anonymous Poll
16%
1
17%
2
4%
3
11%
4
35%
5
18%
Всё отлично скомпилируется
Аннотации, часть 1: обзор
Аннотации - дополнительная информация к исходному коду.
Первая часть будет о том, как сделать свою аннотацию, а во второй расскажу, когда и зачем это нужно.
Создать аннотацию легко:
Во времена java 4 аннотаций не было и для дополнительной информации классу добавляли интерфейс-маркер. В интерфейсах Cloneable, Serializable, Remote нет методов, они используются только как дополнительный признак класса.
Подход рабочий, но похож на костыль. Цель интерфейса - показать контракт класса, поэтому для маркировки кода в java 5 ввели аннотации.
Вернёмся в наши дни. Посмотрим исходный код @Deprecated:
🔸Поля
Содержат доп. информацию. Если указать значение по умолчанию, поле становится необязательным:
🔸Список внутри @Target показывает элементы, для которых работает аннотация.
В java 7 аннотации доступны для классов, методов, параметров, полей и переменных.
В java 8 аннотации действуют везде, где указан тип. Можно писать даже такое:
Аннотации нельзя ставить для имён переменных. Правильный ответ на вопрос перед постом - ошибка в 5 строке:
✅
@Target и @Retention- это мета аннотации, то есть аннотации для аннотаций.
Какие ещё бывают мета-аннотации:
🔸@Documented - аннотация появится в JavaDoc
🔸@Inherited - наследуется подклассами
🔸@Repeatable (Java 8) - можно использовать несколько раз для одного элемента. Иногда такое приятнее читать, чем один массив:
Аннотации - дополнительная информация к исходному коду.
@Override, @Deprecated, @SuppressWarnings - вот это всё.Первая часть будет о том, как сделать свою аннотацию, а во второй расскажу, когда и зачем это нужно.
Создать аннотацию легко:
public @interface MyAnnotation {}
❓Почему ключевое слово @интерфейс, а не @аннотейшн? Во времена java 4 аннотаций не было и для дополнительной информации классу добавляли интерфейс-маркер. В интерфейсах Cloneable, Serializable, Remote нет методов, они используются только как дополнительный признак класса.
Подход рабочий, но похож на костыль. Цель интерфейса - показать контракт класса, поэтому для маркировки кода в java 5 ввели аннотации.
Вернёмся в наши дни. Посмотрим исходный код @Deprecated:
@Retention(RUNTIME)На этом примере видно, из чего состоит аннотация:
@Target(value={FIELD,…})
public @interface Deprecated {
String since() default "";
boolean forRemoval() default false;
}
🔸Поля
Содержат доп. информацию. Если указать значение по умолчанию, поле становится необязательным:
@Deprecated(since="14")// forRemoval по умолчанию false
🔸Список внутри @Target показывает элементы, для которых работает аннотация.
В java 7 аннотации доступны для классов, методов, параметров, полей и переменных.
В java 8 аннотации действуют везде, где указан тип. Можно писать даже такое:
▫️new @Test Account()
▫️throws @Test IOException
▫️implements @Test Comparable<@Test
T>
Такие аннотации называются type annotations и используются в IDE и компиляторах для анализа и строгого контроля типов.Аннотации нельзя ставить для имён переменных. Правильный ответ на вопрос перед постом - ошибка в 5 строке:
✅
@Test String doubled
❌ String @Test out
🔸@Retention определяет, когда доступна аннотация и как её можно использовать. Все виды подробно рассмотрим во второй части.@Target и @Retention- это мета аннотации, то есть аннотации для аннотаций.
Какие ещё бывают мета-аннотации:
🔸@Documented - аннотация появится в JavaDoc
🔸@Inherited - наследуется подклассами
🔸@Repeatable (Java 8) - можно использовать несколько раз для одного элемента. Иногда такое приятнее читать, чем один массив:
@Schedule(dayOfMonth="last")Создать аннотацию легко, правильно применить - уже сложнее. С этим вопросом разберёмся во второй части.
@Schedule(dayOfWeek="Fri", hour="23")
❤1
Аннотации, часть 2: как использовать
Продолжим вчерашнюю тему. Рассмотрим Retention, и когда пригодится самодельная аннотация.
@Retention определяет, на каком этапе доступна аннотация:
🔹 SOURCE - аннотация видна только во время компиляции
🔹 CLASS - доступна также в байт-коде
🔹 RUNTIME - видна всегда, даже во время работы программы
Доступность выбирается исходя из цели. Поэтому перейдём к кейсам.
Что можно сделать через аннотации?
1️⃣ Объединить уже существующие.
Самый популярный и простой случай. Если в проекте несколько аннотаций часто идут вместе, объедините их в одну. Если у всех компонентов есть обработчики, то больше ничего делать не надо, всё заработает само.
Пример: @SpringBootApplication - это комбинация @Configuration, @EnableAutoConfiguration и @ComponentScan.
2️⃣ Генерация кода и файлов.
Происходит на этапе компиляции:
🔸 Отмечаем код аннотацией
🔸 Создаём класс-наследник от AbstractProcessor. Определяем, на какие аннотации реагировать
🔸 Вытаскиваем дополнительную информацию через
🔸 Включаем процессор в компиляцию. В maven-compiler-plugin это секция annotationProcessors.
Для обработки подойдут аннотации с любой RetentionPolicy.
Что получаем:
❌ Долгая компиляция
❌ Специфичное тестирование. Пример
😐 Сложный и запутанный код
✅ Не тратится время на старте приложений
Этот подход используется в библиотеке Lombok, микрофреймворках Quarkus и Micronaut, в Android фреймворке Dagger.
Библиотека Dekorate на основе аннотаций создаёт манифесты для Kubernetes и OpenShift.
3️⃣ Статический анализ.
Алгоритм такой же - создать наследник от AbstractProcessor, добавить в процесс компиляции.
Примеры: библиотека Google Error Prone ищет в коде ошибки, Hibernate Validator проверяет, что аннотации Hibernate корректно расставлены.
4️⃣ Работа с байт-кодом.
Редкий случай. В байт-коде остаются аннотации с RetentionPolicy.CLASS или RUNTIME.
5️⃣ Создать объекты и прокси-классы.
Доступно для аннотаций с RetentionPolicy.RUNTIME.
Основа работы многих фреймворков: Spring, Hibernate, Java EE. Под работу с аннотациями в рантайме заточены многие библиотеки: Reflections, Spring. Работать с ними удобно и приятно.
Обработка рантайм-аннотаций обычно происходит на старте приложения, поэтому запуск сервиса может занимать несколько минут.
❌Теперь рассмотрим анти-кейсы, для чего аннотации НЕ нужны:
1️⃣ Отметить код для себя или команды.
Поставить аннотацию @RefactorASAP легко, но без дальнейших действий это бесполезно. Аннотации нужно обрабатывать, и делать это автоматически.
Чтобы запомнить место в коде, используйте TODO комментарии в Intellij IDEA.
2️⃣ Для бизнес-логики.
Аннотации легко добавить в обход ООП и основной логики. Так можно быстро решить проблему, но долгосрочно это неудачный вариант:
❌ Нельзя контролировать процесс целиком
❌ Сложно писать тесты
❌ Сложно дебажить
❌ Внезапные сайд-эффекты
Частая ситуация на Spring проектах: на старте запускаются десятки @PostConstruct. Если в процессе возникает ошибка, то найти и исправить её непросто.
Но вообще, чем меньше вы полагаетесь на аннотации, тем лучше.
Продолжим вчерашнюю тему. Рассмотрим Retention, и когда пригодится самодельная аннотация.
@Retention определяет, на каком этапе доступна аннотация:
🔹 SOURCE - аннотация видна только во время компиляции
🔹 CLASS - доступна также в байт-коде
🔹 RUNTIME - видна всегда, даже во время работы программы
Доступность выбирается исходя из цели. Поэтому перейдём к кейсам.
Что можно сделать через аннотации?
1️⃣ Объединить уже существующие.
Самый популярный и простой случай. Если в проекте несколько аннотаций часто идут вместе, объедините их в одну. Если у всех компонентов есть обработчики, то больше ничего делать не надо, всё заработает само.
Пример: @SpringBootApplication - это комбинация @Configuration, @EnableAutoConfiguration и @ComponentScan.
2️⃣ Генерация кода и файлов.
Происходит на этапе компиляции:
🔸 Отмечаем код аннотацией
🔸 Создаём класс-наследник от AbstractProcessor. Определяем, на какие аннотации реагировать
🔸 Вытаскиваем дополнительную информацию через
.class
Deprecated d = Account.class. getAnnotation(Deprecated.class)🔸 Делаем что-то полезное
🔸 Включаем процессор в компиляцию. В maven-compiler-plugin это секция annotationProcessors.
Для обработки подойдут аннотации с любой RetentionPolicy.
Что получаем:
❌ Долгая компиляция
❌ Специфичное тестирование. Пример
😐 Сложный и запутанный код
✅ Не тратится время на старте приложений
Этот подход используется в библиотеке Lombok, микрофреймворках Quarkus и Micronaut, в Android фреймворке Dagger.
Библиотека Dekorate на основе аннотаций создаёт манифесты для Kubernetes и OpenShift.
3️⃣ Статический анализ.
Алгоритм такой же - создать наследник от AbstractProcessor, добавить в процесс компиляции.
Примеры: библиотека Google Error Prone ищет в коде ошибки, Hibernate Validator проверяет, что аннотации Hibernate корректно расставлены.
4️⃣ Работа с байт-кодом.
Редкий случай. В байт-коде остаются аннотации с RetentionPolicy.CLASS или RUNTIME.
5️⃣ Создать объекты и прокси-классы.
Доступно для аннотаций с RetentionPolicy.RUNTIME.
Основа работы многих фреймворков: Spring, Hibernate, Java EE. Под работу с аннотациями в рантайме заточены многие библиотеки: Reflections, Spring. Работать с ними удобно и приятно.
Обработка рантайм-аннотаций обычно происходит на старте приложения, поэтому запуск сервиса может занимать несколько минут.
❌Теперь рассмотрим анти-кейсы, для чего аннотации НЕ нужны:
1️⃣ Отметить код для себя или команды.
Поставить аннотацию @RefactorASAP легко, но без дальнейших действий это бесполезно. Аннотации нужно обрабатывать, и делать это автоматически.
Чтобы запомнить место в коде, используйте TODO комментарии в Intellij IDEA.
2️⃣ Для бизнес-логики.
Аннотации легко добавить в обход ООП и основной логики. Так можно быстро решить проблему, но долгосрочно это неудачный вариант:
❌ Нельзя контролировать процесс целиком
❌ Сложно писать тесты
❌ Сложно дебажить
❌ Внезапные сайд-эффекты
Частая ситуация на Spring проектах: на старте запускаются десятки @PostConstruct. Если в процессе возникает ошибка, то найти и исправить её непросто.
Но вообще, чем меньше вы полагаетесь на аннотации, тем лучше.
👍3❤1
Stream API: новые методы в Java 16
16 марта вышла java 16. Новые фичи входят во вторую превью стадию перед главным релизом 2021 - java 17 LTS.
Существующие классы тоже развиваются. В java 16 в Stream API появилось 4 новых метода, которые мы и рассмотрим в этом посте.
1️⃣
Новый метод не совсем равнозначный:
▫️Collectors.toList() возвращает экземпляр ArrayList.
▫️Новый метод toList() возвращает неизменяемый список.
2️⃣ mapMulti
Это оптизированный flatMap. Объясню суть на примере. Заказ - класс Order, товар - класс Item. Заказ состоит из нескольких товаров. Из списка заказов хотим получить список всех товаров.
Минус: объект стрима создаётся всегда, даже для пустых списков.
mapMulti устраняет этот недостаток:
mapMulti принимает на вход (order, consumer):
▪️order - элемент стрима, в нашем случае - заказ
▪️consumer - следующий этап в стриме. Наша задача - передать этому этапу все будущие элементы. Берём у заказа товары и для каждого вызываем consumer.accept(item).
Мультимэп не знает, для каких объектов будет вызван accept, и не может вывести тип выходных элементов. Поэтому для нормальной работы тип надо указать явно:
✅ Небольшое количество элементов в списках.
Например, много заказов с 1-2 товарами
✅ Элементы легко получить без Stream API
Основная фишка mapMulti - нет промежуточных стримов. Если внутри метода создаётся стрим, то вся выгода сходит на нет.
❌ order.getItems().stream()…
Есть три вариации метода:
🔸IntStream mapMultiToInt
🔸LongStream mapMultiToLong
🔸DoubleStream mapMultiToDouble
Для них выходной тип не указывается.
16 марта вышла java 16. Новые фичи входят во вторую превью стадию перед главным релизом 2021 - java 17 LTS.
Существующие классы тоже развиваются. В java 16 в Stream API появилось 4 новых метода, которые мы и рассмотрим в этом посте.
1️⃣
toList()
С 25 по 27 ноября была серия постов о коллекторах (часть 1, часть 2, часть 3). Там я писала, что вместоcollect(Collectors.toList())было бы удобно писать просто
toList()30 ноября разработчик Oracle добавил метод toList() в класс Stream. Вряд ли он читает этот канал, но совпадение интересное🙂
Новый метод не совсем равнозначный:
▫️Collectors.toList() возвращает экземпляр ArrayList.
▫️Новый метод toList() возвращает неизменяемый список.
2️⃣ mapMulti
Это оптизированный flatMap. Объясню суть на примере. Заказ - класс Order, товар - класс Item. Заказ состоит из нескольких товаров. Из списка заказов хотим получить список всех товаров.
orders.stream()flatMap переводит "список списков" в один список. Товары для каждого заказа превращаются в Stream, а метод flatMap объединяет эти стримы в один.
.flatMap(order->order.getItems().stream())
.toList();
Минус: объект стрима создаётся всегда, даже для пустых списков.
mapMulti устраняет этот недостаток:
orders.stream()Что происходит:
.<Item>mapMulti((order, consumer) ->
order.getItems().forEach(item -> consumer.accept(item))
).toList();
mapMulti принимает на вход (order, consumer):
▪️order - элемент стрима, в нашем случае - заказ
▪️consumer - следующий этап в стриме. Наша задача - передать этому этапу все будущие элементы. Берём у заказа товары и для каждого вызываем consumer.accept(item).
Мультимэп не знает, для каких объектов будет вызван accept, и не может вывести тип выходных элементов. Поэтому для нормальной работы тип надо указать явно:
<Item>mapMulti(…)Когда использовать mapMulti?
✅ Небольшое количество элементов в списках.
Например, много заказов с 1-2 товарами
✅ Элементы легко получить без Stream API
Основная фишка mapMulti - нет промежуточных стримов. Если внутри метода создаётся стрим, то вся выгода сходит на нет.
❌ order.getItems().stream()…
Есть три вариации метода:
🔸IntStream mapMultiToInt
🔸LongStream mapMultiToLong
🔸DoubleStream mapMultiToDouble
Для них выходной тип не указывается.
❤1
Intellij IDEA: как выучить шорткаты
В IDEA сотни горячих клавиш. С ними удобно работать, не надо тащить курсор через 2 монитора и бродить по контекстному меню. Есть только одна проблема - шорткаты сложно запомнить сразу.
Видела, как люди распечатывают огромный список горячих клавиш и вешают рядом с монитором. Поделюсь более прогрессивными методами:
1️⃣ Выучить топ-15
Статистика использования IDE находится в Help → Productivity Guide. Сортируем по колонке Used, получаем часто используемые команды. В описании указаны шорткаты. Запоминаем горячие клавиши для 10-15 действий, и продуктивность заметно растёт.
2️⃣ Плагин Key Promoter X
Установка: File → Settings → Plugins → Key Promoter X.
При действиях с мышкой в углу всплывает подсказка-шорткат.
Здесь работает правило 80/20: шорткаты для навигации, поиска и рефакторинга покрывают большинство ежедневных задач. Их легко выучить с помощью этих двух инструментов.
В IDEA сотни горячих клавиш. С ними удобно работать, не надо тащить курсор через 2 монитора и бродить по контекстному меню. Есть только одна проблема - шорткаты сложно запомнить сразу.
Видела, как люди распечатывают огромный список горячих клавиш и вешают рядом с монитором. Поделюсь более прогрессивными методами:
1️⃣ Выучить топ-15
Статистика использования IDE находится в Help → Productivity Guide. Сортируем по колонке Used, получаем часто используемые команды. В описании указаны шорткаты. Запоминаем горячие клавиши для 10-15 действий, и продуктивность заметно растёт.
2️⃣ Плагин Key Promoter X
Установка: File → Settings → Plugins → Key Promoter X.
При действиях с мышкой в углу всплывает подсказка-шорткат.
Здесь работает правило 80/20: шорткаты для навигации, поиска и рефакторинга покрывают большинство ежедневных задач. Их легко выучить с помощью этих двух инструментов.
Intellij IDEA: Database View
Продолжая тему с БД, расскажу как можно работать с базой через Intellij IDEA.
Окошко открывается так: View → Tool Windows → Database
Подключить базу просто, самые необходимые функции есть:
▫️ Информация о таблицах, столбцах, индексах и т.д
▫️ Выполнить запрос
▫️ Выгрузить данные или метадату
Какие базы доступны:
✅ Реляционные: Oracle, PostgreSQL, MySQL
✅ Многие NoSQL: Mongo, Cassandra, Hive, ClickHouse, Vertica
✅ Экзотичные: Exasol, Greenplum и Snowflake
❌ Redis, Couchbase, HBase, CouchDB, Neo4j
Полный список баз на сегодня:
Продолжая тему с БД, расскажу как можно работать с базой через Intellij IDEA.
Окошко открывается так: View → Tool Windows → Database
Подключить базу просто, самые необходимые функции есть:
▫️ Информация о таблицах, столбцах, индексах и т.д
▫️ Выполнить запрос
▫️ Выгрузить данные или метадату
Какие базы доступны:
✅ Реляционные: Oracle, PostgreSQL, MySQL
✅ Многие NoSQL: Mongo, Cassandra, Hive, ClickHouse, Vertica
✅ Экзотичные: Exasol, Greenplum и Snowflake
❌ Redis, Couchbase, HBase, CouchDB, Neo4j
Полный список баз на сегодня: