Вопросы при собеседовании java junior

Собеседую программистов на Java. Единый набор вопросов для любого уровня

В своей карьере мне приходилось быть и разработчиком, и менеджером, и даже один раз «CTO» в небольшом стартапе. И, разумеется, приходилось проводить большое количество собеседований кадидатов. Поэтому для себя я выработал такие правила проведения технических собеседований:

  • всем кандидатам задавать одинаковые вопросы,
  • вопросы должны быть такие, чтобы на них ответил и junior, и senior, но по разному,
  • после трёх вопросов должен быть понятен уровень кандидата.

Расскажите про HashMap

Да-да, тот самый стандартный вопрос, с которого начинается 50% собеседований. Почему я его задаю? Потому что на него можно ответить очень и очень по разному.

  • Идеальный ответ начинается с постановки задачи. Зачем нам нужна такая структура? Какую именно задачу она решает? Как выглядит тривиальное решение данной задачи «в лоб» и чем оно плохо?
  • «Бонусные очки» за исторический экскурс, знание автора решения, хотя бы примерный год его появления (не в Java, разумеется)
  • Ответ хотя бы junior’а обязан включать способы использования структуры. Какие методы она поддерживает.
  • От middle-разработчика требуется понимание внутреннего устройства, а также описание контрактов функций hashCode() и equals(), функциональных требований к ним
  • «Бонусные очки» за описание нефункциональных требований к hashCode() и equals()
  • «Бонусные очки» за рассмотрение вопроса использования HashMap в многопоточной среде.
  • «Бонусные очки» за рассмотрение альтернатив HashMap — их перечисление, сравнение по сложности реализации, использования, скорости работы в общем, идеальном и самом плохом случаях.
  • «Бонусные очки» за альтернативы HashMap в виде отдельных компонентов системы (например, баз данных и «внешних» кэшей).
  • «Бонусные очки» за описание того, как HashMap используется в базах данных, и почему обычно используют индексы на основе двоичных деревьев, а не HASH-индексы.
Читайте также:  Http сервер apache php mysql

Если будет скучно, замените HashMap на TreeMap.

Напишите SQL.

Ага, и снова «стандартный» вопрос, который 10 лет назад был на каждом собеседовании. Сейчас уже реже, видимо из-за моды на nosql. Но умение работать с данными всегда нужно, и программисты, понимающие декартово произведение, всегда полезнее (и дороже) тех, кто ограничивается общим пересказом учебника.

Пусть в базе данных существуют две таблицы: students и groups. У каждого студента указан идентификатор группы group_id, к которой он относится. Напишите SQL-запрос без использования вложенных, выводящий список групп (или количество групп) без единого студента

Правильный ответ будет, разумеется, содержать не просто JOIN, но LEFT JOIN со сравнением значения на NULL. Самое интересное будет поговорить с кандидатом о том, какие ошибки можно допустить при написании запроса, и почему именно запрос не будет работать, если их допустить. Почему нельзя сравнивать с NULL через равенство? Почему не будет работать простой JOIN?

Бонус за индексы, которые ускорят работу этого запроса и за рассмотрение вариантов SQL в разных диалектах (разных СУБД).

Найдите ошибки в коде

Предположим, что вам на code review приходит Pull Request (Merge Request) от другого разработчика. В этом request’е большое количество разных файлов, но один из них выглядит следующим образом (приведён код класса целиком):

package ru.mycompany.utils; /** Wrap around Lock to simplify interface */ class LockWrapper < private Lock lock; public wait() < this.lock.wait() >> 

Будут ли у вас замечания к этому коду, и если будут, то какие? Пропустите ли вы запрос с таким файлом далее (в master-ветку), или же потребуете переделать, и почему?

Разумеется, и здесь есть как минимум три уровня.

  • Любой junior должен указать на синтаксические ошибки, которые есть в этом коде. Разработчик должен указать, почему код не скомпилируется. И проблема не только в синтаксисе, разумеется.
  • Разработчик должен знать, почему даже если код скомпилируется, он не заработает. И как необходимо этот код поправить, чтобы он заработал. Разработчик должен уметь использовать и конструкцию synchronize, и классы из пакета java.util.concurrent, и знать, почему одно второму не третье.
  • Идеальный разработчик же должен начать с вопроса, а зачем этот код нужен, какую задачу он решает, и может ли он её решить, даже если исправить все существующие проблемы в этом коде.

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

Вместо заключения

Один совет, который хочется дать всем тем, кому придётся собеседовать будущих коллег. Не пытайтесь дать ответ — подходит человек или нет. Формулируйте своё мнение либо в виде грейда (если у вас в компании они приняты), либо в виде денежной суммы, которую вы готовы заплатить кандидату, чтобы он работал в вашей компании. Это, во-первых, упрощает принятие решение вам, ведь оно не будет чёрным или белым, во-вторых — тому, кто будет принимать финальное решение или сравнивать итоги нескольких собеседований.

Источник

7 практических заданий с собеседования на позицию Junior Java Developer

Обложка: 7 практических заданий с собеседования на позицию Junior Java Developer

Для начинающего разработчика очень важно не только знать теоретическую базу, но и понимать как все работает под «капотом», поэтому зачастую вопросы, задаваемые на собеседовании, не только проверяют теоретические знания, но и способность их применить.

1. Каким будет значение переменной x, выведенной в консоль, при вызове метода bar()?

bar() < int[] nums = ; for ( int x = 0; x < nums.length; x++ ) < x += nums[x]; >System.out.println(x); >

Код не с компилируется. Этот вопрос в большей степени проверяет внимательность и сосредоточенность кандидата, в данном примере, переменная x существует только внутри цикла и попытка вывести ее вне цикла приведет к ошибке. Теперь, когда все внимание собрано, можно перейти к следующему вопросу.

2. Какой результат выведет вызов метода foo()?

void foo() < String m = "Hello"; System.out.print(m); bar(m); System.out.print(m); >void bar(String m)

Разберем решение детально: С первым выводом Hello вопросов быть не должно, далее в метод bar передаем копию ссылки на строку, теперь на данную строку ссылаются две переменные: m из метода foo и m из метода bar . Так как строки в Java являются immutable, при попытке присоединить к уже существующей строке дополнительное значение World! , в методе bar произойдет создание новой строки и локальная переменная m этого метода будет ссылаться на новую строку со значением Hello World! , при этом в методе foo в результат будет выведено значение переменной m которая по прежнему ссылается на строку Hello .

3. Каким будет результат сравнения в следующем коде?

String s1 = "abc"; String s2 = "abc"; String s3= new String("abc"); System.out.println("s1 == s2 ? "+(s1==s2)); System.out.println("s1 == s3 ? "+(s1==s3)); System.out.println("s1 equals s3 ? "+(s1.equals(s3)));

Вопрос на понимание работы пула строк в Java и на понимание сравнения строк. Разберем детально: Переменная s1 ссылается на строку в пуле уникальных строк в памяти, переменная s2 ссылается на ту же саму строку в пуле уникальных строк, что и переменная s1 , первое сравнение будет true , так как s1 и s2 ссылаются на один и тот же объект. Переменная s3 ссылается на новый объект, который не находится в пуле уникальных строк, так как он создан через new , следовательно второе сравнение будет false , так как сравниваем переменные которые ссылаются на на два разных объекта. Третье сравнение будет true , так как мы сравниваем строки посимвольно на эквивалентность через equals , а содержимое данных строк одинаково.

4. Напишите реализацию синглтона

public class Singleton < private static final Singleton instance = new Singleton(); private Singleton() < >public static Singleton getInstance() < return instance; >public void print() < System.out.println("This is singleton print method"); >> class TestSingleton < public static void main(String[] args) < Singleton instance = Singleton.getInstance(); instance.print(); >>

Основные моменты при реализации синглтона: Конструктор класса должен быть с модификатором доступа private , что не позволит создать экземпляр этого класса за его пределами; должна быть private static final переменная, хранящая единственный экземпляр этого класса и public static метод возвращающий экземпляр этого класса.

Дополнительный вопрос: Реализовать Lazy initialization (Ленивая инициализация) синглтона.

public class Singleton < private static Singleton instance; private Singleton() < >public static Singleton getInstance() < if (instance == null) < instance = new Singleton(); >return instance; > public void print() < System.out.println("This is singleton print method"); >>

Вся особенность Lazy initialization в том, что экземпляр класса создается только в момент первого обращения к нему.

5. Какой результат будет выведен в консоль?

public abstract class OurAbstractClass < public OurAbstractClass() < System.out.println("This is abstract class constructor"); >> class OurDemoClass extends OurAbstractClass < public OurDemoClass() < System.out.println("This is demo class constructor"); >public static void main(String[] args) < OurDemoClass ourDemoClass = new OurDemoClass(); >>
This is abstract class constructor This is demo class constructor

Вопрос на понимание абстрактных классов. Создать экземпляр абстрактного класса нельзя, но он все же имеет конструктор. Более того любой класс имеет конструктор, даже если он не задан явно (он будет добавлен при компиляции). Здесь важно понимать, что при создании экземпляра наследника, самой первой строкой в конструкторе класса наследника будет вызван конструктор класса родителя.

6. Какая проблема возникнет с этим кодом?

public static void main(String[] args) < try < foo(); >catch (IOException e) < e.printStackTrace(); >catch (FileNotFoundException e) < e.printStackTrace(); >public static void foo()throws IOException,FileNotFoundException

Данный код не с компилируется. Этот вопрос на знание иерархии исключений, в данном случае FileNotFoundException унаследован от IOException , первый catch будет перехватывать все исключения и в следующий блок catch управление не будет передано.

7. Каким будет результат выполнения данного кода?

public static void main(String[] args) < ListstringList = new ArrayList<>(); stringList.add("one"); stringList.add("one and a half"); stringList.add("two"); stringList.add("two and a half"); stringList.add("three and a half"); System.out.println("Before " + stringList); Iterator stringIterator = stringList.iterator(); while (stringIterator.hasNext()) < String next = stringIterator.next(); if (next.equals("two and a half")) < stringList.add("three"); >> System.out.println("After " + stringList); >
Before [one, one and a half, two, two and a half, three and a half] Exception in thread "main" java.util.ConcurrentModificationException

При попытке добавить элемент в список возникнет исключение связанное с попыткой изменить список , по которому итерируемся, так как итератор для ArrayList изначально это fail-fast итератор. В таком случае необходимо использовать fail-safe итераторы, они работают с клоном коллекции которую потребовалось изменить. В данном случае можно использовать CopyOnWriteArrayList .

Источник

Оцените статью