Java Interview Tasks
4.5K subscribers
201 photos
1 file
128 links
Реальные вопросы и задачи с собеседований.
Оригинальный авторский контент.
Актуальный материал.
Уровень вопросов от junior до supersenior.

Автор канала - @alexzelentsov

По рекламе: @alexzelentsov и https://telega.in/c/java_interview_tasks
Download Telegram
🔍 Ответ на задачу про вывод элементов списка

Тут есть одна особенность: индекс увеличивается до получения элемента из списка благодаря ++index.

При таком подходе, цикл начинает с индексом 1, а значит будет выбирать имена начиная с "Боря", а "Аня" будет пропущена. Значение index будет увеличено на 1, после чего произойдет проверка условия index < names.size(), и условие будет истинным до тех пор, пока индекс не станет равен размеру списка.

Таким образом, в результате выполнение кода мы увидим такой вывод на консоли:

Боря
Вова
А дальше будет эксепшен, так как следующего индекса в массиве уже нет.


🥳 Надеюсь, этот разбор был полезен! Не забудьте лайкнуть пост, подписаться на канал и оставить комментарий, если у вас есть вопросы или дополнения!

#java #coding #++i #java_interview_tasks
👍17🔥2🐳21
🔍 Ответ на задачу про логические операторы

Давайте разберем работу логических операторов в данном коде на Java. У нас есть три логические переменные: a, b, и c, со значениями true, false, и false соответственно. В условии if используется комбинация операторов (логическое "ИЛИ") и && (логическое "И").

Стоит помнить, что оператор && имеет более высокий приоритет, чем оператор . Поэтому выражение b && c будет вычислено первым. Но поскольку b равно false, а c также false, это выражение дает в результате false.

Далее, выражение a false будет всегда истинным, так как a равно true. Следовательно, полное условие в if равно true, и будет выполнена первая ветка блока:

1

Когда дело касается вложенных логических операторов в условных выражениях, расстановка скобок может значительно упростить понимание кода и избежать путаницы. В данном случае, добавим скобки для ясности:
boolean a = true;
boolean b = false;
boolean c = false;

if (a || (b && c)) {
System.out.println("1");
} else {
System.out.println("2");
}

Скобки вокруг выражения (b && c) четко определяют, что это будет вычислено в первую очередь. Это не только делает код более понятным, но и исключает возможность неправильной интерпретации, особенно если у вас большой и сложный условный оператор.

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

✍️ Научитесь писать чистый и понятный код! Поддержите эту идею, поставив лайк, подписывайтесь на канал и оставляйте комментарии с вашими мыслями об использовании скобок в коде.

#java #logicaloperators #boolean #clean_code #java_interview_tasks
🔥9👍62
Наверняка эта задачка входит в число хрестоматийных и встречается на собеседованиях по #Java, но поскольку я по ним не хожу, пришлось убить часок на разбирательство с ней. Поделюсь с вами; вдруг кто-то тоже встретит.

🎓 Дано
Ванильный пул потоков на голом JDK (аналоги из класса Executors не подходят):
var threadPool = new ThreadPoolExecutor(
corePoolSize, // 3
maxPoolSize, // 30
keepAliveTime, // 60
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(maxQueueLength), // 100
Executors.defaultThreadFactory(),
new DiscardPolicy()); // could also be a logging implementation


И некий метод, который сначала просто напихивает задачки в этот пул:
List<Future> futures = new ArrayList<>();
futures.add(threadPool.submit(task));


, потом идёт по своим делам, а когда заканчивает с ними, проверяет готовность задачек и, если надо, дожидается завершения каждой, чтобы продолжить работу дальше:
for (Future future : futures) {
try {
future.get();
}
catch (Exception e) {
log.error("Failed to get task result from future", e);
}
}


🔍 Найти
Какого _🙊_ в некоторых случаях метод намертво зависает на вызове future.get()?
При этом в дампе потоков нет никаких следов задач, которые бы зависли/зациклились/заблокированы.

🔑 Решение
Вариант 1. Добавить таймаут в метод future.get(). Да, это решит проблему, но не даст понять, почему она появилась.

Вариант 2. Извернуться как-нибудь так, чтобы прийти к вызову вида CompletableFuture.allOf(c1, c2, c3).join(). Наверняка так можно (не проверял), но выглядит избыточно сложно, должно же работать и так.

Вариант 3. Обернуть вызов future.get() вот в такое условие:
    if (future.isDone()) {
future.get();
}

Казалось бы, смысла в нём нет, ведь если задача не завершена (isDone() == false), то мы просто дождёмся её завершения при вызове get(). Но нет. Когда мы имеем дело с ThreadPoolExecutor, то при вызове submit() он в качестве имплементации Future возвращает экземпляр FutureTask, у которого метод isDone() выглядит так:
    public boolean isDone() {
return state != NEW;
}

, то есть "сделанной" считается любая не новая задача (в том числе когда она ещё в работе).

А метод FutureTask.get() устроен так:
    public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}

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

Но если бы задача, на которой завис наш поток, была в состоянии COMPLETING, мы наверняка увидели бы соответствующий ей поток в дампе, а раз его нет, значит, она в NEW.
А как она могла оказаться NEW, если все задачи вроде как были переданы пулу на исполнение? Видимо, он её не взял. А почему не взял? Правильно — из-за переполнения очереди, ведь она ограничена (new LinkedBlockingQueue<>(maxQueueLength)). А почему тогда это не привело к ошибкам и прерыванию всего процесса? Верно, из-за с виду безобидной new DiscardPolicy(), которая просто дропает не влезшие задачки (и логирует их, как было в нашем случае).

Вся цепочка кратко:
— не влезающие в очередь задачи молча отбрасываются политикой пула, оставляя им статус NEW;
— видя этот статус, метод future.get() впадает в бесконечное ожидание;
— исключить ожидание можно добавлением проверки на NEW в виде вызова future.isDone().
⚠️ Если очередь будет большой, а задачи — долгоиграющими, можно нарваться на случай, когда задача уже в очереди и имеет шанс быть выполненной, но цикл с вызовом get() её не подождёт. В этом случае решение должно быть другим.

Мораль: пишите однопоточные приложения🤪
🔥14👍43😁2
🔍 Ответ на задачу про сравнение строк в Java

Давайте разберемся, что напечатает приведённый код! 🚀
String a = "ab";
String b = "a" + "b";
String c = "a";
String d = c + "b";

System.out.println(a == b);
System.out.println(a == d);
System.out.println(a.equals(d));

Этот код выводит на экран:

true — В первом сравнении (a == b), оба операнда являются строковыми литералами, и компилятор оптимизирует их, так что они указывают на один и тот же объект в строковом пуле.
false — Во втором сравнении (a == d), d создается путем конкатенации на этапе выполнения, из-за чего она не будет указывать на тот же объект в строковом пуле, что и a.
true — В третьем сравнении (a.equals(d)), метод equals сравнивает содержимое строк, а не их ссылки, потому этот результат будет true, так как содержимое одинаково.
Интересно, правда? 😄 Не забудьте, что использование оператора == для сравнения строк может привести к неожиданным результатам. Для проверки эквивалентности строк на уровне содержимого всегда используйте equals.

Ставьте лайк, подписывайтесь на канал и оставляйте комментарии! 💬👉

#Java #StringComparison #ИзучаемJava #java_interview_tasks
👍122🔥2
🔍 Ответ на задачу про исключения в Java

Давайте разберемся, что произойдет при выполнении представленного кода! ⬇️
public class ExceptionTest {
public static void main(String[] args) {
try {
System.out.println("A");
int result = 10 / 0; // Здесь возникнет ArithmeticException
System.out.println("B"); // Эта строка не будет выполнена
} catch (ArithmeticException e) {
System.out.println("C");
} finally {
System.out.println("D");
}
System.out.println("E");
}
}

Рассмотрим выполнение программы по шагам:

"A" будет напечатано, так как это первое действие в блоке try.
Далее происходит деление на ноль (10 / 0), что вызывает ArithmeticException.
Блок catch перехватывает исключение, и "C" выводится на экран.
Блок finally выполняется всегда, независимо от того, поймано ли исключение, таким образом, "D" будет напечатано.
После выполнения всех блоков try-catch-finally программа продолжает выполнение, поэтому "E" также будет напечатано.
Итак, правильная последовательность вывода: A, C, D, E. 🎉

Не забудьте поставить лайк, подписаться на наш канал и оставляйте комментарии! 💬👉

#Java #Исключения #ОбработкаИсключений #java_interview_tasks
👍11🔥3🙏2
🔍 Ответ на задачу про работу с многопоточностью в Java

Давайте разберёмся, что происходит при запуске данного кода! 🔍
public class ThreadTest {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " - " + i);
}
});

thread.start();
thread.run();
}
}

Объяснение:

thread::start — запускает новый поток, который выполняет переданное лямбда-выражение. В отдельном потоке выводятся значения от 0 до 4. Поток выполняет метод run, и будет выполняться параллельно с основным потоком.

thread::run — здесь метод run вызывается в основном потоке так, как если это был обычный метод, а не в отдельном потоке. Это означает, что в основном потоке без создания нового потока пойдет выполнение того же самого кода ещё раз, так как метод run просто выполняется в потоке, из которого он был вызван.

Следовательно, программа завершится успешным выполнением, и будут выведены две последовательности от 0 до 4. Таким образом, правильный ответ — Код скомпилируется и выполнится, но "thread::run()" будет выполняться в основном потоке.

Эта ситуация — прекрасный пример, демонстрирующий разницу между методами start() и run() в многопоточности. 🌟

Не забудьте поставить лайк, подписаться на канал и оставлять комментарии с вашими идеями и вопросами! 💬👉

#Java #Многопоточность #Concurrency #java_interview_tasks
🔥8👍73
🔍 Ответ на задачу про исключение в стримах Java! 🚨

При выполнении данного кода возникнет исключение NullPointerException.
Давайте разберём, почему это происходит. 🤔

Код:
 
public static class Fee {
private String description;

public Fee(String description) {
this.description = description;
}

public String getDescription() {
return description;
}
}

public static void main(String[] args) {
List<Fee> fees = List.of(new Fee(null));
String s = fees.stream()
.map(Fee::getDescription)
.findFirst()
.orElse("1");
System.out.println(s);
}


Проблема возникает в строчке findFirst(). Метод .map(Fee::getDescription) создаёт стрим, где первый элемент имеет значение null из-за description равного null в объекте Fee.

Когда findFirst() пытается вернуть найденное значение — а это null — метод Optional.of() выбрасывает NullPointerException, поскольку Optional.of() не позволяет обёртывать null значениями. Для обработки null значений нужно использовать Optional.ofNullable().

Чтобы исправить это и избежать исключения, можно немного изменить этот код:

String s = fees.stream()
.map(Fee::getDescription)
.filter(Objects::nonNull) // добавляем этот фильтр
.findFirst()
.orElse("1");
Этот код сначала фильтрует все null значения из стрима и предотвращает NullPointerException.

Если вам понравился разбор, не забудьте поставить лайк, подписаться и оставить комментарий! 😊

#streamAPI #nullHandling #java_interview_tasks
🔥21👍101🤝1
🔍 Ответ на задачу про MegaClass 📊

Давайте разберём, что именно будет напечатано при выполнении данного кода. Здесь мы имеем класс MegaClass с переопределёнными методами equals() и hashCode(), и работаем с объектами этого класса в HashSet. Обратите внимание на влияние изменения состояния объекта на результат работы методов, связанных с коллекциями.

Пояснения:

A: set.add(o) - Возвращает true, потому что объект o только что добавлен в set.

B: set.contains(new MegaClass(10)) - Возвращает false, так как после изменения поля i, o имеет hashCode = 1000, который не совпадает с 1000 у new MegaClass(10).

C: set.add(new MegaClass(10)) - Возвращает true, объект с hashCode равным 10 не найден в set, потому что изменили o.

D: set.contains(new MegaClass(1000)) - Возвращает false, так как теперь oбъект, у которого hashcode 1000, содержится в set, но предыдущий объект был добавлен с хешкодом 10 и поэтому он не найдется теперь.

E: new MegaClass(10).equals(new MegaClass(1000)) - Возвращает false, так как поля i отличаются.

📈 Этот пример отлично демонстрирует, насколько важно соблюдать неизменяемость полей, участвующих в вычислении hashCode() и equals(), при работе с коллекциями.

Если вам понравился анализ этого кода и вы хотите узнавать больше, ставьте лайк, подписывайтесь на канал и делитесь своими мыслями в комментариях! 👍💬

#java #hashcode #equals #collections #java_interview_tasks
👍8🔥85
🔍 Ответ на задачу про работу String.valueOf() с null! 💡

String s1 = String.valueOf((Object) null);
String s2 = String.valueOf(null);
System.out.println(Objects.equals(s1, s2));


Вызов String.valueOf((Object) null) в первой строке приводит к тому, что Java воспринимает null как объект, и возвращает строку "null".

Во второй строке, String.valueOf(null) вызывает перегруженный метод, который принимает char[]. Но поскольку передан null, вызов упадет с NPE. 🚀

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

Спасибо, что дочитали до сюда) Не забудьте поставить лайк, оставить комментарий и подписаться! 🙌

#Java #NullPointerException #String #java_interview_tasks
👍273🔥2
🔍 Ответ на задачу про сравнение лонгов:🌟


В методе main, вызывается checkEvent с новым объектом Event, где id инициализирован null. Поэтому, при сравнении (event.id == 42) произойдет неявный вызов метода java.lang.Long.longValue(), что вызовет NullPointerException и программа завершится с ошибкой.

Программа выведет исключение:

Exception in thread "main" java.lang.NullPointerException
👨‍💻 Советы: всегда проверяйте null-ссылки перед использованием объектов во избежание необработанных исключений!

Интересная задача? Поддержите лайком и оставьте комментарий! 😊👇

#java #exceptionHandling #java_interview_tasks
🔥9👍7🙏1
🔍 Ответ на задачу про Immutable объекты в Java 🔒

✍️ В Java объект типа String является неизменяемым (immutable). Операция s1.concat(" World") создает новый объект строки и присваивает его s1. Переменная s2 остается ссылаться на старую строку "Hello". Поэтому программа выведет: Hello

Если задача понравилась, ставьте лайк 👍, подписывайтесь на канал и пишите свои ответы и вопросы в комментариях! Обсудим вместе 😊

#java #string #immutable #interview #java_tasks #java_interview_tasks
👍181🔥1😢1
🔍 Ответ на задачу про работу с HashMap и null 🗺

✍️ HashMap в Java разрешает использовать ключ null.
Правильный ответ: 5

Если задача была полезна, ставь лайк 👍, подписывайся и пиши свое решение или вопросы в комментариях! 💬

#java #hashmap #null #map #java_tasks #java_interview_tasks
🔥8👍51