Java Guru 🤓
13.3K subscribers
916 photos
15 videos
774 links
Канал с вопросами и задачами с собеседований!

По сотрудничеству и рекламе: @NadikaKir

Канал в перечне РКН: https://vk.cc/cJrSQZ

Мы на бирже: telega.in/channels/javatasks/card?r=lcDuijdm
Download Telegram
Что такое функциональный интерфейс?

Так называется специальная разновидность интерфейса, который определяет тип-функцию, коллбэк.

Чтобы компилятор считал интерфейс функциональным, этот интерфейс должен добавлять единственный абстрактный метод. Вдобавок он может содержать любое количество дефолтных методов с телом. Переобъявление методов класса Object также игнорируется.

Никаких других ограничений на метод не накладывается: он не ограничен в типах аргументов и возвращаемого значения, может иметь любое название и список выбрасываемых исключений (checked и unchecked).

Даже при выполнении всех этих условий, никакие другие разновидности типов кроме interface не могут считаться функциональными интерфейсами.

Дополнительно функциональный интерфейс принято помечать аннотацией
@FunctionalInterface. Наличие этой аннотации не необходимо, но оно даёт дополнительную валидацию: её присутствие на нефункциональном типе спровоцирует ошибку компиляции.

Типичные примеры функциональных интерфейсов: Callable, Supplier, Comparable.


@javatasks #java
5🔥4👍2
Задачи с собеседований: Проверка, является ли бинарное дерево деревом поиска (middle)

— Как определить, является ли заданное бинарное дерево деревом поиска (BST)?

📌 Ключевые моменты:

- Бинарное дерево поиска (BST) — это бинарное дерево, в котором для каждого узла все значения в левом поддереве меньше значения узла, а все значения в правом поддереве больше.
- Для проверки можно использовать рекурсивный подход с отслеживанием допустимых диапазонов значений для каждого узла.
- Как изменить реализацию для работы с любыми типами данных в узлах дерева?

Реализация с числами в узлах на картинке 👆

@javatasks #java
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍3🔥2
Чем отличается final finally finalize?

Тем, что это даже синтаксически разные вещи. Как и вопрос о методах Object, это способ начать разговор.

finalize – метод-финализатор из Object.

final – модификатор, который применяется к переменным, полям, методам и классам. Переменная или поле становится неизменяемым и требует инициализации. Финальный метод нельзя переопределить в наследниках. Финальный класс не может иметь наследников вообще. Используется для создания хорошего API по принципу наименьших привилегий.

Когда в методе используется локальная переменная внешней области видимости, она обязана быть
effectively final. В этом случае ключевое слово final необязательно, но значение всё равно не должно меняться.

finally – часть языковой конструкции try-catch-finally.

Любое исключение, выброшенное из блока try переводит исполнение в самый соответствующий ему catch (при наличии). Этим продиктована необходимость располагать блоки catch в строгом порядке, от типа исключения-наследника, к родителю. В случае multicatch тот же порядок должен соблюдаться и внутри одного catch.
Больше примеров про порядок.

После выполнится блок finally. Выполняется он в любом случае, было исключение или нет. Типичное использование – освобождение ресурсов, обязательные завершающие действия.

Для требующих финализации классов («ресурсов») добавляется интерфейс AutoCloseable, повторяющийся код блока final выносится в метод close и вызывается неявно в конце
try-with-resources. Если в этой конструкции присутствует и явный final, он будет выполнен после.

Java Guru🤓 #java
6👍4🔥4
Чем отличаются checked и unchecked исключения?

Вопрос формулируют по-разному, суть вопроса – объяснение иерархии классов исключений. Подробно описано в документации.

Исключения бывают checked и unchecked. Checked требуется указывать в сигнатуре метода в разделе throws; перехватывать или добавлять в throws в вызывающем его методе. Unchecked можно добавить, но не обязательно, перехватывать не обязательно даже если указана в throws.

🔘Throwable – базовый класс для всего что может быть использовано с оператором throw и в конструкции try-catch
🔘RuntimeException – «нормальные» unchecked-исключения
🔘Error – unchecked исключения, которые означают «серьезные проблемы» приложения. Не должны обрабатываться (хотя технически можно). Теоретически JVM может находиться в невалидном состоянии и не давать больше никаких гарантий
🔘Exception (кроме RuntimeException) – checked исключения

@javatasks #java
Please open Telegram to view this post
VIEW IN TELEGRAM
5🔥4👍3
Зачем нужно ключевое слово default?

Изначально (с Java 1.5) это слово использовалось для объявления дефолтного значения элементов аннотации.

В Java 8 вместе с лямбдами и стримами появилась острая необходимость дополнить стандартные интерфейсы новыми методами. Никто естественно не собирался ломать обратную совместимость, и было предложено добавить методы по умолчанию.

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

В реализации такого метода его дефолтный вариант вызывается тем же синтаксисом, что и внешний класс из вложенного: InterfaceName.super.methodName().

Методы по умолчанию подошли еще на шаг к введению в Java беспроблемной версии множественного наследования – примесям (mixin). Интерфейс не может иметь состояния, поэтому полноценные примеси всё ещё недоступны.


@javatasks #java
👍7🔥41
В каком порядке указываются модификаторы?

Правила применения модификаторов поля описаны в JLS 8.3.1:
🔘Нельзя указывать один модификатор дважды;
🔘Нельзя использовать несколько модификаторов доступа одновременно.

Порядок указания вообще свободный, но обычно используется следующий:
@Аннотации, доступ,
static final transient volatile


Требования для модификаторов метода находятся в JLS 8.4.3:
🔘Те же требования, что и к полю;
🔘Совместно с abstract кроме аннотаций можно использовать только protected или public;
🔘native метод не может использовать strictfp.

И так же не требуется, но рекомендуется использовать такой порядок:
@Аннотации, доступ,
abstract static final synchronized native strictfp

Java Guru🤓 #java
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥61
📎Паттерн Фасад (Facade)

Фасад — это структурный паттерн, который предоставляет унифицированный интерфейс для работы с набором сложных подсистем. Он скрывает сложность системы и упрощает взаимодействие с ней, предоставляя более простой и понятный API для клиента.

Использование:

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

Преимущества:

1️⃣ Упрощает взаимодействие с комплексной системой, предоставляя удобный интерфейс.
2️⃣ Снижает зависимость клиента от конкретных классов подсистем, облегчая поддержку и тестирование.
3️⃣ Уменьшает количество точек взаимодействия с системой, что помогает избежать ошибок и повысить удобство работы.

Недостатки:

1️⃣ Может скрывать избыточную функциональность, ограничивая возможности системы.
2️⃣ Увеличивает количество кода за счёт добавления нового фасадного класса.
3️⃣ Если фасад слишком абстрактен, может стать сложным для понимания и поддержки.

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

Java библиотека #java
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥106👍2
Что такое короткое замыкание логического оператора?

Логические операторы || и && лево-ассоциативны, то есть их параметры вычисляются слева направо. Если первое значение оказалось true в || или false в && – конечный результат уже предрешен, он будет тем же. В этом случае происходит так называемое «короткое замыкание» (short-circuiting) – оставшийся второй аргумент не вычисляется за ненадобностью.

Эту особенность иногда удобно эксплуатировать, например для проверки на null в одну строку:
return param != null && param.getBoolMember();


Но иногда такая ситуация влечет за собой неожиданные плавающие баги, если второй аргумент – не переменная, а функция с побочным эффектом. Для этой ситуации введены версии операторов без короткого замыкания: | и &. Это логические вариации «битового и» и «битового или».

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


Java Guru🤓 #java
8👍4🔥1
👩‍💻 31 июля стартует курс «Java-разработчик» от OTUS — это то, что нужно, если вы хотите успешно вкатиться в разработку в 2025

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

Если вы сисадмин, тестировщик, аналитик или просто хотите освоить программирование с нуля — этот курс для вас.
Мы научим создавать серверные веб-приложения, работать с PostgreSQL, Kafka и Kubernetes, формировать портфолио и готовить резюме под Middle-Java-Dev.

🎁 Дарим промокод, который дает скидку на обучение - JAVA7

👉 Оставьте заявку и и присоединяйтесь к группе: https://vk.cc/cNTt7j

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍2🔥2
Перечислите целочисленные битовые операторы

Во-первых, стоит освежить знания о бинарном представлении целых знаковых чисел. В Java используется подход two's complement – для значения 0 все биты нули, при переполнении максимального значения на 1 получается минимальное.

Бинарные битовые операторы &, | и ^ действуют очевидным образом: выполняют побитовые «И», «ИЛИ» и «исключающее ИЛИ» (XOR) соответственно. Здесь особенно интересен XOR:

Применение к значению «исключающего или» с одним и тем же параметром два раза дает то же значение. За счет этого его можно использовать как простейшее шифрование, аргумент выступит ключом;
С помощью XOR реализуется XOR-обмен – алгоритм обмена значениями переменных без дополнительной памяти и без риска переполнения. Это также один из популярных вопросов для собеседования.

Унарный оператор битового отрицания (дополнения) ~. Эквивалентен «исключающему или» с самим собой – все биты инвертируются. ~x эквивалентно -x-1. ~0 == -1.
Битовые сдвиги: левый << правый знаковый >> и правый беззнаковый >>>. Левый операнд – что сдвигать, правый – на сколько битов.

Второй параметр, дистанция сдвига, должен быть не больше доступных разрядов – 31 для int и 63 для long. Если передано значение больше – используются младшие 5 и 7 битов соответственно. То есть для int переменной x << 33 эквивалентно x << 2.

a << b эквивалентно умножению a на 2 в степени b.
a >> b совпадает с делением на 2 в степени b, с округлением вниз. Для положительных a то же что a/pow(2,b). Для не делящихся нацело на pow(2,b) отрицательных это a/pow(2,b)-1.

Беззнаковый сдвиг вправо трактует число не как two's complement, а как беззнаковое. То есть Integer.MIN_VALUE будет сдвинут так, как будто это сдвигается число на 1 большее чем Integer.MAX_VALUE.

Беззнакового сдвига влево не существует, потому что он совпадал бы со знаковым сдвигом, и был бы избыточным.


Java Guru🤓 #java
🔥64👍3
🔍Тестовое собеседование с Java-разработчиком из Oracle завтра

23 июля(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.

Как это будет:
📂 Алексей Ушаровский, разработчик с опытом работы в Oracle и EPAM, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Алексей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Алексею

Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.

Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot

Реклама.
О рекламодателе
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍2🔥2
Как узнать, является ли A подтипом B?

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

instanceof – бинарный оператор, самый быстрый и самый используемый. Если есть экземпляр A и можно указать B явно, выбирать надо его. Если A (точнее тип хранящей экземпляр A переменной) и B не из одной цепочки наследования – экземпляр точно не может быть подтипом B и компиляция упадет с ошибкой inconvertible types.

Class::isInstance – метод принимает параметром объект типа A. Его стоит выбрать, когда экземпляр A в наличии, но B – неизвестный на этапе компиляции тип. То есть, для переменных A a и Class bClass, можем проверить bClass.isInstance(a).

Class::isAssignableFrom – принимает Class<A>. Единственное, что остается, если экземпляра A нет. bClass.isAssignableFrom(aClass).

Есть еще четвертый способ – имея экземпляр типа A привести его к B. Если типы были несовместимы, приведение выбросит ClassCastException. Это во всех смыслах плохой способ, построению логики программы на исключениях нет оправдания. Подробная аргументация описана в Effective Java Item 57.


Java Guru🤓 #java
6👍5🔥3
Чем анонимный внутренний класс отличается от лямбды?

Лямбда-выражение имеет более легковесный синтаксис. Не нужно явно указывать тип функционального интерфейса, который лямбда реализует – он автоматически выведется из контекста. Лямбда-выражения добавлены в язык в первую очередь как синтаксический сахар.

С другой стороны, у класса есть поля. Экземпляр анонимного класса сохраняет свое состояние между вызовами, и меняет его при необходимости. Для лямбды доступен лишь захват и effectively final использование внешних переменных.

Лямбдой реализуется только функциональный интерфейс. Функциональный интерфейс – это тип с единственным абстрактным методом. Анонимным классом же можно расширить любой расширяемый класс или реализовать интерфейс с любым количеством абстрактных методов.

Анонимный класс создает новый скоуп, лямбда работает в текущем. Это значит, что объявление переменной с именем, которое уже используется снаружи, в лямбде вызовет ошибку компиляции «variable is already defined», в анонимном классе скроет (shadowing) внешнюю переменную.

С точки зрения реализации JVM, для лямбды не создается дополнительного .class файла, как это происходит для анонимного класса. Соответственно, не происходит и обычной загрузки и верификации класса. Вместо этого используется механизм invokedynamic и класс генерируется на лету с помощью LambdaMetafactory. Так что лямбда-выражения обычно работают быстрее.


Java Guru🤓 #java
🔥124👍4🌭1
Как объявить переменное количество аргументов метода?

Для этого используется аргумент-массив. В нем может находиться любое количество элементов. Еще с Java 5 для этого случая добавился синтаксический сахар: Variable-length argument (vararg). Три точки ... ставятся между типом и именем переменной, и становится можно передать любое количество аргументов, не упаковывая их в массив.

На уровне байткода применение массива и варарга не отличаются: vararg-параметр Foo... превращается в параметр-массив Foo[], на этапе вызова подставляется неявное инстанцирование и заполнение массива.

Чтобы избежать неоднозначностей, на vararg наложено ограничение: им может быть только один последний аргумент.

Vararg, как массив, может быть пустым. Иногда это приводит к неочевидному поведению. Допустим, имеем две перегрузки метода с аргументами int... и float.... Вызов такого метода без параметров попадает в вариант с int, как с более специфичным типом. Наличие же перегрузки с несовместимыми типами, например int... и boolean..., приводит при вызове к ошибке компиляции «Ambiguous method call».

Когда типом варарга используется generic-параметр, возникает warning «Possible heap pollution from parameterized vararg type». Вам нужно убедиться, что вы понимаете в чем этот риск, что ваш код не приводит к heap pollution, и уведомить об этом компилятор аннотацией
@SafeVarargs.

Java Guru🤓 #java
👍103🔥2
Что будет при вызове /api/customers/{5}, если записи c id 5 нет
👍6🔥3
🔥6👍51
This media is not supported in your browser
VIEW IN TELEGRAM
Технологии, железо и роботы на Yandex Robotics Day уже 16 августа!

На складах Маркета, Леманы Про, Перекрестка, Лавки и других компаний работают роботы Яндекса, которые помогают быстро сканировать товары, собирать посылки и перемещать заказы. Чтобы все функционировало быстро и точно, специалисты Яндекс Роботикс постоянно улучшают их.

16 августа в Москве пройдет митап, на котором они расскажут, как именно это делают:
— Серёжа Стариков выступит с докладом про коммуникационную платформу Yandex Robotics и ее применение в Yandex RMS
— Дима Мовчан объяснит, как команда создает умную роборуку с помощью imitation learning и RL
— Максим Пшибло расскажет, как с помощью Yandex Robotics Management System управлять несколькими роботами и какие алгоритмы необходимы этой системе

Кроме докладов в программе презентация нового робота, выставка тех, которые уже вовсю работают на складах, нетворкинг и неформальное афтепати с экспертами Яндекс Роботикс.

Регистрируйтесь и зовите коллег!

Реклама. ООО "ЯНДЕКС МАРКЕТ". ИНН 9704254424.
5👍1
Что если блок finally выбросит исключение?

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

Вопрос подразумевает второй случай, когда исполнение попадает в finally в момент выброса исключения из try. Исключение из finally заменит собой исключение из try и пойдет вверх по стеку вместо него. Оригинальная проблема будет попросту забыта.

Такая маскировка исключения усложняет отладку, лучше избегать её. Например IntelliJ IDEA выводит соответствующее предупреждение на оператор throw внутри finally.


Java Guru🤓 #java
6👍6🔥2
Как скопировать массив?

Object.clone()
и System.arraycopy(). Нативные способы копирования, самые быстрые из возможных. Унаследованный от базового класса clone() копирует весь массив без лишних аргументов. arraycopy(), наоборот, максимально гибкий – позволяет копировать часть массива и указывать массив, в который копировать.

Arrays.copyOf(), Arrays.copyOfRange() и все их перегрузки. Утилитарные методы, которые дают более специализированные способы копирования. Внутри все используют System.arraycopy().

Копирование через стрим.
Arrays.stream(sourceArray).toArray(). Удобно когда нужно встроить дополнительные промежуточные операции.

Сторонними библиотеками. Обычно обеспечивают дополнительные удобства, такие как проверка корректности параметров, приведения типов, и прочие. Пример – класс SerializationUtils из Apache Commons.

Все перечисленные способы создают поверхностную копию – оба массива в итоге ссылаются на одни и те же объекты. Лучший способ создать глубокую копию – реализовать ее вручную. Сначала оператором new создается пустой массив нужного размера, затем в цикле заполняется копиями элементов. Stream API здесь может дать удобный интерфейс реализации, и оптимизировать копирование с помощью многопоточности.

Самый быстрый, но ужасный по эффективности способ глубокого копирования массива без реализации копирования отдельных элементов – сериализация+десериализация. Сложно придумать оправдание такому плохому способу для продакшна, но этот метод вполне подходит для реализации быстрого прототипа, или для тестового кода.


Java Guru🤓 #java
👍93🔥3
🚀 Apache Kafka — незаменимый инструмент для масштабируемых микросервисных архитектур! Хотите узнать, как избежать 80% типичных ошибок и построить отказоустойчивый обмен сообщениями?

📅 30 июля в 19:00 МСК — открытый вебинар!

На мероприятии мы подробно разберём:
🔹 Взаимодействие через брокер сообщений
🔹 Конкурирующие получатели и порядок доставки
🔹 Базовые паттерны использования Kafka

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

🎟 Зарегистрируйтесь прямо сейчас — вебинар проходит в преддверии старта курса «Apache Kafka», и все участники получат скидку на обучение: https://vk.cc/cO4kns

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
4👍2🔥2🥱1