Telegram Web
11 шагов к Senior Google User

Главный навык разработчика - умение пользоваться интернетом. Чтобы занять голову не регулярками и опциями докера, а действительно важными вещами. Вот несколько приёмов для быстрого и чёткого поиска.

1️⃣ Искать по-английски
Материала больше, обычно он приятнее и понятнее русских аналогов.

2️⃣ Кавычки для поиска конкретной фразы
"parse pdf to xml"

Чтобы пропустить часть фразы, используйте звёздочку:
"java regex * tutorial"

3️⃣ AND
Обязательное вхождение обоих слов / фраз

"Spring in Action" AND "Евгений Борисов"

4️⃣ OR
Для поиска одного из вариантов

"how to do java" OR "java for beginners"

5️⃣ Исключить ключевое слово через минус
java types -javascript

Работает и для сайтов:
как пройти собеседование -otvet.mail.ru

6️⃣ Поиск на конкретном сайте
NPE site:stackoverflow.com

7️⃣ Найти файлы
Удобно искать книжки, презентации к докладам

"effective java" filetype:pdf

8️⃣ Найти только свежие / старые материалы
thread safety before:2020
functional programming after:2020-12-20

9️⃣ Быстрый перевод
coherence in russian
resilience по русски

🔟 Сложный поиск
Чтобы не запоминать эти приёмчики, есть страница Advanced Search с формочками для всех критериев и опцией "Скрывать непристойные результаты".

🔸 Бонусный пункт для владельцев Android со связанным Google аккаунтом:

find my phone в строке поиска. Даже если звук на телефоне выключен, можно включить звонок и найти телефон.
Закулисье курса по многопоточке

19 апреля стартовал первый поток курса по многопоточному программированию на java. Хочу рассказать, что там происходит и поделиться мыслями по этому поводу.

О чём вообще речь.

В прошлом году я начала готовить курс по многопоточке на java. Тема важная и сложная, а хороших материалов очень мало. Получился двухмесячный концентрированный курс: уроки с заданиями выходят три раза в неделю. Три недели назад стартовал первый поток, поэтому можно уже поделиться результатами.

По цифрам:
🔹 Участники с опытом от года до 8 лет
🔹 33% выполняют задания к уроку в течение 2 дней
🔹 60% - в течение недели
🔹 Самая активное время сдачи ДЗ - с 22 до часу ночи🌚
🔹 1 человеку не подошёл формат, вернула деньги

Что говорят ребята:
❤️ Курс действительно заполняет пробелы. Интересна точка зрения опытного разработчика на проблемы
❤️ Большое спасибо, что вы находите время писать развернутые комментарии и отвечать на смежные вопросы!) Это круто)
❤️ Если говорить в целом - то я очень доволен курсом
❤️ Сложно конечно, много нового для меня, не всегда успеваю сразу сдавать. Но чувствую, что полезно))

В целом я довольна. Времени на обратную связь трачу много, но, кажется, не зря.

Поэтому в июле планирую повторить. Тоже с небольшой группой, не больше 20 учеников. В предварительном списке уже больше 40 человек! Если тоже хотите первыми узнать дату старта и условия, вписывайтесь сюда:

Предварительный список на двухмесячный курс по java.util.concurrent и смежным вопросам
Собеседование:
- Расскажите про enumerations.
- Ну, это набор констант
- Как их можно использовать в коде?
- Как набор констант
(что им надо?)
- А как они реализованы в JVM?
- Как константы
(спросите лучше про хэшмэп)

Чтобы не получилось такой ситуации, на этой неделе разберёмся с темой перечислений. Enum - очень полезные конструкции. С ними код становится проще и безопаснее. Если их использовать, конечно.

План такой:
Часть 1 - обзор enumerations
Часть 2 - как используется на практике
Часть 3 - разберём загрузку классов и душный вопрос с собеседования
В enum Planet есть метод getRadius. В классе Meteor тоже он есть. Мы хотим сделать метод getInfo, который работает с обеими сущностями и вызывает их метод getRadius.

Вопрос: что будет вместо солнышка во входном параметре?
(щёлкните по картинке, чтобы открыть полностью)
Enumerations, часть 1: обзор

Внутри JVM нет такого понятия как enum. Енумы компилируются в обычный класс, а значения - в статические экземпляры:

public final class Planet extends Enum {
public static final Planet EARTH;
public static final Planet MARS;
}

Полноценные классы c конструкторами, методами, полями и статическими элементами. У экземпляров есть состояние и определённое поведение.

Но есть нюансы:

🔸 Суперкласс Enum

От суперкласса Enum наследуются методы name(), ordinal() и статический метод values().
name() возвращает имя переменной, ordinal() - порядковый номер в списке. На практике эти методы достаточно бесполезны.

Метод values() используется чаще и возвращает массив всех объектов. Можно пройтись по нему в цикле:
for (Planet p : Planet.values()) {…}

или через Stream API:
Arrays.stream(Planet.values()).forEach(…)

🔸 Интерфейсы суперкласса

Enum реализует три интерфейса: Comparable, Serializable, Constable.

Первые два всем знакомы. Интерфейс Constable определяет методы для размещения объектов в пуле констант внутри JVM.

🔸 Создание экземпляров

Этим занимается JVM на старте приложения. Экземпляры енума создаются через приватный конструктор, недоступный вне енума.

🔸 Поля

Указываются для каждого экземпляра, инициализируются в конcтрукторе:

public enum Planet {
MARS(3389),
EARTH(6371);
int radius;

Planet(int radius) {
this.radius = radius;
}
}

🔸 Два типа методов

▫️Обычные
public int getRadius()

Используется для геттеров и простых вычислений.

В теории можно сделать set* метод и поменять поле у любого экземпляра. Но на практике так никто не делает. Когда объект доступен из любого места системы, то проще жить, если он неизменяемый.

▫️Абстрактные
Каждый экземпляр определяет свою реализацию:

public enum Planet {
MARS {
int distanceFrom(int) {…}
},
EARTH {
int distanceFrom(int) {…}
};

abstract int distanceFrom(int);
}

🔸 Наследование

Любой enum - это final класс с уже определённым суперклассом. Единственный шанс встроить enum в иерархию - добавить для него интерфейс.

Иногда это удобно. Если у енумов и классов один интерфейс, то с ними можно работать через один метод:

interface SpaceObject

enum Planet implements SpaceObject
class Meteor implements SpaceObject

public void getInfo(SpaceObject so)
Вопрос
Enum Formatter занимается форматированием строк в заданные форматы. Во время работы было выполнено 50 форматирований в XML, в JSON - 30, в YAML - 5.

Что вернёт метод Formatter.JSON.getCount()?
Enumerations, часть 2: практика

В прошлом посте разобрали, из чего сделан enum. В этом - разберёмся, как его использовать.

1️⃣ Набор констант

Самый простой и популярный случай. Используем enum как поле класса или локальную переменную. Проверяем значение через if / switch и делаем ветвления в коде:

if (state == UserState.NEW) {…}

2️⃣ Паттерн Singleton

Вообще синглтон - антипаттерн и антитренд. Если без него никак - рассмотрите вариант с enum. Если вы склонны к риску, можно сделать изменяемые поля.

Может быть несколько объектов в рамках одного enum
Доступ из любого места в коде
Ленивая инициализация

3️⃣ Паттерн State

Более продвинутый вариант, чем "набор констант". Здесь фокус на данных: используются связанные значения, а не элемент enum сам по себе.

Пример: в статус пользователя вносим дополнительные поля - необходимость подтверждения личности и максимальный размер скидки:

enum UserState { 
NEW(true, 10),
VALIDATED(false, 25),
FRAUD(true, 0);

boolean needConfirmation;
int maxDiscount;
}

4️⃣ Паттерн Strategy

Здесь фокус на разнице в поведении. Абстрактный метод переопределяется для каждого экземпляра:

NEW { boolean check(Order){…}},
VALIDATED { boolean check(Order){…}};

abstract boolean check(Order order)

Подойдёт для алгоритмов, конвертеров, сортировок
Простая иерархия, всё в одном классе
Список всех значений доступен через values()
😐 Весь код в одном файле. Не всегда удобно
Сложно связать с другими объектами
Нарушается принцип open for extension but closed for modification

Получается специфическая альтернатива полиморфизму, но иногда ок.

Enum - не просто набор констант. Инструмент своеобразный, но полезно знать и такие реализации паттернов. Чем шире арсенал разработчика, тем выше шанс найти подходящее решение.
Вопрос
В классе User хранится статус в виде enum State.

В каком порядке и как будут создаваться объекты при первом вызове User user = new User()?
Enumerations, часть 3: загрузка классов

Мы уже разобрали, из чего состоит enum и как его использовать. Сегодня разберём, как загружаются классы и экземпляры enum. Поможет нам в этом душноватый вопрос с собеседований, который находится выше.

Классы в JVM загружаются по мере необходимости. Что происходит при первом вызове new User():

🔹 Загрузка класса User, создание экземпляра User.class
🔹 Инициализируются статические переменные и выполняются блоки static {...}

Дальше переходим к созданию объекта:

🔸 Создаются явно указанные поля и выполняются блоки { }
🔸 Вызов конструктора класса и суперклассов

Внутри инициализирующего блока понадобился класс State. Переходим к нему.

Enum State компилируется в такую штуку:

public final class State extends Enum {
public static final State NEW;
public static final State VALIDATED;

// init блок
State() {...}
// static блок
}

Возникла проблема. Перед вызовом конструктора надо закончить со статическими полями. А статические поля - экземпляры этого же класса. Замкнутый круг.

В такой ситуации JVM создаёт экземпляры NEW и VALIDATED перед статическими блоками. Получается такой порядок:

1️⃣ Создаём экземпляр State NEW:
▫️блок инициализации S-Init
▫️конструктор S-Constr

2️⃣ Повторяем тот же процесс для VALIDATED

3️⃣ Выполняем статический блок S-Static

Поэтому правильный ответ - G:
▫️enum NEW(Init-Constr)
▫️enum VALIDATED(Init-Constr)
▫️enum-Static
▫️объект User (Init-Constr)
Анонс мероприятий

Реклама не за деньги, а по любви. Общалась со всеми организаторами, поэтому рекомендую с чистой совестью.

1️⃣ Integrity Solutions Tech Talks. Митап при участии JUG Ru Group

Когда: 24 мая, 18:00 (по МСК)
Участие: бесплатно
Формат: онлайн

Программа :
▫️ "Java Flight Recorder": что такое, чем полезен и когда его применять. На мой взгляд самый полезный доклад.
▫️"Переезд с PostgreSQL на Elasticsearch для гибкого поиска адресов"
▫️ "Использование Тhymeleaf для динамических SQL-запросов"

Подробности и регистрация

2️⃣ Онлайн-чемпионат от Совкомбанк

Для кого: junior-middle
Зачем: проверить свои знания и найти пробелы. Если у вас в резюме нет пет-проджекта, можно сделать на основе заданий чемпа. Есть шанс выиграть деньги и мерч.
Когда: 22-23 мая
Формат: онлайн
Подача заявки: сегодня последний день😨

Что будет:
22 мая: вопросы по Java core, Collections, веб-сервисы, очереди, БД и ORM, Maven, git
23 мая: сделать REST сервис с авторизацией и с кем-то интегрироваться. Чьё приложение пройдёт больше тестов и лучше выдержит нагрузку - тот победит.

Подробности и регистрация

3️⃣ Ночной онлайн-чемпионат Tech Monsters Night от М.Видео

Для кого: middle-senior
Зачем: проверить себя и побороться за мерч и технику. Организаторы обещают доставку пиццы всем участникам🍕
Когда: 4 июня, с 22 до 3 ночи
Формат: онлайн
Подача заявки: до 3 июня

Подробности и регистрация
Ресурсы, идиома RAII и Java 9

Разработка - сложная штука c множеством идей и концептов. В этом посте я расскажу об идиоме RAII, разнице при работе с ресурсами в java и C++, блоке try-with-resources и изменениях java 9.

Начнём с основ. Ресурс - это сущность, для которой нужен эксклюзивный доступ. Их количество ограничено. Большинство ресурсов находятся за пределами JVM: файлы, соединения с БД, сокеты и т.д

Для корректной работы только один поток должен работать с ресурсом. Для этого нужно принять дополнительные меры. Обозначим их как "открыть" и "закрыть" ресурс:
🔸Открыть = получить эксклюзивный доступ.
🔸Закрыть = закончить работу. Теперь другой поток может работать с ресурсом.

Такой вот нехитрый жизненный цикл(ЖЦ).

RAII
или Resource Acquisition Is Initialization - одна из техник по работе с ресурсами. Другое название: SBRM - Scope-Bound Resource Management.

Суть: ассоциируем ресурс с объектом. Тогда ЖЦ ресурса совпадает с ЖЦ объекта. В идеале это выглядит так:

public void do() {
File f=new File("t.txt");
// Создаём объект File, ресурс "t.txt" теперь наш
// что-то делаем
}
// вышли из метода: объект f уже не нужен, ресурс "t.txt" освобождается

RAII легко реализовать в С++. В конструкторе пишем логику "открытия" ресурса, а в деструкторе - "закрытия". Конструктор и деструктор явно прописываются, поэтому ЖЦ объекта и ресурса под контролем.

В java так не получится. Деструктор выполнится неизвестно когда, а ресурс - штука ценная. Поэтому в java нужно явно вызвать метод закрытия. В стандартных библиотеках это close().

В java 7 появилась специальная конструкция для ресурсов:
try (PrintWriter writer = new PrintWriter(…)) {
// что-то делаем
}

Ресурс реализует интерфейс AutoCloseable, и после завершения блока для него вызовется close(). try-with-resources считается java реализацией RAII.

Но такой формат не идеален. Внутри try всегда определяется новый объект. Когда ресурсов два и больше, код становится громоздким:

try (DatagramChannel udpServer = …;
Selector selector = …) {
// …
}

В java 9 в блок try можно передать переменные:

DatagramChannel udpServer = …;
Selector selector = …;

try (udpServer;selector) {
// …
}

С одной стороны это удобно. Код выглядит приятно.

С другой - после try остаются переменные с закрытыми ресурсами. Теперь нельзя сказать, что java реализует RAII.

Ну и ладно, никто не расстроился🙂 Языки разные, и классно замечать, как по-разному в них реализуются идеи, и как они меняются с течением времени.
Почему на канале так много Java Core? Потому что это база для ежедневной работы, которую хорошо знать вдоль и поперёк. Но лично мой интерес лежит в другом. Мне нравится разбирать дизайн и разбираться, почему сделано так, а не иначе.

Тема этой недели - дженерики.
Часть 1: посмотрим реализацию в JVM
Часть 2: углубимся в wildcards и работу с подтипами
Какой результат выполнения этого кода?
Generics, часть 1: история и корпоративные ценности

Вернёмся в 1998 год.

В java 1.2 появились интерфейсы Map, Set, List и основные реализации. В те времена они хранили только объекты:

List values = new ArrayList()

Чтобы нормально работать, приходилось использовать явное приведение:

values.add("value");
String s = (String) values.get(0);

Главная проблема с коллекциями тех лет - type loss, потеря типа при компиляции и написании кода:
Можно запросто получить ClassCastException
Надо помнить тип объектов
Ошибки возникают только в рантайме

В java 5 появилась возможность указать тип через дженерики:

List<String> values = new ArrayList<String>();
values.add("p");
String v = values.get(0);

Удобно пользоваться
Хорошо читается
Компилятор проверяет типы

Как реализованы дженерики?

Примерим на себя должность архитектора java и прикинем, что можно сделать с ArrayList<T>:

1️⃣ Скомпилировать в класс с типом String
Все T заменяем на String:

void add(String str)
String get(int index)

В итоге создаём отдельный класс для каждого типа данных.

2️⃣ Добавить в JVM параметризованный тип

<T> остаётся на уровне байт-кода и определяется для каждого объекта в рантайме.

3️⃣ Оставить на уровне JVM работу с объектами. Проверить все типы во время компиляции и привести один к другому там, где нужно.
Получаем один ArrayList.class и множество дополнительных конструкций по всему коду.

Для ArrayList<String> программист напишет:

String value = list.get(0)

Компилятор преобразует это в

String value = (String) list.get(0);

🤔Все варианты адекватные и имеют право на жизнь. Что же выбрать?

Почти в каждом IT офисе на стенах висят слоганы и ценности компании. Что-то про качество работы, развитие сотрудников, гибкость и довольных клиентов. Из этого получается классный корпоративный мерч.

Ценности нормального человека определяют стратегию и дают ориентир для решения сложных ситуаций. "Ценности" java явно нигде не определены, но направление работы задано чётко. Например, кроссплатформенность и слоган Write Once, Run Anywhere заставляют разработчиков JDK поддерживать фичи даже для древних процессоров.

Бинарная совместимость - ещё один ориентир java. Поэтому для дженериков используется третий вариант: компилятор добавляет необходимые приведения типов в код и стирает информацию о дженериках. И код на java 5 теперь совместим с предыдущими версиями.

Ответ на вопрос перед постом

В консоли напечатаются оба значения. У списка tmp тип не задан, поэтому компилятор не мешает добавлять строки и передавать объекты в метод println.

Если в println передать список intList.get(0), где тип указан явно, то мы получим ошибку компиляции.
Какой результат выполнения этого кода?
2025/07/08 04:44:03
Back to Top
HTML Embed Code: