Repository: netty/netty
File: codec-http/src/main/java/io/netty/handler/codec/http/HttpVersion.java (Java)

Code before:
    private final String protocolName;
    private final int majorVersion;
    private final int minorVersion;
    private final String text;
    private final boolean keepAliveDefault;
    private final byte[] bytes;

    /**
     * Creates a new HTTP version with the specified version string.  You will
     * not need to create a new instance unless you are implementing a protocol
     * derived from HTTP, such as
     * <a href="https://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol">RTSP</a> and
     * <a href="https://en.wikipedia.org/wiki/Internet_Content_Adaptation_Protocol">ICAP</a>.
     *
     * @param keepAliveDefault
     *        {@code true} if and only if the connection is kept alive unless
     *        the {@code "Connection"} header is set to {@code "close"} explicitly.
     */
    public HttpVersion(String text, boolean keepAliveDefault) {
        this(text, false, keepAliveDefault);
    }

    HttpVersion(String text, boolean strict, boolean keepAliveDefault) {
        text = checkNonEmptyAfterTrim(text, "text").toUpperCase();

        Matcher m = strict ? VERSION_PATTERN_STRICT.matcher(text) : VERSION_PATTERN.matcher(text);
        if (!m.matches()) {
            throw new IllegalArgumentException("invalid version format: " + text);
        }

        protocolName = m.group(1);
        majorVersion = Integer.parseInt(m.group(2));
        minorVersion = Integer.parseInt(m.group(3));
        this.text = protocolName + '/' + majorVersion + '.' + minorVersion;
        this.keepAliveDefault = keepAliveDefault;
        bytes = null;
    }

    /**
     * Creates a new HTTP version with the specified protocol name and version
     * numbers.  You will not need to create a new instance unless you are
     * implementing a protocol derived from HTTP, such as
     * <a href="https://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol">RTSP</a> and
     * <a href="https://en.wikipedia.org/wiki/Internet_Content_Adaptation_Protocol">ICAP</a>
     *
     * @param keepAliveDefault
     *        {@code true} if and only if the connection is kept alive unless
     *        the {@code "Connection"} header is set to {@code "close"} explicitly.
     */
    public HttpVersion(
            String protocolName, int majorVersion, int minorVersion,

Review comment (suggestion):
optionally: for `strict` validation, it's possible to avoid using `Pattern` completely by checking length, then either by character or with `startsWith`. No need to check digits because they will be checked by either `Integer.parseInt` or you can consider a custom method to convert char to int

Code after:
    private final int minorVersion;
    private final String text;
    private final boolean keepAliveDefault;
    private final byte[] bytes;

    /**
     * Creates a new HTTP version with the specified version string.  You will
     * not need to create a new instance unless you are implementing a protocol
     * derived from HTTP, such as
     * <a href="https://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol">RTSP</a> and
     * <a href="https://en.wikipedia.org/wiki/Internet_Content_Adaptation_Protocol">ICAP</a>.
     *
     * @param keepAliveDefault
     *        {@code true} if and only if the connection is kept alive unless
     *        the {@code "Connection"} header is set to {@code "close"} explicitly.
     */
    public HttpVersion(String text, boolean keepAliveDefault) {
        this(text, false, keepAliveDefault);
    }

    HttpVersion(String text, boolean strict, boolean keepAliveDefault) {
        text = checkNonEmptyAfterTrim(text, "text").toUpperCase();

        if (strict) {
            // Only single digit major / minor version is allowed.
            // See
            //  - https://datatracker.ietf.org/doc/html/rfc7230#section-2.6
            //  - https://datatracker.ietf.org/doc/html/rfc9110#name-protocol-version
            if (text.length() != 8 || !text.startsWith("HTTP/") || text.charAt(6) != '.') {
                throw new IllegalArgumentException("invalid version format: " + text);
            }
            protocolName = "HTTP";
            majorVersion = toDecimal(text.charAt(5));
            minorVersion = toDecimal(text.charAt(7));
        } else {
            Matcher m = VERSION_PATTERN.matcher(text);
            if (!m.matches()) {
                throw new IllegalArgumentException("invalid version format: " + text);
            }

            protocolName = m.group(1);
            majorVersion = Integer.parseInt(m.group(2));
            minorVersion = Integer.parseInt(m.group(3));
        }

        this.text = protocolName + '/' + majorVersion + '.' + minorVersion;
        this.keepAliveDefault = keepAliveDefault;
        bytes = null;
    }

    private static int toDecimal(final int value) {