Skip to content

GroteskSerega/java-optimization-guide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

9 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Java 21+ Extreme Optimization: 10+1 Golden Rules

EN RU

ΠœΠ°Π½ΠΈΡ„Π΅ΡΡ‚ ΠΈΠ½ΠΆΠ΅Π½Π΅Ρ€Π°: Как Π·Π°ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ JVM Π»Π΅Ρ‚Π°Ρ‚ΡŒ, Π° Native Image - Π±Ρ‹Ρ‚ΡŒ ΠΊΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Ρ‹ΠΌ.

ВОП-10+1 "Π—ΠΎΠ»ΠΎΡ‚Ρ‹Ρ… ΠΏΡ€Π°Π²ΠΈΠ» ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΉ Java 21+: ΠΊΠ°ΠΊ Π·Π°ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ JIT ΠΏΠ΅Ρ‚ΡŒ, Π° GraalVM - Π»Π΅Ρ‚Π°Ρ‚ΡŒ"

Π­Ρ‚ΠΎΡ‚ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ содСрТит ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΊΠΎΠ΄Π° ΠΈ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Ρ‹ΠΉ Ρ€Π°Π·Π±ΠΎΡ€ 11 Π·ΠΎΠ»ΠΎΡ‚Ρ‹Ρ… ΠΏΡ€Π°Π²ΠΈΠ» ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ для Java 21+, Spring Boot 3 ΠΈ GraalVM Native Image.

ΠŸΠΎΡ‡Π΅ΠΌΡƒ ваша Java-систСма буксуСт Ρ‚Π°ΠΌ, Π³Π΄Π΅ Π΄ΠΎΠ»ΠΆΠ½Π° Π»Π΅Ρ‚Π°Ρ‚ΡŒ? ΠœΡ‹ ΠΏΡ€ΠΈΠ²Ρ‹ΠΊΠ»ΠΈ Π΄ΠΎΠ²Π΅Ρ€ΡΡ‚ΡŒ ΠΌΠ°Π³ΠΈΠΈ JVM, Π½ΠΎ Π² ΠΌΠΈΡ€Π΅ Java 21 ΠΈ Native Image ΠΏΡ€Π°Π²ΠΈΠ»Π° ΠΈΠ³Ρ€Ρ‹ измСнились. ΠžΡ‚ ΠΌΠΈΠΊΡ€ΠΎ-ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΉ Π±Π°ΠΉΡ‚-ΠΊΠΎΠ΄Π° Π΄ΠΎ Ρ€Π°Π΄ΠΈΠΊΠ°Π»ΡŒΠ½ΠΎΠΉ смСны ΠΏΠ°Ρ€Π°Π΄ΠΈΠ³ΠΌΡ‹ с Scoped Values – Ρ€Π°Π·Π±ΠΈΡ€Π°Π΅ΠΌ 11 "Π·ΠΎΠ»ΠΎΡ‚Ρ‹Ρ… ΠΏΡ€Π°Π²ΠΈΠ»", ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ заставят JIT ΠΏΠ΅Ρ‚ΡŒ, Π° ваш Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊ – ΡΡ‚Π°Ρ€Ρ‚ΠΎΠ²Π°Ρ‚ΡŒ Π·Π° миллисСкунды. Никакой "Π²ΠΎΠ΄Ρ‹", Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ…Π°Ρ€Π΄ΠΊΠΎΡ€, рСгистры процСссора ΠΈ "голоса" компиляторов Π²Π½ΡƒΡ‚Ρ€ΠΈ вашСго ΠΊΠΎΠ΄Π°.

Работая с ΠΊΠΎΠ΄ΠΎΠΌ, я Π½Π΅ Ρ€Π°Π· Π»ΠΎΠ²ΠΈΠ» Π°Π·Π°Ρ€Ρ‚: Π° ΠΊΠ°ΠΊ этот ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΌΠΎΠΆΠ½ΠΎ ΡƒΡΠΊΠΎΡ€ΠΈΡ‚ΡŒ Π΅Ρ‰Ρ‘? ΠšΠ°ΠΊΡƒΡŽ Π³Π°ΠΉΠΊΡƒ ΠΏΠΎΠ΄ΠΊΡ€ΡƒΡ‚ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ JVM Π½Π΅ просто Ρ€Π°Π±ΠΎΡ‚Π°Π»Π°, Π° Π±ΡƒΠΊΠ²Π°Π»ΡŒΠ½ΠΎ Π»Π΅Ρ‚Π΅Π»Π°? Π§Ρ‚ΠΎ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π² Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Native Image стал Π΅Ρ‰Ρ‘ ΠΊΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Π΅Π΅, Π° Ρ…ΠΎΠ»ΠΎΠ΄Π½Ρ‹ΠΉ старт – Π΅Ρ‰Ρ‘ быстрСС?

Π˜ΡΠΏΡ‹Ρ‚Π°Π² этот Π°Π·Π°Ρ€Ρ‚ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ Π½Π΅ Ρ€Π°Π·, я Ρ…ΠΎΡ‡Ρƒ ΠΏΠΎΠ΄Π΅Π»ΠΈΡ‚ΡŒΡΡ ΠΈΠΌ с Π²Π°ΠΌΠΈ. Π― собрал ΠΊΠ²ΠΈΠ½Ρ‚ΡΡΡΠ΅Π½Ρ†ΠΈΡŽ своСго ΠΎΠΏΡ‹Ρ‚Π° Π² ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΉ Ρ‡Π΅ΠΊ-лист.

Π­Ρ‚ΠΎ Π½Π΅ просто совСты ΠΏΠΎ ΡΡ‚ΠΈΠ»ΡŽ ΠΊΠΎΠ΄Π°. Π­Ρ‚ΠΎ "10+1 Π—ΠΎΠ»ΠΎΡ‚Ρ‹Ρ… ΠΏΡ€Π°Π²ΠΈΠ» ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ Java 21+".

Π­Ρ‚ΠΎ Ρ‚Π΅ Ρ€Ρ‹Ρ‡Π°Π³ΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π·Π°ΡΡ‚Π°Π²Π»ΡΡŽΡ‚ JIT-компилятор ΠΏΠ΅Ρ‚ΡŒ, Π° GraalVM – Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊΠΈ с хирургичСской Ρ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒΡŽ.

ΠŸΡ€ΠΈΠ³ΠΎΡ‚ΠΎΠ²ΡŒΡ‚Π΅ΡΡŒ! ΠœΡ‹ Π½Π°Ρ‡ΠΈΠ½Π°Π΅ΠΌ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ!


Π‘ΠΎΠ΄Π΅Ρ€ΠΆΠ°Π½ΠΈΠ΅

  1. ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–1. Records ΠΊΠ°ΠΊ DTO (Immutability & Heap)
  2. ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–2. fillInStackTrace(null) Π² бизнСс-ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡΡ…
  3. ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–3. Final Π²Π΅Π·Π΄Π΅
  4. ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–4. Π‘ΠΌΠ΅Ρ€Ρ‚ΡŒ РСфлСксии (AOT-friendly)
  5. ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–5. ΠšΠΎΡ€ΠΎΡ‚ΠΊΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ (Inlining Threshold)
  6. ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–6. ΠŸΡ€Π΅Π°Π»Π»ΠΎΠΊΠ°Ρ†ΠΈΡ ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΉ
  7. ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–7. BigDecimal vs Long (Π‘ΠΈΡ‚Π²Π° Π·Π° ΠΏΡ€ΠΈΠΌΠΈΡ‚ΠΈΠ²Ρ‹)
  8. ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–8. Π˜Π·Π±Π΅Π³Π°ΠΉΡ‚Π΅ прокси Π² критичСских ΡƒΠ·Π»Π°Ρ…
  9. ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–9. Generics: ИзбСгаСм Π»ΠΈΡˆΠ½ΠΈΡ… кастов
  10. ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–10. БтатичСский Π°Π½Π°Π»ΠΈΠ· вмСсто динамичСского (MapStruct)
  11. ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–11. Scoped Values вмСсто ThreadLocal

ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–1. Records ΠΊΠ°ΠΊ DTO (Immutability & Heap)

Π’ Ρ‡Ρ‘ΠΌ боль: ΠžΠ±Ρ‹Ρ‡Π½Ρ‹Π΅ POJO с сСттСрами – это "Ρ‡Ρ‘Ρ€Π½Ρ‹ΠΉ ящик". ΠšΠΎΠΌΠΏΠΈΠ»ΡΡ‚ΠΎΡ€ постоянно Π½Π°Ρ‡Π΅ΠΊΡƒ: Π²Π΄Ρ€ΡƒΠ³ ΠΊΡ‚ΠΎ-Ρ‚ΠΎ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ состояниС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π² сСрСдинС ΠΌΠ΅Ρ‚ΠΎΠ΄Π°? Π­Ρ‚ΠΎ ΠΌΠ΅ΡˆΠ°Π΅Ρ‚ Π³Π»ΡƒΠ±ΠΎΠΊΠΎΠΉ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΈ услоТняСт Π°Π½Π°Π»ΠΈΠ· Π³Ρ€Π°Ρ„Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ².

Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅: Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ record для всСх Π΄Π°Π½Π½Ρ‹Ρ…, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ просто "лСтят" сквозь систСму.

public record UserUpsertRequest (

        @NotBlank(message = VALIDATE_USER_USERNAME_BLANK)
        @Size(min = NAME_SIZE_MIN, max = NAME_SIZE_MAX, message = VALIDATE_USER_USERNAME_INCORRECT_SIZE)
        @Pattern(regexp = LATIN_REGEX, message = VALIDATE_USER_USERNAME_INCORRECT_REGEX)
        String username,

        @NotBlank(message = VALIDATE_USER_PASSWORD_BLANK)
        @Size(min = PASSWORD_SIZE_MIN, max = PASSWORD_SIZE_MAX, message = VALIDATE_USER_PASSWORD_INCORRECT_SIZE)
        String password,

        @NotBlank(message = VALIDATE_USER_FIRSTNAME_BLANK)
        @Size(min = NAME_SIZE_MIN, max = NAME_SIZE_MAX, message = VALIDATE_USER_FIRSTNAME_INCORRECT_SIZE)
        @Pattern(regexp = CYRILLIC_REGEX, message = VALIDATE_USER_FIRSTNAME_INCORRECT_REGEX)
        String firstName,

        @Size(min = NAME_SIZE_MIN, max = NAME_SIZE_MAX, message = VALIDATE_USER_SECONDNAME_INCORRECT_SIZE)
        @Pattern(regexp = CYRILLIC_REGEX, message = VALIDATE_USER_SECONDNAME_INCORRECT_REGEX)
        String secondName,

        @NotBlank(message = VALIDATE_USER_LASTNAME_BLANK)
        @Size(min = NAME_SIZE_MIN, max = NAME_SIZE_MAX, message = VALIDATE_USER_LASTNAME_INCORRECT_SIZE)
        @Pattern(regexp = CYRILLIC_REGEX, message = VALIDATE_USER_LASTNAME_INCORRECT_REGEX)
        String lastName,

        @NotBlank(message = VALIDATE_USER_EMAIL_BLANK)
        @Size(min = NAME_SIZE_MIN, max = NAME_SIZE_MAX, message = VALIDATE_USER_EMAIL_INCORRECT_SIZE)
        @Email(regexp = EMAIL_REGEX, message = VALIDATE_USER_EMAIL_INCORRECT_REGEX)
        String email
) {

}

Голос JIT: "О, record! НаконСц-Ρ‚ΠΎ я Π²ΠΈΠΆΡƒ final поля ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ. Π’Π΅ΠΏΠ΅Ρ€ΡŒ я Ρ‚ΠΎΡ‡Π½ΠΎ знаю, Ρ‡Ρ‚ΠΎ Π΄Π°Π½Π½Ρ‹Π΅ Π½Π΅ измСнится послС создания. Π― ΠΌΠΎΠ³Ρƒ агрСссивнСС ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡ‚ΡŒ Scalar Replacement (Ρ€Π°Π·Π»ΠΎΠΆΠΈΡ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π½Π° ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅) ΠΈ Π·Π°ΠΈΠ½Π»Π°ΠΉΠ½ΠΈΡ‚ΡŒ доступ ΠΊ Π½ΠΈΠΌ прямо Π² рСгистры процСссора".

Π¨Ρ‘ΠΏΠΎΡ‚ AOT: "ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ структура record извСстна ΠΌΠ½Π΅ Π΅Ρ‰Ρ‘ Π½Π° этапС сборки, я ΠΌΠΎΠ³Ρƒ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ°ΠΏΠΏΠΈΠ½Π³ этих Π΄Π°Π½Π½Ρ‹Ρ… Π² Π±ΠΈΠ½Π°Ρ€Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π³ΠΎΡ€Π°Π·Π΄ΠΎ агрСссивнСС, Ρ‡Π΅ΠΌ для ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹Ρ… классов с ΠΈΡ… динамичСской ΠΏΡ€ΠΈΡ€ΠΎΠ΄ΠΎΠΉ".

ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–2. fillInStackTrace(null) Π² бизнСс-ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡΡ…

Π’ Ρ‡Ρ‘ΠΌ боль: ΠœΡ‹ часто ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Exception для Π»ΠΎΠ³ΠΈΠΊΠΈ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, UserNotFound). Но созданиС ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ – это Π½Π΅ просто созданиС ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°, это Π΄ΠΎΡ€ΠΎΠ³ΠΎΠ΅ "ΠΏΡƒΡ‚Π΅ΡˆΠ΅ΡΡ‚Π²ΠΈΠ΅" ΠΏΠΎ всСму стСку Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² для заполнСния массива StackStraceElement[]. На это ΡƒΡ…ΠΎΠ΄ΠΈΡ‚ Π΄ΠΎ 90% Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ "ΠΆΠΈΠ·Π½ΠΈ" ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ.

Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅: Для прСдсказуСмых бизнСс-ошибок, Π³Π΄Π΅ Π²Π°ΠΌ Π½Π΅ Π½ΡƒΠΆΠ΅Π½ Π»ΠΎΠ³ со всСми внутрСнностями Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠ°, ΠΏΠ΅Ρ€Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚Π΅ сбор стСктрСйса.

public class EntityNotFoundException extends RuntimeException {
    public EntityNotFoundException(String message) {
        super(message, null, false, false); // Π΅Ρ‰Ρ‘ быстрСС Ρ‡Π΅Ρ€Π΅Π· конструктор
    }

    @Override
    public synchronized Throwable fillInStackTrace() {
        // ΠœΡ‹ Π½Π΅ собираСм трассировку стСка, Ρ‡Ρ‚ΠΎ позволяСт ΡΠΊΠΎΠ½ΠΎΠΌΠΈΡ‚ΡŒ рСсурсы CPU
        return this;
    }
}

Голос JIT: "Бпасибо! Когда Π²Ρ‹ создаётС ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠ΅ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅, я Π²Ρ‹Π½ΡƒΠΆΠ΄Π΅Π½ Π±Ρ€ΠΎΡΠΈΡ‚ΡŒ всё ΠΈ ΠΏΠΎΠ±Π°ΠΉΡ‚ΠΎΠ²ΠΎ Π²ΠΎΡΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Ρ‚ΡŒ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΡƒ Π²Ρ‹Π·ΠΎΠ²ΠΎΠ². Π­Ρ‚ΠΎΡ‚ ΠΊΠ°ΠΊ ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Ρ„ΠΈΠ»ΡŒΠΌ Π½Π° ΠΏΠ°ΡƒΠ·Ρƒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠ΅Ρ€Π΅ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ всС ΠΊΠ°Π΄Ρ€Ρ‹. Π‘ этим ΠΏΡ€Π°Π²ΠΈΠ»ΠΎΠΌ я просто создаю ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΈ Π±Π΅Π³Ρƒ дальшС, сохраняя Ρ‚Π΅ΠΌΠΏ выполнСния".

Π¨Ρ‘ΠΏΠΎΡ‚ AOT: "Π’ Native Image ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ стСктрСйс – это Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΌΠ΅Ρ‚Π°-ΠΊΠΎΠ΄, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ я Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡƒΠΌΠ΅Ρ‚ΡŒ Π²ΠΎΡΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Ρ‚ΡŒ Π² Ρ€Π°Π½Ρ‚Π°ΠΉΠΌΠ΅. Убирая fillInStackTrace, Π²Ρ‹ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ускоряСтС Π»ΠΎΠ³ΠΈΠΊΡƒ, Π½ΠΎ ΠΈ Π΄Π΅Π»Π°Π΅Ρ‚Π΅ ΠΌΠΎΠΉ Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊ ΠΊΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Π΅Π΅, избавляя мСня ΠΎΡ‚ Π»ΠΈΡˆΠ½ΠΈΡ… Ρ‚Π°Π±Π»ΠΈΡ† ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ…".

ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–3. Final Π²Π΅Π·Π΄Π΅

Π’ Ρ‡Ρ‘ΠΌ боль: ΠΠ΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΡΡ‚ΡŒ. Если пСрСмСнная Π½Π΅ ΠΏΠΎΠΌΠ΅Ρ‡Π΅Π½Π° ΠΊΠ°ΠΊ final, компилятор Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡƒΡ‡ΠΈΡ‚Ρ‹Π²Π°Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π΅Ρ‘ измСнСния Π² любой ΠΌΠΎΠΌΠ΅Π½Ρ‚. Π­Ρ‚ΠΎ Ρ€Π°Π·Π΄ΡƒΠ²Π°Π΅Ρ‚ Π³Ρ€Π°Ρ„ состояний, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π½ΡƒΠΆΠ½ΠΎ Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΈ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ.

Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅: Π”Π΅Π»Π°ΠΉΡ‚Π΅ final Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅, ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² ΠΈ поля классов. ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ – это ΠΏΡ€Π΅ΠΆΠ΄Π΅ всСго прСдсказуСмый ΠΊΠΎΠ΄. Π§Π΅ΠΌ мСньшС ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… ΠΌΠΎΠ³ΡƒΡ‚ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ своё состояниС, Ρ‚Π΅ΠΌ агрСссивнСС Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ‚ΠΎΡ€Ρ‹.

public Resource exportDataToCsvResource() {
    final List<Statistics> data = statisticsRepository.findAll();

    final StringBuilder builder = new StringBuilder(data.size() * 64);

    builder.append(FIRST_ROW_OF_CSV);

    for (final Statistics stat : data) {
        builder.append(stat.getId()).append(DELIMITER_CSV)
                .append(stat.getType()).append(DELIMITER_CSV)
                .append(stat.getUserId()).append(DELIMITER_CSV)
                .append(stat.getCheckIn()).append(DELIMITER_CSV)
                .append(stat.getCheckOut()).append(DELIMITER_CSV)
                .append(stat.getCreatedAt()).append('\n');
    }

    final byte[] bytes = builder.toString().getBytes(StandardCharsets.UTF_8);
    return new ByteArrayResource(bytes);
}

Голос JIT: "Π’ΠΈΠΆΡƒ final – дСлаю Constant Folding. Если я ΡƒΠ²Π΅Ρ€Π΅Π½, Ρ‡Ρ‚ΠΎ ссылка Π½Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΈΠ»ΠΈ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ Π½Π΅ измСнится, я ΠΌΠΎΠ³Ρƒ Π²Ρ‹ΠΊΠΈΠ½ΡƒΡ‚ΡŒ лишниС ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ ΠΈΠ· машинного ΠΊΠΎΠ΄Π° ΠΈ Π΄Π°ΠΆΠ΅ Π·Π°Ρ€Π°Π½Π΅Π΅ Π²Ρ‹Ρ‡ΠΈΡΠ»ΠΈΡ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ. Для мСня final – это Π½Π΅ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅, Π° Π·Π΅Π»Ρ‘Π½Ρ‹ΠΉ свСт: "Π—Π΄Π΅ΡΡŒ бСзопасно, ΠΆΠΌΠΈ Π½Π° Π³Π°Π·!".

Π¨Ρ‘ΠΏΠΎΡ‚ AOT: "Для мСня final – это Π±Π°Π·Π° для Dead Code Elimination. Если я Π²ΠΈΠΆΡƒ константноС условиС, я ΠΌΠΎΠ³Ρƒ просто "ΠΎΡ‚Ρ€Π΅Π·Π°Ρ‚ΡŒ" Ρ†Π΅Π»Ρ‹Π΅ Π²Π΅Ρ‚ΠΊΠΈ ΠΊΠΎΠ΄Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ исполнятся. Π­Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅Ρ‚ Π±ΠΈΠ½Π°Ρ€Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» мСньшС, Π° Π»ΠΎΠ³ΠΈΠΊΡƒ - прямолинСйнСС".

ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–4. Π‘ΠΌΠ΅Ρ€Ρ‚ΡŒ РСфлСксии (AOT-friendly)

Π’ Ρ‡Ρ‘ΠΌ боль: РСфлСксия – это "чёрная Π΄Ρ‹Ρ€Π°" для ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ. JIT Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π·Π°Ρ€Π°Π½Π΅Π΅ Π·Π°Π³Π»ΡΠ½ΡƒΡ‚ΡŒ Π²Π½ΡƒΡ‚Ρ€ΡŒ Π²Ρ‹Π·ΠΎΠ²Π° Ρ‡Π΅Ρ€Π΅Π· Method.invoke(), Π° Native Image ΠΈ вовсС Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ ΠΎΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ‚Π°ΠΊΠΎΠΉ "Ρ‡ΠΈΡ…" Π² JSON-ΠΊΠΎΠ½Ρ„ΠΈΠ³Π°Ρ…. Если Π²Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚Π΅ Ρ€Π΅Ρ„Π»Π΅ΠΊΡΠΈΡŽ Π² критичСском ΡƒΠ·Π»Π΅, Π²Ρ‹ Π΄ΠΎΠ±Ρ€ΠΎΠ²ΠΎΠ»ΡŒΠ½ΠΎ ΠΎΡ‚ΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚Π΅ΡΡŒ ΠΎΡ‚ 30-50% ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΉ скорости.

Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅: Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ MapStruct, JOOQ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ, Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‰ΠΈΠ΅ Ρ‡Π΅Ρ€Π΅Π· ΠΊΠΎΠ΄ΠΎΠ³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΡŽ (APT). Они ΡΠΎΠ·Π΄Π°ΡŽΡ‚ чистый Java-ΠΊΠΎΠ΄ Π½Π° этапС компиляции, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ выглядит Ρ‚Π°ΠΊ, Π±ΡƒΠ΄Ρ‚ΠΎ Π²Ρ‹ написали Π΅Π³ΠΎ Ρ€ΡƒΠΊΠ°ΠΌΠΈ - с прямыми Π²Ρ‹Π·ΠΎΠ²Π°ΠΌΠΈ Π³Π΅Ρ‚Ρ‚Π΅Ρ€ΠΎΠ² ΠΈ сСттСров.

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING,
        unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface UserMapper {

    User requestToUser(UserUpsertRequest request);

    UserResponse userToResponse(User user);

    default UserListResponse userListToUserListResponse(List<User> users) {
        return new UserListResponse(users
                .stream()
                .map(this::userToResponse)
                .toList());
    }

    @Mapping(target = "id", ignore = true)
    @Mapping(target = "username", ignore = true)
    @Mapping(target = "password", ignore = true)
    @Mapping(target = "roles", ignore = true)
    @Mapping(target = "createAt", ignore = true)
    @Mapping(target = "updateAt", ignore = true)
    void updateUser(UserUpsertRequest request, @MappingTarget User user);
}

Голос JIT: "РСфлСксия для мСня – это ΠΊΠ°ΠΊ Ρ‚ΡƒΠΌΠ°Π½ Π½Π° трассС. Π― Π½Π΅ Π²ΠΈΠΆΡƒ, Ρ‡Ρ‚ΠΎ Π²ΠΏΠ΅Ρ€Π΅Π΄ΠΈ ΠΈ сниТаю ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ Π΄ΠΎ ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌΠ°, ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π°Ρ всС свои супСрспособности. А ΠΊΠΎΠ΄ ΠΎΡ‚ MapStruct – это прямой Π°Π²Ρ‚ΠΎΠ±Π°Π½. Π― Π²ΠΈΠΆΡƒ entity.getName() -> dto.setName() ΠΈ просто "ΠΏΡ€ΠΎΡˆΠΈΠ²Π°ΡŽ" этот Π²Ρ‹Π·ΠΎΠ² насквозь Ρ‡Π΅Ρ€Π΅Π· Inlining".

Π¨Ρ‘ΠΏΠΎΡ‚ AOT: "РСфлСксия – ΠΌΠΎΠΉ Π½ΠΎΡ‡Π½ΠΎΠΉ ΠΊΠΎΡˆΠΌΠ°Ρ€. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ½Π° Π·Π°Ρ€Π°Π±ΠΎΡ‚Π°Π»Π° Π² Native Image, ΠΌΠ½Π΅ Π½ΡƒΠΆΠ½ΠΎ Ρ‚Π°Ρ‰ΠΈΡ‚ΡŒ Π·Π° собой ΠΊΡƒΡ‡Ρƒ ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ…, Ρ‡Ρ‚ΠΎ Ρ€Π°Π·Π΄ΡƒΠ²Π°Π΅Ρ‚ Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊ. ΠšΠΎΠ΄ΠΎΠ³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΡ позволяСт ΠΌΠ½Π΅ Π²Ρ‹ΠΊΠΈΠ½ΡƒΡ‚ΡŒ всё лишнСС Π΅Ρ‰Ρ‘ ΠΏΡ€ΠΈ сборкС. МСньшС рСфлСксии – мСньшС reflect-config.json ΠΈ быстрСС старт".

ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–5. ΠšΠΎΡ€ΠΎΡ‚ΠΊΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ (Inlining Threshold)

Π’ Ρ‡Ρ‘ΠΌ боль: ГигантскиС ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ Π½Π° 500 строк, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΄Π΅Π»Π°ΡŽΡ‚ всё: Π²Π°Π»ΠΈΠ΄ΠΈΡ€ΡƒΡŽΡ‚, ΡΡ‡ΠΈΡ‚Π°ΡŽΡ‚, Π»ΠΎΠ³ΠΈΡ€ΡƒΡŽΡ‚ ΠΈ ΡΠΎΡ…Ρ€Π°Π½ΡΡŽΡ‚. JIT Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΡ… "ΠΏΡ€ΠΎΠ³Π»ΠΎΡ‚ΠΈΡ‚ΡŒ" (Π²ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΎΠ΄ΠΈΠ½ Π² Π΄Ρ€ΡƒΠ³ΠΎΠΉ), ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΎΠ½ΠΈ ΠΏΡ€Π΅Π²Ρ‹ΡˆΠ°ΡŽΡ‚ Π»ΠΈΠΌΠΈΡ‚Ρ‹ ΠΏΠΎ Ρ€Π°Π·ΠΌΠ΅Ρ€Ρƒ Π±Π°ΠΉΡ‚-ΠΊΠΎΠ΄Π°. Π’ ΠΈΡ‚ΠΎΠ³Π΅ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ Π²Ρ‹Π·ΠΎΠ² этого ΠΌΠ΅Ρ‚ΠΎΠ΄Π° – это чСстный ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ ΠΏΠΎ адрСсу Π² памяти, созданиС Ρ„Ρ€Π΅ΠΉΠΌΠ° Π² стСкС ΠΈ ΠΊΡƒΡ‡Π° Π»ΠΈΡˆΠ½ΠΈΡ… Ρ‚Π°ΠΊΡ‚ΠΎΠ² процСссора.

Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅: Π”Ρ€ΠΎΠ±ΠΈΡ‚Π΅ Π»ΠΎΠ³ΠΈΠΊΡƒ Π½Π° ΠΌΠ΅Π»ΠΊΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹. Π˜Π΄Π΅Π°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π°Π·ΠΌΠ΅Ρ€ для ΠΈΠ½Π»Π°ΠΉΠ½ΠΈΠ½Π³Π° – Π΄ΠΎ 35 Π±Π°ΠΉΡ‚ Π±Π°ΠΉΡ‚-ΠΊΠΎΠ΄Π°. ΠšΡ€Π°ΡΠΈΠ²Ρ‹ΠΉ ΠΊΠΎΠ΄ ΠΏΠΎ Clean Code Π²Π½Π΅Π·Π°ΠΏΠ½ΠΎ оказываСтся самым быстрым для ΠΌΠ°ΡˆΠΈΠ½Ρ‹.

@Before("@annotation(AuthoriseUserCreateByAnonymous)")
public void validateRoleTypeForAnonymousUserCreate(JoinPoint joinPoint) {
    HttpServletRequest request = getRequest();

    loggingOperation(joinPoint, request);

    Authentication auth = getAuth();

    if (!auth.getName().equals(ANONYMOUS_USER)) {
        AppUserPrincipal principal =
                ((AppUserPrincipal) auth.getPrincipal());

        if (isAdmin(principal)) {
            return;
        }

        throw new ForbiddenException(TEMPLATE_OPERATION_FORBIDDEN);
    }

    if (isRoleTypeUser(joinPoint)) {
        return;
    }

    throw new ForbiddenException(TEMPLATE_OPERATION_FORBIDDEN);
}

private HttpServletRequest getRequest() {
    RequestAttributes requestAttributes =
            RequestContextHolder.getRequestAttributes();

    if (requestAttributes == null) {
        throw new ForbiddenException(TEMPLATE_OPERATION_FORBIDDEN);
    }

    return ((ServletRequestAttributes) requestAttributes).getRequest();
}

private void loggingOperation(JoinPoint joinPoint,
                              HttpServletRequest request) {
    Map<String, String> pathVariables =
            (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);

    Authentication auth =
            SecurityContextHolder.getContext().getAuthentication();

    log.info(CALL_OPERATION,
            auth.getName(),
            joinPoint.getSignature().getName(),
            pathVariables.toString(),
            Arrays.toString(joinPoint.getArgs()));
}

private Authentication getAuth() {
    return SecurityContextHolder.getContext().getAuthentication();
}

private AppUserPrincipal getUserDetails() {
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();

    if (auth == null || !auth.isAuthenticated()) {
        throw new UserNotAuthenticatedException(TEMPLATE_OPERATION_UNAUTHORIZED);
    }

    return (AppUserPrincipal) auth.getPrincipal();
}

Голос JIT: "Π£ мСня Π΅ΡΡ‚ΡŒ Тёсткий Π»ΠΈΠΌΠΈΡ‚ MaxInlineSize. Если ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΊΡ€ΠΎΡ…ΠΎΡ‚Π½Ρ‹ΠΉ, я просто ΠΊΠΎΠΏΠΈΡ€ΡƒΡŽ Π΅Π³ΠΎ Ρ‚Π΅Π»ΠΎ Π² мСсто Π²Ρ‹Π·ΠΎΠ²Π°. Π“Ρ€Π°Π½ΠΈΡ†Ρ‹ ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°ΠΌΠΈ ΠΈΡΡ‡Π΅Π·Π°ΡŽΡ‚, ΠΊΠΎΠ΄ становится ΠΌΠΎΠ½ΠΎΠ»ΠΈΡ‚Π½Ρ‹ΠΌ ΠΈ Π»Π΅Ρ‚ΠΈΡ‚ со ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒΡŽ свСта. ΠžΠ³Ρ€ΠΎΠΌΠ½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ я Π²Ρ‹Π½ΡƒΠΆΠ΄Π΅Π½ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ "ΠΏΠΎ старинкС" - с сохранСниСм состояния стСка ΠΈ ΠΏΡ€Ρ‹ΠΆΠΊΠ°ΠΌΠΈ ΠΏΠΎ адрСсами. Π‘ΡƒΠ΄ΡŒΡ‚Π΅ ΠΏΡ€ΠΎΡ‰Π΅, ΠΈ я сдСлаю ваш ΠΊΠΎΠ΄ ΠΏΠΎ-настоящСму быстрым!"

Π¨Ρ‘ΠΏΠΎΡ‚ AOT: "Π’ Native Image я ΠΏΡ€ΠΎΠ²ΠΎΠΆΡƒ Π³Π»ΡƒΠ±ΠΎΠΊΠΈΠΉ Π°Π½Π°Π»ΠΈΠ· достиТимости ΠΊΠΎΠ΄Π°. МСлкиС ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ ΠΌΠ½Π΅ Ρ‚ΠΎΡ‡Π½Π΅Π΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ, ΠΊΠ°ΠΊΠΈΠ΅ части ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π½ΠΈΠΊΠΎΠ³Π΄Π° Π½Π΅ Π±ΡƒΠ΄ΡƒΡ‚ Π²Ρ‹Π·Π²Π°Π½Ρ‹, ΠΈ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ Π²Ρ‹Ρ€Π΅Π·Π°Ρ‚ΡŒ ΠΈΡ… ΠΏΡ€ΠΈ сборкС. Π§Π΅ΠΌ Ρ‡ΠΈΡ‰Π΅ структура Π²Π°ΡˆΠΈΡ… ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ², Ρ‚Π΅ΠΌ стройнСС ΠΈ быстрСС ΠΈΡ‚ΠΎΠ³ΠΎΠ²Ρ‹ΠΉ Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊ".

ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–6. ΠŸΡ€Π΅Π°Π»Π»ΠΎΠΊΠ°Ρ†ΠΈΡ ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΉ

Π’ Ρ‡Ρ‘ΠΌ боль: Боздавая new ArrayList<>(), new HashMap<>() ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ структуры Π΄Π°Π½Π½Ρ‹Ρ… Π±Π΅Π· ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ², Π²Ρ‹ подписываСтС JVM Π½Π° ΡΠ΅Ρ€ΠΈΡŽ "ΠΏΠ΅Ρ€Π΅Π΅Π·Π΄ΠΎΠ²". Как Ρ‚ΠΎΠ»ΡŒΠΊΠΎ список наполняСтся, ΠΎΠ½ создаёт массив побольшС ΠΈ ΠΊΠΎΠΏΠΈΡ€ΡƒΠ΅Ρ‚ Ρ‚ΡƒΠ΄Π° старыС Π΄Π°Π½Π½Ρ‹Π΅. Π­Ρ‚ΠΎ лишниС Π°Π»Π»ΠΎΠΊΠ°Ρ†ΠΈΠΈ, фрагмСнтация памяти ΠΈ Ρ€Π°Π±ΠΎΡ‚Π° для GC.

Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅: Π—Π°Π΄Π°Π²Π°ΠΉΡ‚Π΅ Initial Capacity. Π’ Java 19+ для этого появились Π΅Ρ‰Ρ‘ Π±ΠΎΠ»Π΅Π΅ ΡƒΠ΄ΠΎΠ±Π½Ρ‹Π΅ статичСскиС ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ сами ΡƒΡ‡ΠΈΡ‚Ρ‹Π²Π°ΡŽΡ‚ коэффициСнт Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ (Load Factor).

import java.util.LinkedHashMap;

private Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
    // ΠŸΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ Π²Ρ‹Π΄Π΅Π»Π΅Π½ΠΈΠ΅ 16 buckets
    Map<String, Object> errorProperties = LinkedHashMap.newLinkedHashMap(16);

    errorProperties.putAll(getErrorAttributes(request,
            ErrorAttributeOptions.defaults()));

    int status =
            (int) errorProperties.getOrDefault("status", 500);

    return ServerResponse.status(status)
            .contentType(MediaType.APPLICATION_JSON)
            .bodyValue(errorProperties)
            .doOnNext(resp -> log.error("Ошибка запроса: [{}]: {}",
                    status,
                    errorProperties));
}

Голос JIT: "ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π·, ΠΊΠΎΠ³Π΄Π° массив Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΈ Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅Ρ‚ΡΡ, я ΡΠ»Ρ‹ΡˆΡƒ ΠΏΠ»Π°Ρ‡ Garbage Collector’a. Π—Π°Ρ€Π°Π½Π΅Π΅ Π·Π°Π΄Π°Π½Π½Ρ‹ΠΉ Ρ€Π°Π·ΠΌΠ΅Ρ€ – это ΠΊΠ°ΠΊ Π·Π°Π±Ρ€ΠΎΠ½ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ столик Π² рСсторанС: Π½ΠΈΠΊΠ°ΠΊΠΎΠΉ суСты ΠΈ Π»ΠΈΡˆΠ½ΠΈΡ… Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠΉ. Π― просто Π²Ρ‹Π΄Π΅Π»ΡΡŽ ΠΎΠ΄ΠΈΠ½ кусок памяти ΠΈ спокойно Ρ€Π°Π±ΠΎΡ‚Π°ΡŽ с Π½ΠΈΠΌ, Π½Π΅ ΠΎΡ‚Π²Π»Π΅ΠΊΠ°ΡΡΡŒ Π½Π° ΠΏΠ΅Ρ€Π΅ΠΊΠ»Π°Π΄Ρ‹Π²Π°Π½ΠΈΠ΅ Π±Π°ΠΉΡ‚ΠΎΠ²".

Π¨Ρ‘ΠΏΠΎΡ‚ AOT: "Π’ Native Image ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠ°ΠΌΡΡ‚ΡŒΡŽ Π΅Ρ‰Ρ‘ Π±ΠΎΠ»Π΅Π΅ строгоС. ΠŸΡ€Π΅Π°Π»Π»ΠΎΠΊΠ°Ρ†ΠΈΡ позволяСт ΠΌΠ½Π΅ Π»ΡƒΡ‡ΡˆΠ΅ ΠΏΡ€Π΅Π΄ΡΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΏΠΈΠΊΠΎΠ²ΠΎΠ΅ ΠΏΠΎΡ‚Ρ€Π΅Π±Π»Π΅Π½ΠΈΠ΅ RAM вашим ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ. Π§Π΅ΠΌ мСньшС Ρƒ вас динамичСских Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠΉ массивов, Ρ‚Π΅ΠΌ ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½Π΅Π΅ ΠΈ прСдсказуСмСС Π²Π΅Π΄Ρ‘Ρ‚ сСбя Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊ ΠΏΠΎΠ΄ Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠΎΠΉ".

ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–7. BigDecimal vs Long (Π‘ΠΈΡ‚Π²Π° Π·Π° ΠΏΡ€ΠΈΠΌΠΈΡ‚ΠΈΠ²Ρ‹)

Π’ Ρ‡Ρ‘ΠΌ боль: BigDecimal – это тяТёлый ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ скрыт массив int[]. Π›ΡŽΠ±Π°Ρ арифмСтичСская опСрация с Π½ΠΈΠΌ – это созданиС Π½ΠΎΠ²ΠΎΠ³ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π² памяти. Π’ Π±ΠΈΠ»Π»ΠΈΠ½Π³Π΅ ΠΈΠ»ΠΈ высоконагруТСнных расчётах это Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ Ρ‚ΠΎΠ½Π½Ρ‹ мусора Π² памяти, заставляя GC Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π½Π° износ.

Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅: Π₯Ρ€Π°Π½ΠΈΡ‚Π΅ Π΄Π΅Π½Π΅ΠΆΠ½Ρ‹Π΅ значСния Π² ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹Ρ… Π΅Π΄ΠΈΠ½ΠΈΡ†Π°Ρ… (ΠΊΠΎΠΏΠ΅ΠΉΠΊΠΈ, Ρ†Π΅Π½Ρ‚Ρ‹) Π² Ρ‚ΠΈΠΏΠ΅ long. ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΡ‚Π΅ Π½Π° BigDecimal Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² самый послСдний ΠΌΠΎΠΌΠ΅Π½Ρ‚ – ΠΏΡ€ΠΈ Π²Ρ‹Π²ΠΎΠ΄Π΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ.

public record WalletResponse(
    long amount, // long - это быстро
    String currency
) {
    // Волько для красоты ΠΏΡ€ΠΈ Π²Ρ‹Π²ΠΎΠ΄Π΅
    public BigDecimal getDisplayAmount() {
        return BigDecimal.valueOf(amount, 2);
    }
}

Голос JIT: "long – это просто 64 Π±ΠΈΡ‚Π° Π² ΠΌΠΎΡ‘ΠΌ рСгистрС. Π― Ρ…Ρ€Π°Π½ΡŽ Π΅Π³ΠΎ прямо Π² рСгистрах процСссора. Π‘Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄Π²ΡƒΡ… long Π·Π°Π½ΠΈΠΌΠ°Π΅Ρ‚ Π΄ΠΎΠ»ΠΈ наносСкунды. Π‘ BigDecimal я Π²Ρ‹Π½ΡƒΠΆΠ΄Π΅Π½ ΠΏΡ€Ρ‹Π³Π°Ρ‚ΡŒ Π² ΠΊΡƒΡ‡Ρƒ (Heap) Π·Π° ΠΊΠ°ΠΆΠ΄Ρ‹ΠΌ числом ΠΈ Π΅Π³ΠΎ ΠΌΠ°ΡΡˆΡ‚Π°Π±ΠΎΠΌ. Π’Ρ‹Π±ΠΈΡ€Π°ΠΉΡ‚Π΅ long, Ссли Π½Π΅ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ я буксовал Π½Π° элСмСнтарной Π°Ρ€ΠΈΡ„ΠΌΠ΅Ρ‚ΠΈΠΊΠ΅".

Π¨Ρ‘ΠΏΠΎΡ‚ AOT: "Π’ Π±ΠΈΠ½Π°Ρ€Π½ΠΎΠΌ ΠΊΠΎΠ΄Π΅ Native Image Ρ€Π°Π±ΠΎΡ‚Π° с long прСвращаСтся Π² ΠΎΠ΄Π½Ρƒ ΠΈΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡŽ ассСмблСра. BigDecimal ΠΆΠ΅ тянСт Π·Π° собой Π΄Π΅Ρ€Π΅Π²ΠΎ зависимостСй ΠΈ ΡΠ»ΠΎΠΆΠ½ΡƒΡŽ Π»ΠΎΠ³ΠΈΠΊΡƒ управлСния ΠΏΠ°ΠΌΡΡ‚ΡŒΡŽ. Π§Π΅ΠΌ большС ΠΏΡ€ΠΈΠΌΠΈΡ‚ΠΈΠ²ΠΎΠ², Ρ‚Π΅ΠΌ мСньшС ΠΌΠΎΠΉ исполняСмый Ρ„Π°ΠΉΠ» ΠΈ Ρ‚Π΅ΠΌ быстрСС ΠΎΠ½ "прогрСваСтся"".

ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–8. Π˜Π·Π±Π΅Π³Π°ΠΉΡ‚Π΅ прокси Π² критичСских ΡƒΠ·Π»Π°Ρ…

Π’ Ρ‡Ρ‘ΠΌ боль: @Transactional ΠΈ @Async, @Cacheable - это ΡƒΠ΄ΠΎΠ±Π½ΠΎ, Π½ΠΎ Π·Π° кулисами ΠΎΠ½ΠΈ ΡΠΎΠ·Π΄Π°ΡŽΡ‚ динамичСскиС ΠΎΠ±Π΅Ρ€Ρ‚ΠΊΠΈ (Proxy) Π² Ρ€Π°Π½Ρ‚Π°ΠΉΠΌΠ΅. ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ Π²Ρ‹Π·ΠΎΠ² проксированного ΠΌΠ΅Ρ‚ΠΎΠ΄Π° - это лишний "ΠΏΡ€Ρ‹ΠΆΠΎΠΊ" ΠΏΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌ-ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚Ρ‡ΠΈΠΊΠ°ΠΌ, Ρ€Π°Π·Π΄ΡƒΡ‚Ρ‹ΠΉ стСк Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² ΠΈ Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π³Π»ΡƒΠ±ΠΎΠΊΠΎΠ³ΠΎ ΠΈΠ½Π»Π°ΠΉΠ½ΠΈΠ½Π³Π°. Π’ высоконагруТСнных Ρ†ΠΈΠΊΠ»Π°Ρ… это становится настоящим "стСк-ΠΊΠΈΠ»Π»Π΅Ρ€ΠΎΠΌ".

Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅: Π”Π΅Ρ€ΠΆΠΈΡ‚Π΅ бизнСс-Π»ΠΎΠ³ΠΈΠΊΡƒ "чистой". Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ Π°Π½Π½ΠΎΡ‚Π°Ρ†ΠΈΠΈ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° Π²Π΅Ρ€Ρ…Π½Π΅ΠΌ ΡƒΡ€ΠΎΠ²Π½Π΅ (Entry Points), Π° Π²Π½ΡƒΡ‚Ρ€ΠΈ сСрвисов Π²Ρ‹Π·Ρ‹Π²Π°ΠΉΡ‚Π΅ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹Π΅ private/package-private ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹. Если Π²Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ @Transactional ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΈΠ· Ρ‚ΠΎΠ³ΠΎ ΠΆΠ΅ класса - Π²Ρ‹ ΡƒΠΆΠ΅ Π·Π½Π°Π΅Ρ‚Π΅, Ρ‡Ρ‚ΠΎ прокси Π½Π΅ сработаСт (self-invocation), ΠΈ это ΠΎΡ‚Π»ΠΈΡ‡Π½Ρ‹ΠΉ ΠΏΠΎΠ²ΠΎΠ΄ Π·Π°Π΄ΡƒΠΌΠ°Ρ‚ΡŒΡΡ ΠΎ Π΄Π΅ΠΊΠΎΠΌΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ.

@RequiredArgsConstructor
@Transactional(readOnly = true)
@Service
public class UserService {

    @Value("${app.kafka.kafkaStatisticsService.kafkaUserCreatedStatus}")
    private String kafkaUserCreatedStatus;

    private final PasswordEncoder passwordEncoder;

    private final UserRepository userRepository;

    private final UserMapper userMapper;

    private final KafkaTemplate<String, Object> kafkaTemplate;

    public List<User> findAll(UserFilter userFilter) {
        return userRepository.fetchAll(
                UserSpecification.withFilter(userFilter),
                PageRequest.of(
                        userFilter.pageNumber(),
                        userFilter.pageSize()
                )
        ).getContent();
    }

    public User findById(UUID id) {
        return userRepository.findById(id)
                .orElseThrow(() ->
                        new EntityNotFoundException(MessageFormat.format(TEMPLATE_USER_NOT_FOUND_EXCEPTION, id)));
    }

    public User findByUsername(String username) {
        return userRepository.findByUsername(username)
                .orElseThrow(() ->
                        new UsernameNotFoundException("Username not found!"));
    }

    @AuthoriseUserCreateByAnonymous
    @Transactional
    public UUID save(User user, RoleType roleType) {
        // ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ Π²Ρ‹Π·ΠΎΠ² ΠΌΠ΅Ρ‚ΠΎΠ΄Π°
        userRepository.findUserIdByUsernameAndEmail(
                user.getUsername(),
                user.getEmail()
        ).ifPresent(id -> {
                    throw new UserAlreadyExistsException(
                            MessageFormat.format(TEMPLATE_USER_ALREADY_EXISTS_EXCEPTION,
                                    user.getUsername(),
                                    user.getEmail()));
        });

        user.setRoles(new ArrayList<>(List.of(roleType)));
        user.setPassword(passwordEncoder.encode(user.getPassword()));

        UUID userId = userRepository.saveAndFlush(user).getId();

        TransactionSynchronizationManager.registerSynchronization(
                new TransactionSynchronization() {
                    @Override
                    public void afterCommit() {
                        kafkaTemplate.send(kafkaUserCreatedStatus,
                                new UserRegistrationEvent(userId)
                        );
                    }
                }
        );

        return userId;
    }

    @AuthoriseUserUpdateAndDelete
    @Transactional
    public UUID update(UUID userId, UserUpsertRequest request, RoleType roleType) {
        // ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ Π²Ρ‹Π·ΠΎΠ² ΠΌΠ΅Ρ‚ΠΎΠ΄Π°
        User existedUser = findById(userId);

        userMapper.updateUser(request, existedUser);

        if (request.password() != null && !request.password().isBlank()) {
            existedUser.setPassword(passwordEncoder.encode(request.password()));
        }

        if (roleType != null) {
            existedUser.getRoles().clear();
            existedUser.getRoles().add(roleType);
        }

        return userRepository.saveAndFlush(existedUser).getId();
    }

    @AuthoriseUserUpdateAndDelete
    @Transactional
    public void delete(UUID id) {
        findById(id);

        userRepository.deleteById(id);
    }
}

Голос JIT: "ΠŸΡ€ΠΎΠΊΡΠΈ для мСня – это Π»Π°Π±ΠΈΡ€ΠΈΠ½Ρ‚. Π― Π²ΠΈΠΆΡƒ Ρ†Π΅ΠΏΠΎΡ‡ΠΊΡƒ сгСнСрированных классов-ΠΎΠ±Π΅Ρ€Ρ‚ΠΎΠΊ, Ρ‡Π΅Ρ€Π΅Π· ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½ΡƒΠΆΠ½ΠΎ ΠΏΡ€ΠΎΠ΄Ρ€Π°Ρ‚ΡŒΡΡ ΠΊ Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΌΡƒ ΠΊΠΎΠ΄Ρƒ. Π§Π΅ΠΌ мСньшС ΠΌΠ°Π³ΠΈΠΈ ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΌΠ½ΠΎΠΉ ΠΈ вашим ΠΊΠΎΠ΄ΠΎΠΌ, Ρ‚Π΅ΠΌ быстрСС я ΠΏΠΎΡΡ‚Ρ€ΠΎΡŽ прямой Π³Ρ€Π°Ρ„ Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Π½ΡŽ inlining".

Π¨Ρ‘ΠΏΠΎΡ‚ AOT: "ДинамичСскиС прокси – ΠΌΠΎΠΉ Π²Ρ€Π°Π³ Π½ΠΎΠΌΠ΅Ρ€ ΠΎΠ΄ΠΈΠ½. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ½ΠΈ Ρ€Π°Π±ΠΎΡ‚Π°Π»ΠΈ Π² Native Image, ΠΌΠ½Π΅ приходится Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈΡ… Π·Π°Ρ€Π°Π½Π΅Π΅ ΠΈΠ»ΠΈ Ρ‚Π°Ρ‰ΠΈΡ‚ΡŒ тяТёлый ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ рСфлСксии. Убирая лишниС прокси, Π²Ρ‹ ΡƒΠΌΠ΅Π½ΡŒΡˆΠ°Π΅Ρ‚Π΅ количСство сгСнСрированных классов Π² Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊΠ΅ ΠΈ ускоряСтС запуск прилоТСния".

ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–9. Generics: ИзбСгаСм Π»ΠΈΡˆΠ½ΠΈΡ… кастов

Π’ Ρ‡Ρ‘ΠΌ боль: Π₯отя Π² Ρ€Π°Π½Ρ‚Π°ΠΉΠΌΠ΅ Ρ‚ΠΈΠΏΡ‹ ΡΡ‚ΠΈΡ€Π°ΡŽΡ‚ΡΡ (Type Erasure), использованиС Object ΠΈΠ»ΠΈ Raw Types заставляСт вас (ΠΈ JVM) постоянно Π²ΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ Π² Π±Π°ΠΉΡ‚-ΠΊΠΎΠ΄ ΠΈΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡŽ checkcast. Π­Ρ‚ΠΎ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ нСбСзопасно, Π½ΠΎ ΠΈ заставляСт процСссор Ρ‚Ρ€Π°Ρ‚ΠΈΡ‚ΡŒ лишниС Ρ‚Π°ΠΊΡ‚Ρ‹ Π½Π° ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΡƒ ΠΈΠ΅Ρ€Π°Ρ€Ρ…ΠΈΠΈ классов ΠΏΡ€ΠΈ ΠΊΠ°ΠΆΠ΄ΠΎΠΌ ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠΈ ΠΊ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρƒ.

Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅: Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ строго Ρ‚ΠΈΠΏΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ Π΄ΠΆΠ΅Π½Π΅Ρ€ΠΈΠΊΠΈ Π²Π΅Π·Π΄Π΅, Π³Π΄Π΅ Π²Π°ΠΆΠ½Π° ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ. Π­Ρ‚ΠΎ позволяСт компилятору Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΈΠΏΡ‹ Π½Π° этапС сборки, Π° JIT-компилятору - ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΌΠ°ΡˆΠΈΠ½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π±Π΅Π· Π»ΠΈΡˆΠ½ΠΈΡ… "ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒΠ½ΠΎ-пропускных ΠΏΡƒΠ½ΠΊΡ‚ΠΎΠ²".

@RequiredArgsConstructor
@Component
public class ValidatorHandler {

    private final Validator validator;

    // ИспользованиС <T> Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚, Ρ‡Ρ‚ΠΎ Π½Π° Π²Ρ‹Ρ…ΠΎΠ΄Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Ρ‚ΠΎΡ‚ ΠΆΠ΅ Ρ‚ΠΈΠΏ, Ρ‡Ρ‚ΠΎ ΠΈ Π½Π° Π²Ρ…ΠΎΠ΄Π΅
    // Никаких Ρ€ΡƒΡ‡Π½Ρ‹Ρ… (Cast) Π² Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‰Π΅ΠΌ ΠΊΠΎΠ΄Π΅!
    public <T> Mono<T> validate(T body) {
        return Mono.fromCallable(() -> {
                    var violations = validator.validate(body);

                    if (violations.isEmpty()) {
                        return body;
                    }

                    throw new ValidationException(buildErrorMessage(violations));
                })
                .subscribeOn(Schedulers.boundedElastic());
    }

    private String buildErrorMessage(Set<? extends ConstraintViolation<?>> violations) {
        return violations
                .stream()
                .map(v ->
                        v.getPropertyPath() + ": " +
                                v.getMessage())
                .collect(Collectors.joining("; "));
    }
}

Голос JIT: "ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ Ρ€Π°Π·, ΠΊΠΎΠ³Π΄Π° я Π²ΠΈΠΆΡƒ checkcast, я Π²Ρ‹Π½ΡƒΠΆΠ΄Π΅Π½ ΠΏΡ€ΠΈΡ‚ΠΎΡ€ΠΌΠΎΠ·ΠΈΡ‚ΡŒ ΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ: Π° Ρ‚ΠΎΡ‡Π½ΠΎ Π»ΠΈ этот ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π² памяти совпадаСт с ΠΎΠΆΠΈΠ΄Π°Π΅ΠΌΡ‹ΠΌ Ρ‚ΠΈΠΏΠΎΠΌ? Π‘ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΌΠΈ Π΄ΠΆΠ΅Π½Π΅Ρ€ΠΈΠΊΠ°ΠΌΠΈ я Π΄ΠΎΠ²Π΅Ρ€ΡΡŽ Π²Π°ΡˆΠ΅ΠΌΡƒ ΠΊΠΎΠ΄Ρƒ Π½Π° 100%. Для мСня это скоростная трасса Π±Π΅Π· свСтофоров ΠΈ Π»ΠΈΡˆΠ½ΠΈΡ… ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΎΠΊ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²".

Π¨Ρ‘ΠΏΠΎΡ‚ AOT: "Π’ Native Image я ΠΏΡ€ΠΎΠ²ΠΎΠΆΡƒ Static Analysis всСй ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹. Бтрогая типизация ΠΏΠΎΠΌΠΎΠ³Π°Π΅Ρ‚ ΠΌΠ½Π΅ Ρ‚ΠΎΡ‡Π½Π΅Π΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ Π³Ρ€Π°Π½ΠΈΡ†Ρ‹ Ρ‚ΠΈΠΏΠΎΠ² ΠΈ ΠΈΡΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ лишниС ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ ΠΈΠ· Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊΠ°. Π§Π΅ΠΌ мСньшС "нСизвСстных" Object, Ρ‚Π΅ΠΌ мСньшС ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΎΠΊ Ρ‚ΠΈΠΏΠΎΠ² Π² Ρ€Π°Π½Ρ‚Π°ΠΉΠΌΠ΅ ΠΈ Π²Ρ‹ΡˆΠ΅ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ".

ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–10. БтатичСский Π°Π½Π°Π»ΠΈΠ· вмСсто динамичСского (MapStruct)

Π’ Ρ‡Ρ‘ΠΌ боль: Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Π²Ρ€ΠΎΠ΄Π΅ ModelMapper ΠΈΠ»ΠΈ Π·Π»ΠΎΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π»Π΅Π½ΠΈΠ΅ ObjectMapper.convertValue() - это "динамичСский Π½Π°Π»ΠΎΠ³" Π½Π° ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ. Они ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ ΠΈΠ½Ρ‚Ρ€ΠΎΡΠΏΠ΅ΠΊΡ†ΠΈΡŽ Π² Ρ€Π°Π½Ρ‚Π°ΠΉΠΌΠ΅, Π±ΡƒΠΊΠ²Π°Π»ΡŒΠ½ΠΎ "ощупывая" ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π² поисках подходящих ΠΏΠΎΠ»Π΅ΠΉ Ρ‡Π΅Ρ€Π΅Π· getField() ΠΈ setAccessible(true). Для JIT это Π½Π΅ΠΏΡ€ΠΎΠ·Ρ€Π°Ρ‡Π½Ρ‹ΠΉ ΠΊΠΎΠ΄, Π° для Native Image - ΠΊΠΎΠ½Ρ„ΠΈΠ³-Π°Π΄ Π½Π° тысячи строк.

Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅: ΠŸΠ΅Ρ€Π΅Π½ΠΎΡΠΈΡ‚Π΅ всю ΡΠ»ΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π½Π° этап компиляции. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΊΠΎΠ΄ΠΎΠ³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΡŽ. MapStruct Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ Java-ΠΊΠΎΠ΄ target.set(source.get()) Π½Π° этапС компиляции. ΠœΡ‹ ΡƒΠΆΠ΅ Π²ΠΈΠ΄Π΅Π»ΠΈ Π΅Π³ΠΎ ΠΌΠΎΡ‰ΡŒ Π² ΠŸΡ€Π°Π²ΠΈΠ»Π΅ β„–4, Π½ΠΎ здСсь ΠΏΠΎΠ΄Ρ‡Π΅Ρ€ΠΊΠ½Ρ‘ΠΌ: Π½ΡƒΠ»Π΅Π²ΠΎΠΉ ΠΎΠ²Π΅Ρ€Ρ…Π΅Π΄ Π² Ρ€Π°Π½Ρ‚Π°ΠΉΠΌΠ΅ ΠΈ полная ΠΏΡ€ΠΎΠ·Ρ€Π°Ρ‡Π½ΠΎΡΡ‚ΡŒ для ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ‚ΠΎΡ€ΠΎΠ².

@RequiredArgsConstructor
@RequestMapping("/api/v1/user")
@RestController
public class UserController {

    private static final String pathToUserResource = "/api/v1/user/{id}";

    private final UserMapper userMapper;

    private final UserService userService;

    @GetMapping
    public ResponseEntity<UserListResponse> findAll(@Valid UserFilter userFilter) {
        // Чистый ΠΌΠ°ΠΏΠΏΠΈΠ½Π³: Π½ΠΈ ΠΎΠ΄Π½ΠΎΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ рСфлСксии Π² Ρ€Π°Π½Ρ‚Π°ΠΉΠΌΠ΅!
        return ResponseEntity.ok(
                userMapper.userListToUserListResponse(
                        userService.findAll(userFilter)
                )
        );
    }

    @GetMapping("/{id}")
    public ResponseEntity<UserResponse> findById(@PathVariable UUID id) {
        return ResponseEntity.ok(
                userMapper.userToResponse(userService.findById(id))
        );
    }

    @PostMapping
    public ResponseEntity<Void> create(@RequestBody @Valid UserUpsertRequest request,
                                               @RequestParam RoleType roleType) {
        return ResponseEntity.created(getUri(
                userService.save(
                        userMapper.requestToUser(request),
                        roleType
                )
        )).build();
    }

    @PutMapping("/{id}")
    public ResponseEntity<Void> update(@PathVariable("id") UUID userId,
                                       @RequestBody @Valid UserUpsertRequest request,
                                       @RequestParam RoleType roleType) {
        return ResponseEntity.ok()
                .location(getUri(
                        userService.update(userId,
                                request,
                                roleType)
                ))
                .build();
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> delete(@PathVariable("id") UUID userId) {
        userService.delete(userId);
        return ResponseEntity.noContent().build();
    }

    private URI getUri(UUID id) {
        return UriComponentsBuilder.fromPath(pathToUserResource)
                .buildAndExpand(id)
                .toUri();
    }
}

Голос JIT: "Для мСня ΠΊΠΎΠ΄ ΠΎΡ‚ MapStruct – это ΠΏΠΎΠ΄Π°Ρ€ΠΎΠΊ. Π­Ρ‚ΠΎ прямой, понятный ΠΈ прСдсказуСмый ΠΏΠΎΡ‚ΠΎΠΊ инструкций. Π― инлайню Ρ‚Π°ΠΊΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΌΠ³Π½ΠΎΠ²Π΅Π½Π½ΠΎ, прСвращая ΠΌΠ°ΠΏΠΏΠΈΠ½Π³ Π² практичСски Π±Π΅ΡΠΏΠ»Π°Ρ‚Π½ΡƒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ. Никаких поисков ΠΏΠΎ ΠΈΠΌΠ΅Π½Π°ΠΌ ΠΏΠΎΠ»Π΅ΠΉ Π² HashMap ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ… - Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ€Π°Π±ΠΎΡ‚Π° с рСгистрами процСссора".

Π¨Ρ‘ΠΏΠΎΡ‚ AOT: "БтатичСский Π°Π½Π°Π»ΠΈΠ· – ΠΌΠΎΠΉ Π»ΡƒΡ‡ΡˆΠΈΠΉ Π΄Ρ€ΡƒΠ³. ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ MapStruct Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹Π΅ Π²Ρ‹Π·ΠΎΠ²Ρ‹ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ², я Π²ΠΈΠΆΡƒ всС связи ΠΌΠ΅ΠΆΠ΄Ρƒ классами Π΅Ρ‰Ρ‘ ΠΏΡ€ΠΈ сборкС Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊΠ°. МнС Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ Π³Π°Π΄Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊΠΈΠ΅ поля Π²Ρ‹ Π·Π°Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ "ΠΏΠΎΡ‚Ρ€ΠΎΠ³Π°Ρ‚ΡŒ" Ρ‡Π΅Ρ€Π΅Π· Ρ€Π΅Ρ„Π»Π΅ΠΊΡΠΈΡŽ, поэтому я ΠΌΠΎΠ³Ρƒ смСло Π²Ρ‹Ρ€Π΅Π·Π°Ρ‚ΡŒ всё лишнСС ΠΈΠ· ΠΈΡ‚ΠΎΠ³ΠΎΠ²ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π°".

ΠŸΡ€Π°Π²ΠΈΠ»ΠΎ β„–11. Scoped Values вмСсто ThreadLocal

Π’ Ρ‡Ρ‘ΠΌ боль: ΠœΡ‹ дСсятилСтиями Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈ контСкст ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΠΈΠ»ΠΈ Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΈ Π² ThreadLocal. Π­Ρ‚ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Π»ΠΎ, ΠΊΠΎΠ³Π΄Π° ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² Π±Ρ‹Π»ΠΎ 200-500. Но Π² Java 21 Π²Ρ‹ Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚Π΅ spring.threads.virtual.enabled: true ΠΈ запускаСтС 100_000 Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½Ρ‹Ρ… ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². Если ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΈΠ· Π½ΠΈΡ… "присосётся" ΠΊ тяТёлому ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρƒ Π² ThreadLocal, ваш Heap Π»ΠΎΠΏΠ½Π΅Ρ‚ быстрСС, Ρ‡Π΅ΠΌ сработаСт ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ GC. К Ρ‚ΠΎΠΌΡƒ ΠΆΠ΅, ThreadLocal - это измСняСмая структура, Ρ‡Ρ‚ΠΎ само ΠΏΠΎ сСбС услоТняСт ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡŽ.

Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅: Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ Scoped Values (JEP 446 / 464). Они ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ бСзопасно ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ нСизмСняСмыС Π΄Π°Π½Π½Ρ‹Π΅ Π²Π½ΠΈΠ· ΠΏΠΎ Π΄Π΅Ρ€Π΅Π²Ρƒ Π²Ρ‹Π·ΠΎΠ²ΠΎΠ². Как Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΈΠ· Π±Π»ΠΎΠΊΠ° - Π΄Π°Π½Π½Ρ‹Π΅ становятся нСдоступны, Π° ΠΏΠ°ΠΌΡΡ‚ΡŒ ΠΌΠ³Π½ΠΎΠ²Π΅Π½Π½ΠΎ Π³ΠΎΡ‚ΠΎΠ²Π° ΠΊ очисткС. Никаких ΡƒΡ‚Π΅Ρ‡Π΅ΠΊ ΠΈΠ·-Π·Π° Π·Π°Π±Ρ‹Ρ‚ΠΎΠ³ΠΎ .remove().

private final static ScopedValue<UserContext> CURRENT_USER = ScopedValue.newInstance();

public void handleRequest(UserContext context) {
    // ΠŸΡ€ΠΈΠ²ΡΠ·Ρ‹Π²Π°Π΅ΠΌ Π΄Π°Π½Π½Ρ‹Π΅ ΠΊ области видимости. (Scope)
    ScopedValue.where(CURRENT_USER, context).run(() -> {
        // Π’Π½ΡƒΡ‚Ρ€ΠΈ этого Π±Π»ΠΎΠΊΠ° ΠΈ всСх Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Ρ… ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ²
        // CURRENT_USER.get() Π²Π΅Ρ€Π½Ρ‘Ρ‚ наш контСкст.
        // Никаких ΡƒΡ‚Π΅Ρ‡Π΅ΠΊ, Π½ΠΈΠΊΠ°ΠΊΠΎΠΉ привязки ΠΊ ΠΆΠΈΠ·Π½ΠΈ ΠΏΠΎΡ‚ΠΎΠΊΠ°!
        processOrder();
    });
}

Голос JIT: "ThreadLocal для мСня - это тяТёлый Ρ€ΡŽΠΊΠ·Π°ΠΊ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΠΎΡ‚ΠΎΠΊ Π½Π΅ снимаСт Π΄ΠΎ самой смСрти. Π― Π½Π΅ ΠΌΠΎΠ³Ρƒ ΠΏΡ€Π΅Π΄ΡΠΊΠ°Π·Π°Ρ‚ΡŒ, ΠΊΠΎΠ³Π΄Π° ΠΎΠ½ Π΅Π³ΠΎ снимСт. Scoped Value – это лёгкая эстафСтная ΠΏΠ°Π»ΠΎΡ‡ΠΊΠ°: ΠΏΠΎΠ΄Π΅Ρ€ΠΆΠ°Π», ΠΏΠ΅Ρ€Π΅Π΄Π°Π», ΠΈ ΠΎΠ½Π° исчСзла. Π’ ΠΌΠΈΡ€Π΅ ΠΌΠΈΠ»Π»ΠΈΠΎΠ½Π° Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½Ρ‹Ρ… ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² это СдинствСнный способ Π½Π΅ ΡƒΡ‚ΠΎΠ½ΡƒΡ‚ΡŒ Π² бСсконСчных ΠΌΠ°ΠΏΠ°Ρ… Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ²".

Π¨Ρ‘ΠΏΠΎΡ‚ AOT: "ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ±Π»Π°ΡΡ‚ΡŒ видимости Scoped Value Тёстко ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½Π° Π±Π»ΠΎΠΊΠΎΠΌ ΠΊΠΎΠ΄Π°, я ΠΌΠΎΠ³Ρƒ Π³ΠΎΡ€Π°Π·Π΄ΠΎ эффСктивнСС Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ врСмя ΠΆΠΈΠ·Π½ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ². Π­Ρ‚ΠΎ ΠΏΠΎΠΌΠΎΠ³Π°Π΅Ρ‚ ΠΌΠ½Π΅ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ распрСдСлСниС памяти ΠΈ ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΡ‚ΡŒ Π½Π°ΠΊΠ»Π°Π΄Π½Ρ‹Π΅ расходы Π½Π° ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ контСкста Π² Native-Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊΠ΅".

Π€ΠΈΠ½Π°Π»: Π‘Π»ΠΎΠ²ΠΎ AOT

ΠœΡ‹ Π·Π°ΠΊΠΎΠ½Ρ‡ΠΈΠ»ΠΈ наш список. Π’Π΅ΠΏΠ΅Ρ€ΡŒ, ΠΊΠ°ΠΊ ΠΈ Π΄ΠΎΠ³ΠΎΠ²Π°Ρ€ΠΈΠ²Π°Π»ΠΈΡΡŒ, выпускаСм Π½Π° сцСну "ΡΡƒΠ΄ΡŒΡŽ".

AOT: "Π”Ρ€ΡƒΠ·ΡŒΡ, я всё Π²ΠΈΠ΄Π΅Π». Пока Π²Ρ‹ ΠΏΠΈΡˆΠ΅Ρ‚Π΅ ΠΊΠΎΠ΄, я ΡΡ‚Ρ€ΠΎΡŽ Π΅Π³ΠΎ ΠΊΠ°Ρ€Ρ‚Ρƒ. Если Π²Ρ‹ ΡΠΎΠ±Π»ΡŽΠ΄Π°Π΅Ρ‚Π΅ эти ΠΏΡ€Π°Π²ΠΈΠ»Π°, ΠΌΠΎΠΉ статичСский Π°Π½Π°Π»ΠΈΠ· ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ Π³Π»Π°Π΄ΠΊΠΎ, Π° Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊ получаСтся Π»Ρ‘Π³ΠΊΠΈΠΌ ΠΈ быстрым. Обо всСх Π½Π΅ΠΎΠ΄Π½ΠΎΠ·Π½Π°Ρ‡Π½Ρ‹Ρ… ΠΌΠΎΠΌΠ΅Π½Ρ‚Π°Ρ… – Π±ΡƒΠ΄ΡŒ Ρ‚ΠΎ забытая рСфлСксия ΠΈΠ»ΠΈ динамичСский прокси – я сообщу Π²Π°ΠΌ Π»ΠΈΠ±ΠΎ Π½Π° этапС компиляции, Π»ΠΈΠ±ΠΎ ΡƒΠΆΠ΅ Π² процСссС Ρ€Π°Π±ΠΎΡ‚Ρ‹. Мой Π²Π΅Ρ€Π΄ΠΈΠΊΡ‚ прост: ΠΏΠΈΡˆΠΈΡ‚Π΅ ΠΏΡ€ΠΎΠ·Ρ€Π°Ρ‡Π½ΠΎ, ΠΈ я сдСлаю Π²Π°ΡˆΡƒ Java быстрСС Π½Π°Ρ‚ΠΈΠ²Π½ΠΎΠ³ΠΎ C++".

РСзюмС-Ρ‚Π°Π±Π»ΠΈΡ†Π° для Ρ‚Π΅Ρ…, ΠΊΡ‚ΠΎ ΠΊΡ€ΡƒΡ‚ΠΈΡ‚:

β„– Π—ΠΎΠ»ΠΎΡ‚ΠΎΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ ΠŸΡ€ΠΎΡ„ΠΈΡ‚ для JVM (JIT) ΠŸΡ€ΠΎΡ„ΠΈΡ‚ для Native Image (AOT)
1 Record вмСсто POJO АгрСссивный ΠΈΠ½Π»Π°ΠΉΠ½ΠΈΠ½Π³ final ΠΏΠΎΠ»Π΅ΠΉ. Быстрый статичСский Π°Π½Π°Π»ΠΈΠ· Π³Ρ€Π°Ρ„Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ².
2 fillInStackTrace(null) Экономия CPU (Π² 10-50 Ρ€Π°Π·) ΠΏΡ€ΠΈ создании Exception. МСньшС Π½Π°Ρ‚ΠΈΠ²Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π° для ΠΎΠ±Ρ…ΠΎΠ΄Π° стСка Π² Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊΠ΅.
3 Final Π²Π΅Π·Π΄Π΅ Constant Folding (вычислСния Π½Π° этапС компиляции). Π‘ΠΎΠ»Π΅Π΅ ΠΊΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Ρ‹ΠΉ ΠΈ прСдсказуСмый ΠΊΠΎΠ΄.
4 Π‘ΠΌΠ΅Ρ€Ρ‚ΡŒ РСфлСксии ΠŸΡ€ΡΠΌΡ‹Π΅ Π²Ρ‹Π·ΠΎΠ²Ρ‹ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² Π±Π΅Π· поиска Π² Ρ€Π°Π½Ρ‚Π°ΠΉΠΌΠ΅. ΠšΡ€ΠΈΡ‚ΠΈΡ‡Π½ΠΎ: Π˜Π·Π±Π°Π²Π»ΡΠ΅Ρ‚ ΠΎΡ‚ Π³Ρ€ΠΎΠΌΠΎΠ·Π΄ΠΊΠΈΡ… reflect-config.json.
5 ΠšΠΎΡ€ΠΎΡ‚ΠΊΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ Π“Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ΅ встраиваниС (inlining). ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ Ρ€Π°Π·ΠΌΠ΅Ρ€Π° исполняСмого Ρ„Π°ΠΉΠ»Π°.
6 ΠŸΡ€Π΅Π°Π»Π»ΠΎΠΊΠ°Ρ†ΠΈΡ МСньшС ΠΏΠ°ΡƒΠ· Garbage Collector Π½Π° "ΠΏΠ΅Ρ€Π΅Π΅Π·Π΄Ρ‹" массивов. Π‘Π½ΠΈΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΈΠΊΠΎΠ²ΠΎΠ³ΠΎ потрСблСния RAM.
7 Long вмСсто BigDecimal Π Π°Π±ΠΎΡ‚Π° Π½Π° рСгистрах CPU Π±Π΅Π· Π°Π»Π»ΠΎΠΊΠ°Ρ†ΠΈΠΉ Π² ΠΊΡƒΡ‡Π΅. РадикальноС ΡƒΠΌΠ΅Π½ΡŒΡˆΠ΅Π½ΠΈΠ΅ ΠΎΠ±ΡŠΡ‘ΠΌΠ° ΠΆΠΈΠ²Ρ‹Ρ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ².
8 ΠœΠΈΠ½ΠΈΠΌΡƒΠΌ прокси ΠŸΡ€ΠΎΠ·Ρ€Π°Ρ‡Π½Ρ‹ΠΉ Π³Ρ€Π°Ρ„ Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² Π±Π΅Π· ΠΈΠ½Ρ‚Π΅Ρ€Ρ†Π΅ΠΏΡ‚ΠΎΡ€ΠΎΠ². МСньшС динамичСской Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ Π±Π°ΠΉΡ‚-ΠΊΠΎΠ΄Π°.
9 Π§Ρ‘Ρ‚ΠΊΠΈΠ΅ Generics ΠžΡ‚ΠΊΠ°Π· ΠΎΡ‚ Π»ΠΈΡˆΠ½ΠΈΡ… ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΎΠΊ Ρ‚ΠΈΠΏΠΎΠ² (checkcast). Π£ΠΏΡ€ΠΎΡ‰Π΅Π½ΠΈΠ΅ статичСской Ρ‚ΠΈΠΏΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΏΡ€ΠΈ сборкС.
10 CodeGen вмСсто Reflection Π‘ΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ прямого присваивания a = b. НулСвой ΠΎΠ²Π΅Ρ€Ρ…Π΅Π΄: Π½ΠΈΠΊΠ°ΠΊΠΎΠΉ ΠΌΠ°Π³ΠΈΠΈ Π² Ρ€Π°Π½Ρ‚Π°ΠΉΠΌΠ΅.
11 Scoped Values БСзопасная ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° контСкста Π² Virtual Threads. Π‘Ρ‚Π°Π±ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ Heap ΠΏΡ€ΠΈ ΠΌΠΈΠ»Π»ΠΈΠΎΠ½Π°Ρ… ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ².

Голос AOT (Ρ„ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ Π°ΠΊΠΊΠΎΡ€Π΄):

"ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΡ‚Π΅ Π½Π° эту Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ. Если ваш ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ слСдуСт этим ΠΏΡ€Π°Π²ΠΈΠ»Π°ΠΌ, я собСру Π΅Π³ΠΎ Π² Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ стартуСт Π·Π° миллисСкунды. Если Π½Π΅Ρ‚ – я сообщу Π²Π°ΠΌ ΠΎ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ "грязной" рСфлСксии ΠΈΠ»ΠΈ прокси, Π»ΠΈΠ±ΠΎ Π½Π° этапС компиляции, Π»ΠΈΠ±ΠΎ прямо Π² Π»ΠΎΠ± Π²ΠΎ врСмя Ρ€Π°Π±ΠΎΡ‚Ρ‹. Π’Ρ‹Π±ΠΎΡ€ Π·Π° Π²Π°ΠΌΠΈ!"

About

πŸš€ 10+1 Golden Rules for Java 21+ Optimization: JIT, GraalVM Native Image, and Extreme Spring Boot 3 Performance.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors