Как стать автором
Обновить
Плох тот солдат, что не мечтает быть генералом, и плох тот разработчик, который не стремится стать Java-чемпионом. Если ты чувствуешь себя в многопоточности как рыба в воде, а на структурах классов и Collections API давно собаку съел — добро пожаловать в наш тест.
Покажи, на что ты способен
Всего голосов 39: ↑27 и ↓12+15
Комментарии29

Комментарии 29

Обожаю (нет) эти олимпиадные «вопросики» которые нужны только для собесов. А по факту приходишь в контору и клепаешь сплошную бизнес-логику.

Java-лузер ¯_(ツ)_/¯


В основном на питоне пишу, но, думаю, что и в питоне таких деталей не знаю.
Конечно, считаю необходимым знать такие вещи, но в коде аппликух средних компаний ни разу таких заумных конструкций не встречал.

… и у тебя возникает необходимость использовать класс из этой библиотеки в качестве ключа в HashMap ...

Это ж над чем нужно трудиться, чтобы такая «необходимость» возникла???
Составлением тестов на хабре, очевидно же.

Да над чем угодно. Мало ли надо как-то сопоставить библиотечному объекту свои данные, а потом еще быстро делать поиск и эти данные находить.

Интересно, кто ваши клиенты… можно список, чтобы по возможности избегать?

Кхм. Расчет в методе без использования переданного аргумента? Взаимодействие producer-consumer, где isLock ставится только в true, но никогда — в false? Если уж в тестах у вас ошибки, то в рабочем не лучше. Не-не-не, такой код поддерживать я не хочу.

К сожалению, разработчики написали плохую хеш-функцию, и наблюдается значительная коллизия ключей. Метод equals() переопределен корректно. Какую алгоритмическую сложность поиска значения по ключу стоит ожидать?

Вы, конечно, ожидаете, что с Java 8 будет O(log n). Но это возможно только в том случае, если разработчики сделали свои объекты Comparable и корректно реализовали compareTo. Что было бы наивно ожидать от разработчиков, которые реализовали плохую хэш-функцию. Ни разу в жизни не видел объекта с плохой (но корректной) хэш-функцией и правильным compareTo одновременно. Вы видели?

Ну, разработчики могли и не делать объекты Comparable. В этом случае дерево будет строится в по identity hashcode'у (в конечном счете). Работать будет корректно, за O(log n). Вот только относительно медленно, потому что пока дело дойдет до взятия хэшей, HashMap успеет еще посравнивать имена классов, например.
Но скорее всего, в программе авторства разработчиков, которые не осилили написание хэш-функции, смотреть на ассимптотическую сложность бессмысленно, поскольку производительность можно испортить куда более эффективными способами

О, надо же, я этого не знал. Спасибо! Добавишь так в HashMap объект, а потом biased locking на нём сломается =)

Должен ли класс, который планируется использовать в качестве ключа HashMap, быть полностью immutable?

Тут очень много вопросов. Начиная с того что понимать под immutable класс. Можете дать определение? Я знаю, что лучшие умы OpenJDK обсуждали этот термин долго и горячо, когда ввели вот эти все List.of и собирались их описать в документации. В итоге вообще отказались от слова immutable. Вот к примеру java.lang.String immutable или нет?


Также в "правильном" ответе ничего не написано про контракт Comparable. А если ключ реализует Comparable, но после изменения объекта результат сравнения получается другой? HashMap может сломаться.


Я бы ответил, что для любого объекта, используемого в качестве ключа (в том числе необязательно помещённого в Map, но и переданного в containsKey и т. д.), результат hashCode должен сохраняться на протяжении использования, а также для любой пары объектов, используемых в качестве ключа, результат equals и compareTo (при наличии) должен тоже сохраняться на протяжении использования. А что означает слово immutable — наплевать.

Ты разрабатываешь часть системы, которая выполняет различные финансовые операции. Какие типы могут подойти для выполнения таких операций?

И к этому вопросу много вопросов. Типа Int в стандартной библиотеке Java вообще нет, но допустим это особенность формы опроса и имелся в виду примитивный int. Почему можно его использовать? Человек, у которого больше двух миллиардов рублей на счету, будет очень недоволен. Деление двух интов всегда округляется вниз, хотя вы пишете, что округлений нет. Наконец, любое число, представимое в int, представимо и в double с той же самой точностью. То есть любую операцию, которую вы можете сделать на int, вы можете сделать на double с не меньшей точностью. Причём у вас будет более точный результат деления и меньше рисков переполнения. Почему int считается правильным ответом, а double нет — совершенно неясно.


Нет, я понимаю стандартную мантру "используйте BigDecimal", но блин, вопрос-то надо правильно формулировать.

Дополню что еще есть вариант использовать BigInteger и хранить деньги в целых числах (в «копейках» соответствующей валюты). О делении вообще лучше забыть, а рассмотреть операцию распределения — когда единицы на троих вместо 0.33, 0.33, 0.33 и потерянной копейки будет 0.33, 0.33 и 0.34.
А это тоже спорное решение
Даже в основных валютах финансовые операции в банковских системах могут выполняться пакетом или с рычагом и хранятся, в итоге, далеко не в целых копейках
О бумагах я уж вообще не говорю
А не о чем спорить. Это просто один из вариантов — он не серебряная пуля и не везде подходит :)

На седьмой вопрос мой ответ: у меня глаза текут от этого ужасного кода. Используйте неизменяемые кортежи, лесом синхронизацию.


На восьмой вопрос мой ответ: не мучайте киску. Если вам нужен putIfAbsent, берите CopyOnWriteArraySet и радуйтесь. Если вы по несчастью застряли с synchronizedList, рефакторьте код, это в любом случае опасная фигня (например, стримы от неё небезопасны, я дописал это в документации). Если уж совсем припёрло, почитайте документацию, там написано, что надо использовать в качестве монитора для синхронизации дополнительных операций. Помнить это наизусть необязательно. Про synchronizedList надо помнить одну вещь: что его лучше избегать и использовать крайне осторожно.


На девятый вопрос мой ответ: используйте SynchronousQueue из стандартной библиотеки. Вы всё равно не сделаете лучше. Все четыре предложенные реализации неустойчивы против повторного вызова producer. В этом плане смешно видеть умные слова в ответе "что позволяет потоку писать данные достаточно быстро". Как он может писать достаточно быстро, если дизайн класса не предполагает перекачки более одного значения? Такой код в серьёзном продакшне недопустим. Не надо изобретать велосипеды.


На десятый вопрос мой ответ: давайте всё-таки хорошо подумаем и попытаемся избавиться от циклических зависимостей между компонентами перед тем как делать вот это.

«Ты Java-новичок.» мне понравились вопросы. Да и охарактеризовали меня верно. Не смотря на то, что у меня ОСА 8 и ОСР 11, отсутствие опыта дает о себе знать.

Ты их не слушай, ты lany слушай — вот он действительно стоящие вещи говорит, а эта статейка — сплошноё позёрство и попытки выгрести из говнокода хоть чуть пользы…
Ещё где-то на хабре обитал Шипилёв (можно в ютубчике его выступления на Joker и JPoint посмотреть) — он тоже полезные вещи про это всё говорит.

Задача 8 ад. Ответил неправильно и долго не мог понять, чем другие локи не угодили.


Через 5 минут увидел, что поле то public. Не, это серьёзно? Сейчас ещё есть люди, кто на автомате все поля private/protected/package private не делает?
Ну т.е. использование synchronizedList и не-создание копии входящего списка, видимо, было мало для bad practice


И после таких вопросов:


Сделать шаг к вершине и прокачаться на интересных задачах ты можешь в команде НСПК.

Очень интересные задачи. Мукачайтесь с ними сами

Ещё замечания по поводу восьмого вопроса, который про putIfAbsent, чтобы всё лежа более-менее в одном месте:
• смысл в потокбезопасной обёртке, если оборачиваемый список к нам приходит извне, и по утёкшей ссылке можно вполне себе изменять состояние списка?
• я сам не увидел, но public-поле вообще позволяет подпихнуть что угодно вместо синхронизированного списка.
• Один из ответов вообще не компилируется


вот этот
class ModifiedList<E> {
 public final List<E> syncList;

public ModifiedList(List<E> list) {
   this.syncList = Collections.synchronizedList(list);
}

   public boolean putIfAbsent(E item) {
       boolean absent = !syncList.contains(item);
       if (absent)
           lisyncListst.add(item);
       return absent;
   }
}

У нас нет переменной по имени lisyncListst, а не "Метод не синхронизирован в принципе, может возникнуть race-condition".


Вообще, я раза три думал перестать писать комментарий, но тут и более умные люди прошлись по тесту, пусть будет этот комментарий хотя бы про эту задачу.

НСПК — это те которые делают карты МИР, собеседовал как-то человека который оттуда уволился:
— отзывы о компании удручают
— кандидата в итоге не взяли

Открываем первую задачку:


этот класс ты планируешь использовать в качестве ключа

Точно "этот класс"? Может быть всё-таки "объекты этого класса" или "объекты этого типа"?


Не, серьёзно, поработайте над формулировками.


Я не то, что придираюсь. Но просто если я буду использовать в качестве ключа класс (.class), то очень понятно, что дальше будет происходить, и кажется это не то, чего ожидают авторы вопроса.

Не делайте тест, прокликайте чобы ознакомиться с контекстом и хватит.
Читайте комменты lany. В них смысла больше чем в вопросах и оригинальный ответах.
Как можно засовывать приходящую извне mutable not-threadsafe коллекцию в прокси и требовать какие-либо threadsafety гарантии?

Йеп. Никак.


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

Терпимо, кроме формулировки первого вопроса и использования слова замок.

Во втором вопрос все предложенные варианты верные, если правильно понимать Big O нотацию.

Можете пояснить пожалуйста? Я плохо представляю как можно получить n*n в данном случае
Возможно я неправильно понимаю эту нотацию

Это просто моя маленькая придирка.
Если асимптотика алгоритма O(n), то O(n^2) тоже является асимптотикой данного алгоритма.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий