Изучаем Java. По вопросам сотрудничества: @seniorvladislav
Использование шифрования в Java для обеспечения безопасности данных в банковских приложениях
Шифрование является одним из ключевых методов защиты конфиденциальности и целостности данных, что особенно важно для финансовой отрасли.
Шифрование и дешифрование данных с использованием AES (Advanced Encryption Standard)
В примере мы использовали алгоритм шифрования AES для защиты данных в банковском приложении на Java. AES является широко применяемым и надежным алгоритмом шифрования, который подходит для большинства сценариев использования.
Если ваше банковское приложение предполагает использование криптографических ключей между разными системами или предприятиями, рассмотрите возможность использования протокола HSM (Hardware Security Module) для безопасного хранения, передачи и управления ключами.
В заключение, шифрование данных является критически важным аспектом безопасности для банковских приложений на Java. Убедитесь, что вы выбираете подходящий алгоритм и режим шифрования для вашего сценария использования, и обеспечиваете безопасное хранение и передачу ключей.
#вопросы_с_собеседований
Реализация кеширующего прокси для REST-сервиса
В этом посте мы рассмотрим интересный вопрос, который может возникнуть на собеседовании для Senior Java Developer в компании Microsoft.
Решение этой задачи заключается в создании прокси-класса, который будет кешировать результаты запросов к REST-сервису. Мы воспользуемся библиотекой Retrofit для работы с REST-сервисом и Caffeine для реализации кэша.
На рисунке 1 мы создали кеширующий прокси для WeatherService, который использует Caffeine для хранения кэшированных данных. Запросы к REST-сервису будут кэшироваться на 1 час, и размер кэша ограничен 1000 записями. Если данные присутствуют в кэше, они будут возвращены без дополнительного обращения к REST-сервису.
На рисунке 2 пример демонстрирует, как можно реализовать кэширующий прокси для REST-сервиса на Java, используя Retrofit и Caffeine. Это помогает снизить нагрузку на сервис и улучшить производительность клиентских приложений.
Реализация оптимистической блокировки в Java с использованием JPA и Hibernate
Оптимистическая блокировка - это подход для обеспечения согласованности данных при одновременном доступе к ним, при котором мы предполагаем, что конфликты редки и пытаемся их обнаружить.
1. Вначале создайте Product с полем version, которое будет использоваться для оптимистической блокировки.
2. Затем создайте репозиторий для работы с продуктами.
3. Создайте сервис, который будет выполнять обновление продукта и обрабатывать возможные исключения, связанные с оптимистической блокировкой.
При обновлении продукта Hibernate автоматически увеличивает значение поля version и проверяет, что оно не изменилось с момента предыдущего чтения. Если значение изменилось, это означает, что другой пользователь уже обновил продукт, и Hibernate выбросит исключение OptimisticLockingFailureException. Вы можете обработать это исключение в сервисе, чтобы определить, что делать дальше (например, повторить операцию или уведомить пользователя).
Эффективное вычисление медианы потока чисел в реальном времени с использованием Min и Max Heaps
В этом посте мы рассмотрим один из сложных вопросов, которые могут возникнуть на собеседованиях для Senior Java разработчиков в Uber.
Одним из эффективных подходов к решению этой задачи является использование двух куч (Heaps) - одна для хранения элементов меньше медианы (Max Heap), а другая для хранения элементов больше медианы (Min Heap). Это позволяет обеспечить быстрый доступ к медиане и эффективное добавление новых элементов.
В этом примере мы создаем две кучи - maxHeap и minHeap. Метод addNum() добавляет число в соответствующую кучу и вызывает balanceHeaps() для поддержания баланса между кучами. Метод findMedian() возвращает медиану, исходя из размера и элементов на вершине каждой кучи.
Таким образом, мы можем эффективно вычислять медиану потока чисел в реальном времени, поддерживая баланс между двумя кучами.
Реализация паттерна Команда с использованием Lambda-выражений в Java
В этом посте мы поговорим о паттерне Команда и его реализации с использованием Lambda-выражений в Java. Паттерн Команда является поведенческим паттерном, который позволяет инкапсулировать запросы в виде объектов, что облегчает параметризацию, очередность и хранение запросов.
Lambda-выражения, введенные в Java 8, предоставляют синтаксический сахар для представления функциональных интерфейсов и позволяют писать более лаконичный и выразительный код. Использование Lambda-выражений значительно упрощает код и делает его более гибким и выразительным.
В этом примере, вместо создания отдельных классов для каждой команды, мы используем lambda-выражения, чтобы инкапсулировать действия в виде объектов. Затем мы добавляем команды в список и выполняем их последовательно с помощью метода executeCommands().
Реализация модели акторов с использованием Akka в Java
Сегодня мы углубимся в мир параллелизма и поговорим о модели акторов, используя библиотеку Akka в Java. Это современный подход к обработке параллельных процессов, и его основное преимущество - это абстрагирование от низкоуровневых деталей, таких как блокировки и потоки.
Модель акторов представляет собой математическую модель параллельных вычислений, которая рассматривает "акторы" как примитивы параллельного вычисления: в ответ на сообщение, которое получает актор, он может делать локальные вычисления, создавать больше акторов, отправлять больше сообщений и определять, как реагировать на следующее полученное сообщение.
В данном коде мы создали актор SimpleActor, который может получать сообщения типа String. В ответ на полученное сообщение, он просто логирует его. Если актор получает сообщение, которое не является строкой, он также логирует, что получил неизвестное сообщение.
Что такое ключевое слово final и где его использовать?
Ключевое слово final
можно использовать для переменных, методов и классов.
🔸final переменную нельзя переназначить на другой объект.
🔸final класс бесплоден)) у него не может быть наследников.
🔸final метод не может быть переопределен у предка.
final переменные
Java дает нам два способа создать переменную и присвоить ей некоторое значение:
🔸Можно объявить переменную и инициализировать ее позже.
🔸Можно объявить переменную и сразу же назначить ее.
Пример с использованием final переменной для этих случаев:
🔥Кто сегодня являются первыми среди первых для работодателей в мире IT?
Возможно, это Cloud Solution Architecture - те самые специалисты, которые формируют устойчивые облачные цепочки, управляют ими, оптимизируют.
Начни свой левел-ап в мир облачной архитектуры с открытого урока «Supply Chain Management (SCM) в Облаке. AWS CloudFormation».
Занятие приурочено к новому запуску курса «Cloud Solution Architecture» в Отус и пройдет 10 мая в 20.00 (мск).
📚На вебинаре мы:
- Рассмотрим AWS SAM для serverless
- Познакомимся с Cloudformation
- Изучим основные сущности
- Проведем демонстрацию развертывания инфраструктуры через Cloudformation
👍Участие в уроке бесплатное! Требуется вступительный ТЕСТ https://otus.pw/tPaI/
Преподаватель: Андрей Поляков - старший разработчик в Unlimint
Продолжить изучение практик по работе над архитектурой облачных решений вы сможете на курсе «Cloud Solution Architecture». Сейчас возможны разные способы оплаты обучения. Дополнительный бонус для студентов курса - доступ к AWS. Нативная интеграция. Информация о продукте www.otus.ru
#вопросы_с_собеседований
Как файлы cookie работают в сервлетах?
🔸Файлы cookie – это текстовые данные, отправляемые сервером клиенту и сохраняемые на локальном компьютере клиента.
🔸Servlet API обеспечивает поддержку файлов cookie через класс javax.servlet.http.Cookie, который реализует интерфейсы Serializable и Cloneable.
🔸Метод HttpServletRequest getCookies() предоставляется для получения массива файлов cookie из запроса, поскольку нет смысла добавлять файлы cookie в запрос, нет методов для установки или добавления файлов cookie в запрос.
🔸Аналогичным образом предоставляется метод HttpServletResponse addCookie(Cookie c) для прикрепления файла cookie в заголовке ответа, методы получения для cookie отсутствуют.
#вопросы_с_собеседований
Из за чего может возникать NoClassDefFoundError, NoSuchMethodError?
🔸 NoClassDefFoundError может возникнуть, если нужной библиотеки с этим классом нет в classpath
🔸 NoSuchMethodError может возникнуть из-за несовместимости ваших библиотек, если зависимая библиотека A вызывает метод из старой версии библиотеки B, но в classpath есть более новая версия библиотеки B, c другой сигнатурой этого метода
Стажировка Deep Dive: что это, кого ищут и почему это может быть интересней, чем классическая стажировка 🤔
Deep Dive — оплачиваемая стажировка от Яндекс Маркета, которая проходит
в формате буткемпа. Это интенсив, где участники в течение 3–4 месяцев могут поработать сразу в двух разных командах и выбрать ту, что нравится больше.
Стажёров ищут по трём направлениям:
— бэкенд (С++, Java)
— фронтенд (JavaScript)
— мобильная разработка (iOS, Android)
Что вас ждёт?
1️⃣ Знакомство с технологиями Яндекса, особенностями процесса разработки, программами и инструментами.
2️⃣ Работа над реальными задачами в первой команде и комплексная обратная связь, по итогам которой вам подберут вторую команду.
3️⃣ Работа над новыми задачами во второй команде.
🔥 У всех, кто хорошо себя проявит, будет шанс попасть в штат компании и выбрать команду, в которой больше понравилось работать.
Выход на стажировку 31 мая
📎 Подать заявку
Countdown Latch/Cyclic Barrier
CountdownLatch («защелка») — примитив синхронизации, с помощью которого, например, основной thread может ожидать выполнения работы остальных N тредов. Треды, выполняющие работу, выполняют countDown() на защелке, основной тред ожидает на операции await(). Когда счетчик достигает нуля, основной тред продолжает работу.
Для синхронизации N тредов (все ждут всех) и переиспользования используется CyclicBarrier, ему также можно указывать действие (через Runnable), выполняемое после синхронизации всех-со-всеми
Стать сотрудником Яндекса быстрее и проще, чем кажется. Участвуйте в днях быстрого найма: решите тестовое, пройдите несколько секций собеседования и получите офер за несколько дней.
Теперь дни быстрого найма будут проходить регулярно. Чтобы вам было удобно следить за расписанием, собрали его на отдельной странице.
Ближайшее мероприятие:
• 13-14 мая — Fast Track для бэкенд-разработчиков пишущих на Python или С++, либо тех, кто готов на них перейти, офер за 2 дня в команду RideTech.
Зарегистрироваться
Если бы Даша обратилась к нам — уже хвасталась бы оффером перед друзьями)
Мы в codereview помогаем junior и middle разработчикам с трудоустройством👇
🎢 Разрабатываем стратегию поиска: знаем источники вакансий, о которых многие и не слышали.
🔥 Делаем огненное резюме + оформляем LInkedIn и Github. На этом моменте шанс на оффер увеличивается на 70%.
🗣 Проводим серию Mock Interview, чтобы ты уверенно чувствовал себя на собеседовании.
👨🏫 Рекомендуем тебя партнерам. Мы сотрудничаем с OZON, Сбером, VK и другими крупными компаниями.
И самое главное: будем саппортить тебя в течение полугода, пока ты не получишь оффер.
✌️Пора переходить к активным действиям, если хочешь найти работу в этом году! Оставляй заявку на бесплатную консультацию с нашим HR или Senior разработчиком. Ждем!
Стойте! Если хотите шарить, или уже шарите в Java или Kotlin, то эти каналы однозначно для вас!
После их прочтения вы 100%
повысите свой уровень в несколько раз! Админ каналов Senior-разработчик, а значит ему можно доверять своё обучение:
1. Java Библиотека — Книги, статьи, фичи и советы. Сборная солянка для прогеров.
2. Kotlin Developer - самый топовый канал для котлин разработчика!
3. Книги для Java Программистов — Название говорит само за себя. Лучшие платные и бесплатные книги собраны в одном месте!
4. Java Guru — Хотите пройти собеседование и рубить по 300.000₽ в месяц? Всё возможно, но для этого надо прорешать не одну сотню задач и тестов — на этом канале как раз всё собрано.
5. Java News — А этот канал ежедневно вводит в курс дела и новостей любимого ЯП!
Подписывайтесь на все 5 каналов и станьте мега-программистом!
Реализация распределенных транзакций в микросервисной архитектуре банковского приложения на Java
В микросервисной архитектуре транзакции часто распределяются между разными сервисами, что может вызвать проблемы с целостностью данных при сбоях или сетевых задержках.
Реализация паттерна Saga для распределенных транзакций
1. Создайте интерфейс SagaStep для представления шагов саги
2. Реализуйте пример шага саги для перевода средств между счетами
3. Создайте класс SagaOrchestrator для координации и выполнения саги
4. Используйте SagaOrchestrator для выполнения саги
В примере мы использовали паттерн Saga для реализации распределенных транзакций в микросервисной архитектуре. Saga состоит из последовательности шагов, каждый из которых выполняется на разных микросервисах. Если один из шагов завершается с ошибкой, выполняется откат всех предыдущих шагов в обратном порядке.
Важно отметить, что этот пример упрощен и не включает взаимодействие между разными микросервисами через API или другие механизмы. В реальном приложении вы можете использовать фреймворки, такие как Spring Cloud Saga или Axon, для управления и координации саги в микросервисной архитектуре.
Реализация параллельного алгоритма Fork/Join с использованием Java
Fork/Join Framework был введен в Java 7 и предназначен для решения задач, которые можно разбить на более мелкие подзадачи и затем объединить результаты. Он основан на принципе "разделяй и властвуй" и использует идею рабочего заимствования (work stealing) для управления потоками.
При выполнении этого примера, число Фибоначчи на 10-й позиции будет вычислено параллельно с использованием Fork/Join Framework. Этот подход может быть легко адаптирован для решения других параллельных задач, таких как обработка изображений, матричные операции или анализ больших объемов данных.
Настройка процессов сборки и развертывания приложений (CI/CD)
CI/CD (Continuous Integration/Continuous Deployment) - это практика автоматизации сборки, тестирования и развертывания приложений. В данном случае, мы возьмем пример настройки CI/CD для Java-приложения с использованием Jenkins, Maven и Docker.
Шаг 1: Установка и настройка Jenkins
Установите Jenkins на ваш сервер или локальную машину
Установите плагины Maven Integration, Docker и Git для Jenkins.
Шаг 2: Настройка Jenkinsfile
Создайте файл Jenkinsfile в корне вашего проекта с содержанием выше. Здесь мы создаем 4 этапа: Build, Test, Dockerize и Deploy. Этот файл будет использоваться Jenkins для автоматизации процесса CI/CD.
Шаг 3: Настройка Dockerfile
Создайте файл Dockerfile в корне вашего проекта.
Шаг 4: Настройка Jenkins
Зайдите в Jenkins и создайте новый Pipeline-проект.
В разделе "Pipeline" выберите "Pipeline script from SCM" и укажите репозиторий вашего проекта.
Укажите "Jenkinsfile" в поле "Script Path".
Сохраните настройки проекта и запустите его.
Теперь ваше приложение будет автоматически собираться, тестироваться и развертываться с использованием Jenkins, Maven и Docker.
Шаг 5: Оптимизация и мониторинг
После настройки основного процесса CI/CD, вы можете оптимизировать и улучшить процесс, добавляя дополнительные шаги, такие как:
◾️Оптимизация сборки: Вы можете настроить кеширование зависимостей и артефактов, чтобы ускорить процесс сборки вашего приложения.
◾️Автоматическое масштабирование: Вы можете настроить автоматическое масштабирование вашего приложения на основе нагрузки и ресурсов.
◾️Мониторинг: Вы можете интегрировать системы мониторинга и оповещения для отслеживания состояния вашего приложения и оперативного реагирования на возникающие проблемы.
В итоге, настройка CI/CD для Java-приложений с использованием Jenkins, Maven и Docker позволяет автоматизировать процесс разработки, тестирования и развертывания, обеспечивая непрерывную интеграцию и развертывание вашего приложения.
#вопросы_с_собеседований
Определение циклов в графе с использованием алгоритма Tarjan
Давайте рассмотрим один из сложных вопросов, который могут задать на собеседование для Senior Java разработчика.
Алгоритм Тарьяна — это алгоритм поиска в глубину, который позволяет определить сильно связные компоненты в ориентированном графе. Сильно связная компонента — это подмножество вершин графа, такое что каждая вершина достижима из любой другой вершины в этом подмножестве.
В этом примере мы создаем ориентированный граф, представленный списком смежности. Затем мы создаем объект класса TarjanAlgorithm и вызываем метод findCycles(), чтобы определить сильно связные компоненты. В результате, мы получаем список сильно связных компонент, которые представляют собой циклы в графе.
Применение CompletableFuture в Java для асинхронного программирования
CompletableFuture — это класс в Java, который предоставляет удобный API для работы с асинхронными вычислениями. CompletableFuture позволяет вам запускать задачи асинхронно и комбинировать их результаты без использования блокировок или других механизмов синхронизации.
В этом примере мы создаем два CompletableFuture, каждый из которых выполняет задачу в асинхронном режиме. Метод thenCombine() используется для объединения результатов двух Future, когда они оба доступны. В результате, мы получаем новый CompletableFuture, который завершится после того, как оба исходных Future будут завершены и вернет сумму их результатов.
Обратите внимание на то, что весь код асинхронен, и основной поток не блокируется во время ожидания завершения Future.
#вопросы_с_собеседований
Что такое Instance Variable?
Instance Variable — переменная, которая определена внутри класса, и она существует вплоть до того момента, пока существует объект.
Пример — класс Bee, в котором есть две переменные nectarCapacity и maxNectarCapacity
#вопросы_с_собеседований
Что такое Local Variable?
Популярный вопрос на собеседовании Java-разработчика. Local variable — это переменная, которая определена внутри метода и существует вплоть до того момента, пока выполняется этот метод. Как только выполнение закончится, локальная переменная перестанет существовать.
Вот программа, которая использует локальную переменную helloMessage в методе main()
Final методы
Когда метод маркирован как final, его называют final метод (логично, правда?). Final метод нельзя переопределять у класса наследника.
К слову, методы в классе Object — wait() и notify() — это final, поэтому у нас нет возможность их переопределять.
Как и где использовать final в Java
🔸использовать ключевое слово final, чтобы определить некоторые константы уровня класса;
🔸создавать final переменные для объектов, когда вы не хотите, чтобы они были изменены. Например, специфичные для объекта свойства, которые мы можем использовать для целей логирования;
🔸если не нужно, чтобы класс был расширен, отметить его как окончательный;
🔸если нужно создать immutable< класс, нужно сделать его финальным;
🔸если нужно, чтоб реализация метода не менялась в наследниках, обозначить метод как final
. Это очень важно, чтобы быть уверенным, что реализация не изменится.
#вопросы_с_собеседований
В чем разница между execute, executeQuery, executeUpdate?
🔸Выполнение инструкции(строковый запрос) используется для выполнения любого SQL-запроса и возвращает TRUE, если результатом является ResultSet, такой как выполнение запросов Select. Выходные данные – ЛОЖЬ, если нет объекта ResultSet, такого как выполняющиеся запросы Insert или Update. Мы можем использовать getResultSet(), чтобы получить ResultSet, и метод getUpdateCount(), чтобы получить счетчик обновлений.
🔸Оператор executeQuery(строковый запрос) используется для выполнения запросов Select и возвращает ResultSet. Возвращаемый ResultSet никогда не является нулевым, даже если нет записей, соответствующих запросу. При выполнении запросов select мы должны использовать метод executeQuery, чтобы, если кто-то попытается выполнить оператор вставки / обновления, он выбросит java.sql.SQLException с сообщением «Метод executeQuery не может использоваться для обновления».
🔸Оператор executeUpdate (строковый запрос ) используется для выполнения операторов Insert / Update / Delete (DML) или операторов DDL, которые ничего не возвращают. Результат – int и равен количеству строк для операторов языка манипулирования данными SQL (DML). Для операторов DDL на выходе будет 0.
ReentrantLock
Примитив синхронизации, с помощью которого можно установить границы критической секции. Тред, перед входом в критическую секцию должен сделать захват c операцией lock()
, после выхода из крит. секции — сделать unlock()
. Другой тред в это время ожидает на lock'е (можно указывать таймаут ожидания), либо может проверить доступность через tryLock()
.
ReentrantLock обязательно нужно освобождать (такое кол-во раз, сколько раз он был захвачен), в противном случае будет thread starvation у других тредов, ожидающих у границы критической секции.
ReentrantLock может быть «честным» (fairness = true), тогда приоритет отдается тредам, ждущих на нем наибольшее кол-во времени, но это вроде как уменьшает производительность
#вопросы_с_собеседований
ThreadPoolExecutor — описать механизм работы, св-ва, частности (fixed threadpool, scheduled, single thread executor)
ThreadPoolExecutor — средство контроля исполнения параллельных задач, задействует один из свободных тредов в общем пуле, или ставит задание в очередь, если таковых нет, или достигнуты определенные условия (ниже)
Основными св-вами ThreadPoolExecutor являются corePoolSize и maxPoolSize. Если текущее количество тредов в пуле < corePoolSize — новый тред будет создаваться в независимости от того, есть ли в пуле незанятые треды. В промежутке между corePoolSize и maxPoolSize тред будет создаваться в том случае, если заполнена очередь задач, и удаляться спустя keepAliveTime. Если кол-во тредов стало >= maxPoolSize — новые треды не создаются, а задачи ставятся в очередь.
Есть возможность регулировать поведение очереди:
🔸Direct handoffs: немедленная передача задачи тредпулу. Нет понятия очереди задачи. Если свободных тредов нет — кидается exception. Применимо при неограниченных maxPoolSize, но нужно понимать проблему при быстрых записях и медленных чтениях, что может спровоцировать непомерное потребление ресурсов
🔸Unbounded queues: очередь без ограничений. Задачи будут добавляться в нее при превышении corePoolSize, при этом maxPoolSize будет игнорироваться. Unbounded queues имеют проблемы потребления ресурсов при больших нагрузках, но сглаживают рост тредов при пиках.
🔸Bounded queues: очередь с ограничениями. Задачи будут добавляться в очередь до достижения некоего capacity. Для достижения наилучшей производительности нужно понимать размеры corePoolSize и самой очереди и чем можно пожертвовать — перфомансом (малый corePoolSize и большая очередь), или же памятью (ограниченная очередь, большой corePoolSize)
Частности ThreadPoolExecutor:
ScheduleThreadPoolExecutor — применяется для периодичных по времени задач
fixed thread pool — частность ScheduleThreadPoolExecutor'а с настроенным corePoolSize и unbounded queue
single thread executor — тредпулл, c сorePoolSize = 1, гарантирующий последовательное выполнение задач из очереди
#вопросы_с_собеседований
Generics: В чем преимущество, как работают? Что такое type-erasure? В чем отличие от шаблонов C++?
🔸Типы дженерики обеспечивают параметрический полиморфизм, т.е выполнение идентичного кода для различных типов. Типичный пример — коллекции, итераторы
🔸type-erasure — это стирание информации о типе-параметре в runtime. Таким образом, в байт-коде мы увидим List, Set вместо List<Integer>, Set<Integer>, ну и type-cast'ы при необходимости
🔸В отличие от дженериков в Java, в С++ шаблоны в итоге приводят к компиляции метода или типа для каждого специфицированного типа параметра (специализация шаблона). Да простят меня здесь адепты С++.
#вопросы_с_собеседований
Swing: рассказать про EDT, как им пользоваться
EDT — тред в котором производится обработка пользовательских действий на UI: движение курсора, нажатие клавиш, скролл, drag'n'drop и.т.д. Соотвественно, все «тяжелые» по времени и ресурсам операции нужно выносить в отдельный worker-тред (SwingUtils.invokeLater(...)), чтобы не фризить EDT.
#вопросы_с_собеседований
Как в Java сделать утечку памяти?
Используя самописный класс стека, при выполнении операции pop() не присваивать предыдущей ссылке значение null.
Также можно неверно использовать HashMap вместо WeakHashMap для кэширования чего-нибудь большого, например картинок ваших товаров, пользователей и т.д в. Т.к ссылки на ключи сильные (strong references), значения по этим ключам будут висеть в хипе до следующей перезагрузки jvm процесса или удаления ключа из мапы и обнуления ссылки на него.
#вопросы_с_собеседований
Что такое string-pool? В чем отличие cоздания строки через new от литерала? Что такое String.intern()?
string-pool — структура в памяти, хранящая массив всех строк-литералов программы.
String.intern(), соответственно, вернет строку из пула, при наличии таковой. Полезно при сравнениях вида:
new String("hello").intern() == new String("hello").intern()
Т.к. без интернирования пришлось бы сравнивать строки через equals, что может быть медленнее при наличии длинных строк. В данном случае возвращается ссылка на один и тот же объект строки из пула, и проверка проходит с true.