Ответы пользователя по тегу Java
  • Как правильно использовать Attach to process в intellij idea?

    @Asapin
    В свободное время ковыряюсь с Rust и Wasm
    Если вы запускаете Jetty не изнутри IDEA, а как отдельное приложение, а потом подключаетесь к нему, то в первую очередь проверьте, что вы включили Remote Debug в Jetty.
    Далее, убедитесь, что на сервере и в идее у вас один и тот же код плагина. Сильно упрощая, при remote debug'е, IDE сообщает серверу - останови выполнение, когда достигнешь строки N в классе X. Соответственно, если на сервере крутится один код, а в IDE открыт другой код, то класса X на сервере может не быть, либо строка N может быть no-op (пустая строка или открывающая/закрывающая скобка) из-за того, что какой-то метод был изменён или где-то изменён комментарий, из-за чего строки съехали по сравнению с кодом на сервере.
    Ответ написан
  • Как оптимизировать код Java при работе со строчками?

    @Asapin
    В свободное время ковыряюсь с Rust и Wasm
    Про кеширование
    Если у вас condition бОльшую часть времени имеет малый набор возможных значений, то кешированием в данном случае будет создание хешмапы, где ключ - condition, значение - condition + ",". Можете даже использовать какой-нибудь LRU-кеш, что бы редко используемые ключи постепенно удалялись из кеша и не занимали память.

    Но если честно, в данном случае операция condition + "," настолько незначительна по вычислительной сложности, что хоть какое-то изменение вы заметите только если у вас этот участок кода вызывается в горячем цикле и генерирует столько мусора, что паузы GC перевешивают дополнительные вычисления хеша, ветвления и добавление новых данных в кеш. Но даже в этом случае нужно профилировать, например с помощью JMH и VisualVM.

    Теперь по поводу StringBuilder.
    Сразу скажу, что у меня нет под рукой IDE для Java, что бы проверить то, что будет написано дальше, все выводы сделаны только глядя на исходный код классов String и StringBuilder. Итак, поехали:
    • Код condition + "," будет преобразован компилятором в
      new StringBuilder().append(condition).append(",").toString()
      Это сразу +2 созданных объекта: StringBuilder и новый String, который будет создан в результате вызова метода StringBuilder.toString()

    • a = a.replace("^Var1:", newString); внутри себя тоже создаёт StringBuilder, у которого потом вызывается метод toString() - еще +2 объекта

    • a = a + System.lineSeparator(); опять же будет преобразован в StringBuilder + toString()


    Итого, у вас создаётся минимум 6 объектов.

    Если переменная condition может иметь произвольное значение (т.е. операции с ней нет смысла кешировать, так как всё-равно придётся каждый раз вычислять новое значение), то можете попробовать воспользоваться методом condition.concat(String str) - будете создавать только 1 объект вместо 2. Будет ли это быстрее? Не знаю, надо профилировать.
    Далее, после входа в блок if создаём новый StringBuilder вместимостью a.length() + condition.length() + 2. Если не указать длину строки, то вместимость у StringBuilder будет либо 16 символов, либо равной длине значения в переменной a (в зависимости от того, какой конструктор будет использован). И при конкатенации с новыми строками скорее всего возникнет необходимость увеличивать размер буфера, что приведёт к дополнительному копированию массивов (создать буфер с новым размером, скопировать содержимое старого буфера в новый). Поэтому желательно сразу рассчитать правильную длину результирующей строки. В любом случае, это тоже +1 объект.
    a.replace(CharSequence target, CharSequence replacement)
    можно заменить методом
    StringBuilder.replace(int start, int end, String str)
    (придётся вручную вычислить начало и конец подстроки, которую вы хотите заменить).
    Вместо a = a + System.lineSeparator(); используйте a.append(System.lineSeparator()).
    out.append(a); приведёт к созданию еще 1 объекта - либо вы вручную вызовете a.toString(), либо этот метод будет вызван за вас в методе out.append(CharSequence seq). И скорее всего приведёт еще и к копированию массива символов внутри переменной out, если вы заранее не указали вместимость с запасом.

    Итого, 3 объекта против изначальных 6 с несколькими не сразу очевидными НО. Стоит ли усложнение кода полученной экономии? Не уверен, надо профилировать. Ну и учтите, что производительность самого StringBuilder может быть разной, в зависимости от того, как вы его используете.

    Имхо, то что вы пытаетесь сделать - это экономия на спичках, которая может помочь только если у вас по настоящему высоконагруженный сервис.
    P.S. если вы пишете библиотеку, которая потом будет использоваться другими проектам, то я всеми конечностями за, если вы решили заморочиться с оптимизацией.
    Ответ написан
    1 комментарий
  • Ошибка Inappropriate blocking method call при http запросе в Kotlin. В чем проблема?

    @Asapin
    В свободное время ковыряюсь с Rust и Wasm
    Если по каким-то причинам нет возможности заменить блокирующий код неблокирующим аналогом (например, драйвер БД, для которого асинхронной версии просто не успели ещё написать), то можно использовать такое решение:
    1. Создаёте отдельный тредпул
    2. Все вызовы блокирующего кода оборачиваете в блок
    suspendCoroutine { continuation ->
        //
    }

    3. Внутри этого блока создаёте Runnable, который и будет выполнять ваш блокирующий код. После выполнения блокирующего кода вызываете либо continuation.resume(result), либо continuation.resumeWithException(e)
    4. Скармливаете полученный Runnable тредпулу.

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

    * - В котлине по умолчанию используется диспатчер Dispatcher.Default, количество потоков в котором равно количеству ядер CPU (но не меньше двух), поэтому добавление отдельного тредпула под блокирующие задачи приведёт к увеличению количества тредов, что в экстремальных случаях может привести к общей деградации производительности. Но в если у вас не высоконагруженное приложение, то этим можно пренебречь. Правда не уверен как с этим обстоят дела на мобильных платформах, возможно там количество тредов более критично.

    Из очевидных минусов:
    • количество потоков больше, чем ядер CPU
    • количество одновременно выполняемых блокирующих методов = количеству потоков в этом тредпуле
    • следите за тем, что бы этот тредпул был ограничен сверху
    .

    Насколько я помню, еще ~1.5 года назад примерно такая схема применялась в котлиновских обёртках над спринговыми драйверами то ли к монго, то ли к редису (там было 3 версии драйвера - блокирующая, реактивная, и блокирующая, но обёрнутая в отдельный тредпул, как я описал). Как сейчас - не знаю.
    Ответ написан
    1 комментарий
  • Java junior, серверное ПО, какие задачи решать, чтоб понять устройство системы?

    @Asapin
    В свободное время ковыряюсь с Rust и Wasm
    Если уже есть небольшой опыт работы со спрингом, то советую посмотреть "Spring-потрошитель" (2 части) от Евгения Борисова на ютубе. Он хорошо объяснил как спринг устроен изнутри. Магии много, на разобраться можно.

    После этого можно начинать читать документацию по интересующим модулям спринга. Она обычно очень подробная и понятная. Вот например документация по Spring Jpa.

    После этого попробуйте с нуля написать какое-нибудь простое приложение на спринге не используя туториалы, quick-старты и spring initializr, только maven/gradle (смотря что у вас в команде используется) и документация. Скажем, 3 пользовательских роли (админ, пользователь, аноним), 3 эндпоинта: 1 доступен для всех, 1 доступен админу и пользователю, 1 доступен только админу. Для начала пользователей можно захардкодить. Потом прикрутить постгрес для их хранения, потом прикрутить эластик для логов и т.п.
    После этого добавить несколько тестов, причём как тестов, которые напрямую дёргают методы сервисов и репозиториев, так и тесты, которые эмулируют пользователя: отправляют http-запросы на вход в систему, а потом дёргают эндпоинты и проверяют, что ограничения эндпоинтов по ролям работают правильно.

    Всё это желательно без туториалов, просто ищете название нужного спринг-модуля, открываете его референс-документацию и по ней работаете.

    За пару недель не спеша сделать вполне реально. После этого, если есть возможность, попросите кого-нибудь более опытного посмотреть код и сказать, что и как стоит исправить, желательно с пояснением почему.

    Понимание рекурсии и базовых алгоритмов полезно, но в корпоративном сегменте это будет встречаться не часто: бизнес процессы в большинстве случаев будут расписаны либо бизнес-аналитиком, либо самим заказчиком, а большинство структур данных и алгоритмов работы с ними уже доступны в стандартной библиотеке, Apache Commons Lang 3 и Google Guava.
    Ответ написан
    Комментировать
  • Как работает поиск в массиве mongoDB через Spring Data?

    @Asapin
    В свободное время ковыряюсь с Rust и Wasm
    Ответ зависит от того, какой именно запрос сгенерирует Spring Data для метода countByActiveStatesIn(Set states);.

    Судя по таблице №16 раздела 15.3 документации Spring Data MongoDB, должен сгенерироваться запрос
    db.collectionName.count({ activeStates: { $in: ["logicConnectionLost"] }})

    который посчитает все документы, поле activeStates которых содержит хотя бы один элемент из переданного списка.

    Какой именно запрос был сгенерирован, можно проверить выставив уровень логирования в DEBUG:
    logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG
    
    #Если используете реактивный MongoTemplate:
    logging.level.org.springframework.data.mongodb.core.ReactiveMongoTemplate=DEBUG
    Ответ написан
    Комментировать
  • Java как сделать чтобы каждый символ + 1?

    @Asapin
    В свободное время ковыряюсь с Rust и Wasm
    Если я правильно понял, то вам нужно увеличивать yy на 1 каждый раз, когда меняется pp? Т.е. банально надо посчитать сколько раз изменилась переменная pp.
    В таком случае можно поступить вот так: оборачиваете обе переменные в класс, и работаете с ними только через геттеры и сеттер. Прямой сеттер есть только для pp, внутри него происходит обновление yy по нужным вам правилам.
    Ответ написан
    Комментировать