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

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

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

Мы на бирже: telega.in/channels/javatasks/card?r=lcDuijdm
Download Telegram
Как реализовать метод hashCode?

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

Результат hashCode() должен быть одинаковый для равных в смысле equals объектов. Обычно для этого значение хэш-кода вычисляется на основе значений полей, которые участвуют в equals(). Но и возвращение одной и той же константы 42 для любого экземпляра класса тоже будет валидной реализацией.

Результат hashCode() должен быть равномерно распределен. Это правило не такое строгое как остальные. Его нарушение не сломает программу, хотя может сильно ухудшить производительность. Поэтому константа 42 – допустимая, но не лучшая идея. Вместо этого все значения полей сначала приводятся к int: boolean превращается в любую пару констант, null в 0, для ссылочных типов берется их hashCode(). Затем все эти значения смешиваются с помощью бинарного оператора XOR (^). Дополнительно для лучшего распределения можно применять битовые сдвиги. Если вы владеете информацией о распределении значений полей в конкретно вашем случае, эту реализацию можно улучшить.

Результат hashCode() должен быть одинаковый на протяжении времени жизни объекта. Если вычисление хэш-кода зависит от переменных значений, сохраните его значение во внутреннее поле при первом вызове. При следующих вызовах сразу возвращайте это закэшированное значение.


Java Guru🤓 #java
👍95🔥5
Чем отличается Closeable от AutoCloseable?

Интерфейс AutoCloseable представляет объект-хранилище некоего ресурса, пока тот не закрыт. В единственном его методе close() объявляется логика закрытия этого ресурса. Пример – дескриптор открытого файла (ObjectOutputStream).

Особенность этого интерфейса в том, что его применение позволяет использовать объект в языковой конструкции try-with-resource. Всё это появилось в Java версии 7.

До Java 7 уже существовал похожий интерфейс – Closeable. Смысл его точно такой же. Он всё еще доступен в стандартной библиотеке для обратной совместимости, но в новом коде рекомендуется использовать AutoCloseable. Чтобы экземпляры старого Closeable тоже можно было использовать в try-with-resource, новый интерфейс был добавлен его родителем.

Проблема старого интерфейса Closeable была в узости типа исключений, которые может выбрасывать close(). Ковариантность позволила расширить тип в базовом интерфейсе AutoCloseable с IOException до Exception.

Еще одно отличие – контракт метода close(). Старый Closeable требует его идемпотентности, тогда как новый AutoCloseable разрешает методу иметь побочные эффекты.


Java Guru🤓 #java
👍103🔥3
Что будет результатом кода?
👍52🔥2
Что будет результатом кода?
Anonymous Quiz
16%
Ошибка компиляции
8%
123456
64%
234567
1%
4567
11%
IllegalStateException
👍122🔥2
🤖 А ты справишься с тестом по Kotlin?

🏆 Пройди тест из 10 вопросов, проверь свой уровень знаний и получи скидку на онлайн-курс «Kotlin Backend Developer. Professional» от OTUS!

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

🎫
Курс можно приобрести в рассрочку

➡️ Пройти тест и забрать скидку: https://vk.cc/cLkQRQ

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

Интерфейс Comparable определяет естественный порядок среди объектов. Java Collections Framework активно использует этот порядок. По нему упорядочены элементы SortedSet/SortedMap, им упорядочиваются элементы списков и массивов в методе sort().

Порядок определяется единственным методом compareTo. Отрицательный результат означает что текущий объект «меньше» чем переданный параметром, 0 – равен, положительный – больше. Рекомендуется чтобы равные с точки зрения equals объекты всегда были равны с точки зрения compareTo.

С математической точки зрения это должен быть линейный порядок. Он требует выполнения четырех свойств:
1. Антирефлексивность: x.compareTo(x) всегда 0;
2. Антисимметричность: если x.compareTo(y) > 0, то y.compareTo(x) < 0;
3. Транзитивность: если x.compareTo(y) > 0 и y.compareTo(z) > 0, то x.compareTo(z) > 0;
4. Полнота: отношение определено для любых объектов класса (кроме null).

Интерфейс Comparator – это логика Comparable, вынесенная в отдельный объект. Компаратор реализует паттерн Стратегия. Большинство платформенных методов, использующих Comparable имеют перегруженный вариант с не-comparable объектом и внешним компаратором.

Comparator бывает полезен, когда класс предоставлен сторонней библиотекой, и нет возможности его менять. Другой случай – особая логика упорядочивания, не свойственная классу объектов в общем, но нужная для отдельной ситуации.

Кроме основного метода compare(), в компараторе есть набор утилитарных методов для комбинирования и модификации компараторов. Все они возвращают новый компаратор, позволяя сделать его иммутабельным.


Java Guru🤓 #java
8👍5🔥4
Можно ли наследовать аннотацию?

Можно понять этот вопрос по-разному. Если имеется в виду, передается ли аннотация класса-родителя классу-наследнику, ответ – по умолчанию нет. Но наследование можно включить, если на объявлении аннотации поставить мета-аннотацию @Inherited. Это работает только для классов, переопределенные методы нужно аннотировать заново.

Другой возможный смысл вопроса – наследование самих типов-аннотаций. Аннотация, как класс или интерфейс представляется в системе ссылочным типом, она тоже компилируется в .class-файл. Вы можете создать переменную с типом, скажем, java.lang.Override.

Но в отличие от других ссылочных типов, объявление аннотации (
@interface) не может иметь секций extends или implements. Это ограничение добавлено просто чтобы не усложнять систему типов. В скомпилированном коде все типы-аннотации – это интерфейсы, унаследованные от Annotation.

Java Guru🤓 #java
🔥8👍52
Чем CompletableFuture отличается от Future?

Future – интерфейс, который представляет пока еще недовычисленный результат. Когда породившая его асинхронная операция заканчивается, он заполняется значением. Метод get блокирует выполнение до получения результата, isDone проверяет его наличие. К примеру результат выполнения задач в ExecutorService, ForkJoinTask, реализует интерфейс Future.

CompletableFuture появился в Java 8. Это класс-реализация старого интерфейса Future, а значит всё сказанное выше справедливо и для него. Вдобавок к этому, CompletableFuture реализует работу с отложенными результатами посредством коллбэков. Метод thenApply регистрирует код обработки значения, который будет автоматически вызван позже, когда это значение появится.

В Java 9 прогресс пошел дальше, и появилась библиотека Flow API. Это встроенная реализация реактивных стримов. Реактивный стрим, сильно упрощая, – это более общий случай, последовательность отложенных значений. Другая их реализация – популярная, но не входящая в стандарт библиотека
Reactive Extensions (RxJava).

Java Guru🤓 #java
👍63🔥3
Классы BigInteger и BigDecimal

BigInteger и BigDecimal – иммутабельные числа с заданной точностью. Эти классы – наследники Number, наряду с обертками примитивных чисел. В классах также реализованы базовые математические операции. Наибольший интерес представляет класс BigDecimal – дробное число.

Числа с плавающей точкой (float, double) хранят свои значения в памяти в экспоненциальном виде: знак-порядок-мантисса. Этот факт приводит к неочевидным с точки зрения десятичной системы округлениям при математических операциях.

BigDecimal хранит число в десятичном виде: немасштабированное значение (intVal), размерность (scale), точность (precision) и знак. Значение раскладывается на эти компоненты как intVal ÷ 10^scale. Точность – количество используемых знаков, без учета нулей в начале, но с учетом нулей в конце. Точность числа 0.0010 – 2.

Экземпляр BigDecimal можно создавать из числа с плавающей точкой, и из строки. В первом случае преобразование из экспоненциального в десятичный вид может привести к неожиданной точности, так что рекомендуется использовать строку.
У класса BigDecimal есть редкая особенность: у него не согласованы методы equals() и compareTo(). equals() сравнивает значения с точки зрения структуры объекта – компоненты точности, размерности и значения сравниваются по отдельности. Так equals на числах 0.1 и 0.10 вернет false – у них разная точность, 1 и 2. compareTo() сравнивает числа с математической точки зрения – на тех же 0.1 и 0.10 compareTo вернет 0.

Вместе с BigDecimal активно используется класс MathContext. Это точность, плюс план действий когда значение в нее не влазит – стратегия округления. MathContext можно передавать как в конструктор, так и в математические операции.

BigInteger можем рассматривать как частный случай BigDecimal. Он используется для целых чисел, больших чем Long.MAX_VALUE.


Java Guru🤓 #java
🔥8👍43
Назовите несколько примеров java.lang.Error

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

• AnnotationFormatError – AnnotationParser (Reflection) обнаружил дефект .class-файла аннотации;
• AssertionError – провалилась проверка утверждения (ключевое слово assert). Используется в тестах;
• CoderMalfunctionError – неисправность при кодировании/декодировании Unicode (в пакетах
java.io/java.nio);
• ServiceConfigurationError – проблема с загрузкой сервисов в ServiceLoader (Service Provider Interface);
• IOError – серьезная ошибка ввода-вывода;
• ThreadDeath – особенная ошибка: в отличие от остальных наследников Error, это – «нормальное явление», сигнал асинхронного завершения текущего потока;

• LinkageError – после перекомпиляции случилось непоправимое. Предок для 15 различных ошибок формата .class-файлов, загрузки классов, пропажи используемых членов, и прочего.

• VirtualMachineError – JVM сломалась. Абстрактный класс-предок для:
◦ StackOverflowError – переполнение стека вызовов, обычно встречается при бесконечной рекурсии;
◦ OutOfMemoryError – кончилась память, и GC уже не помогает;
◦ InternalError – внутренняя проблема JVM. Её единственный наследник ZipError не используется с Java 9;
◦ UnknownError – что-то другое.


Java Guru🤓 #java
🔥62👍2
Какие данные есть в исключении?

Разработчик может добавлять в исключение, как и в любой другой класс, произвольные поля и методы. Но у всех исключений есть общая часть, унаследованная от Throwable. В базовых Exception, RuntimeException и Error нет ничего кроме неё.

Cause – другое исключение, которым было вызвано это. Опционально. Можно задать через сеттер или аргумент конструктора, но задается не больше одного раза.

Message – сообщение ошибки. Устанавливается в конструкторе. Кроме обычного геттера есть getLocalizedMessage, который в наследниках может возвращать локализованный вариант сообщения.

Stack Trace – стек вызовов методов потока до того места, где сообщение было сконструировано (не выброшено!). JVM позволено терять часть, или даже все фреймы стека. Есть сеттер для фреймворков удаленного вызова (RPC). Сеттер можно отключить параметром конструктора writableStackTrace.

Suppressed – список исключений, которые были выброшены и подавлены, пока это исключение шло к обработчику. Сюда попадают подавленные исключения финализации ресурсов при использовании try-with-resource. Сеттер доступен и для пользовательского кода. Подавление можно отключить параметром конструктора enableSuppression.


Java Guru🤓 #java
👍93🔥3
⚡️ Квиз на знание Java

Пройти тестирование — сложно! А ты справишься?
21 вопрос, 30 минут

Проверь себя - пройди квиз и оцени свой уровень навыков, а также свою готовность к обучению на курсе — «Разработчик на Spring Framework» от OTUS.

💻 За 5 месяцев обучения ты освоишь современные возможности Spring, научишься быстро проходить путь от идеи до production-grade, создавать Web-приложения на микросервисной архитектуре и решать высокоуровневые задачи по разработке.

👉 ПРОЙТИ ТЕСТ: https://vk.cc/cLsz9h

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

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Please open Telegram to view this post
VIEW IN TELEGRAM
👍32🔥2
Какие значения возвращают мутаторы Map?

Давайте разберемся с этой путаницей раз и навсегда.

• Методы put (put, putIfAbsent) возвращают старое значение.

• Методы работы с множеством элементов (putAll, replaceAll, clear) не возвращают ничего.

• remove и replace с указанием не только ключа, но и старого значения, возвращают boolean; без указания – это самое старое значение.

• Методы с коллбэками (computeIfPresent, computeIfAbsent, compute, merge) возвращают актуальное значение после вызова, оставшееся или новое.


Java Guru🤓 #java
🔥7👍54
Зачем выбирать ReentrantLock вместо synchronized?

Объект класса ReentrantLock решает те же задачи, что и блок synchronized. Поток висит на вызове метода lock() в ожидании своей очереди занять этот объект. Владеть локом, как и находиться внутри блока synchronized может только один поток одновременно. unlock(), подобно выходу из блока синхронизации, освобождает объект-монитор для других потоков.

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

Шире и возможные режимы блокировки. Кроме обычного ожидающего lock(), вариант tryLock() с параметром ожидает своей очереди только заданное время, а без параметра – вообще не ждет, а только захватывает свободный лок.

Еще одно отличие – свойство fair. Лок с этим свойством обеспечивает «справедливость» очереди: пришедший раньше поток захватывает объект раньше. Блок synchronized не дает никаких гарантий порядка.


Java Guru🤓 #java
👍12🔥82
📌 Оптимизация Dependency Injection в Spring

Spring управляет созданием бинов через Dependency Injection (DI), но при большом количестве компонентов это замедляет запуск приложения и расходует память.

Используйте @Lazy, чтобы откладывать создание бина до первого вызова:
@Component
public class Component {

@Lazy
@Autowired
private Service service;
}


🟢Когда применять

— Редко используемые сервисы (например, отчёты, аналитика).
— В крупных приложениях с тысячами зависимостей.
— В микросервисах для уменьшения потребления ресурсов.
— При загрузке тяжёлых конфигураций.

Java библиотека #java
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥53
Как используется метод Lock.newCondition()?

Если реализации интерфейса Lock представляют высокоуровневую альтернативу блока synchronized, то реализации его спутника, интерфейса Condition – альтернатива методам notify/wait. Оба этих интерфейса относятся к пакету java.util.concurrent.locks.

Как и ожидание на мониторе, Condition реализует примитив синхронизации «Условная переменная». Один или несколько потоков зависают на объекте-кондишне с помощью варианта метода await (ждут удовлетворения условия). Другой поток пробуждает их методами signal и signalAll (сигнализирует об удовлетворении условия).

Конкретные реализации Condition всегда решают те же задачи, что блокировка на мониторе, но в теории могут отличаться в нюансах поведения. Например, может не быть требования вызывать ожидание/сигнал только при захваченном локе (аналог требования, по которому notify/wait всегда вызываются в synchronized). Или может гарантироваться порядок получения сигнала ожидающими потоками.

Возвращаясь к поставленному вопросу, Condition всегда связан со своим объектом типа Lock, и метод Lock.newCondition() – единственный правильный способ создания кондишна.


Java Guru🤓 #java
🔥8👍32
Как получить текущий метод

В общем виде задача сводится к получению текущего стек-трейса, и взятию его верхнего элемента. Гарантированного способа не существует, потому что JVM имеет право «терять» фреймы стека (то есть методы цепочки вызовов) при оптимизации.

1. new Exception().printStackTrace(printStream)
Печатает стек-трейс в текстовом виде в поток. Первой строкой выводится toString() объекта Exception, далее стек вызовов до места создания исключения. Соответственно, из потока нужно будет достать и распарсить вторую строку. В зависимости от JVM формат вывода может отличаться.

2. Thread.currentThread().getStackTrace()
3. new Exception().getStackTrace()
Более красивые способы. Возвращают уже массив готовых объектов-фреймов, нужно только взять первый элемент. Эти вызовы дорогие, они всегда загружают весь стек, даже если нужен первый фрейм. От класса-владельца метода в возвращаемом StackTraceElement доступна только строка имени, для доступа через Reflection придется загружать его вручную.

4. StackWalker.getInstance(options, depth).walk(s -> ...)
Самый продвинутый способ, доступный с Java 9 – специально предназначенный для этого класс. Параметрами метода getInstance() можно ограничивать необходимую глубину и детализацию стека. Результаты – экземпляры StackFrame – содержат готовый для рефлекшна Class<?> вызывающего объекта.


Java Guru🤓 #java
👍8🔥81
Что будет результатом кода?
👍9🔥32
Что будет результатом кода?
Anonymous Quiz
2%
0
53%
1
34%
2
9%
Ошибка компиляции
2%
RuntimeException
👍172🔥2😢2
Что будет результатом кода?
👍4🔥21