前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android 14 新特性代码 UUID.fromString & Matcher.matches 的细节改动(扒源码)

Android 14 新特性代码 UUID.fromString & Matcher.matches 的细节改动(扒源码)

作者头像
胖虎哥
发布2024-01-04 08:16:36
1300
发布2024-01-04 08:16:36
举报
文章目录
  • 前言
  • UUID 处理的更改
  • 正则表达式的更改
  • 结束

前言

Android 14 已经出来好久好久了…

今天其他的暂且不论,单纯的讲一下 OpenJDK 17 更新的两点变更(扒源代码)~

  • 对正则表达式的更改
  • UUID 处理

首先,正则表达式的更改:现在,为了更严格地遵循 OpenJDK 的语义,不允许无效的组引用。您可能会看到 java.util.regex.Matcher 类抛出 IllegalArgumentException 的新情况,因此请务必测试应用中使用正则表达式的情形。如需在测试期间启用或停用此变更,请使用兼容性框架工具切换 DISALLOW_INVALID_GROUP_REFERENCE 标志。

其次,UUID 处理:现在,验证输入参数时,java.util.UUID.fromString() 方法会执行更严格的检查,因此您可能会在反序列化期间看到 IllegalArgumentException。如需在测试期间启用或停用此变更,请使用兼容性框架工具切换 ENABLE_STRICT_VALIDATION 标志。

巴拉巴拉,以上是官网的言论,诸君可以看官方的描述地址


UUID 处理的更改

原有代码逻辑~

代码语言:javascript
复制
 /**
     * Creates a {@code UUID} from the string standard representation as
     * described in the {@link #toString} method.
     *
     * @param  name
     *         A string that specifies a {@code UUID}
     *
     * @return  A {@code UUID} with the specified value
     *
     * @throws  IllegalArgumentException
     *          If name does not conform to the string representation as
     *          described in {@link #toString}
     *
     */
    public static UUID fromString(String name) {
        String[] components = name.split("-");
        if (components.length != 5)
            //仅会判断以-分割的数组长度是否等于5来抛出异常
            throw new IllegalArgumentException("Invalid UUID string: "+name);
        for (int i=0; i<5; i++)
            components[i] = "0x"+components[i];

        long mostSigBits = Long.decode(components[0]).longValue();
        mostSigBits <<= 16;
        mostSigBits |= Long.decode(components[1]).longValue();
        mostSigBits <<= 16;
        mostSigBits |= Long.decode(components[2]).longValue();

        long leastSigBits = Long.decode(components[3]).longValue();
        leastSigBits <<= 48;
        leastSigBits |= Long.decode(components[4]).longValue();

        return new UUID(mostSigBits, leastSigBits);
    }

新代码逻辑~

代码语言:javascript
复制
/**
     * Creates a {@code UUID} from the string standard representation as
     * described in the {@link #toString} method.
     *
     * @param  name
     *         A string that specifies a {@code UUID}
     *
     * @return  A {@code UUID} with the specified value
     *
     * @throws  IllegalArgumentException
     *          If name does not conform to the string representation as
     *          described in {@link #toString}
     *
     */
    public static UUID fromString(String name) {
        // BEGIN Android-changed: Java 8 behaviour is more lenient and the new implementation
        // might break apps (b/254278943).
        // Using old implementation for apps targeting Android older than U.
        // 取反! 如果设备的sdk版本,大于等于  UPSIDE_DOWN_CAKE(34)的话,且启用严格验证
        if (!(VMRuntime.getSdkVersion() >= VersionCodes.UPSIDE_DOWN_CAKE
                && Compatibility.isChangeEnabled(ENABLE_STRICT_VALIDATION))) {
            return fromStringJava8(name);
        }
        //如果小于或者没开启严格验证,则执行其他的验证 
        return fromStringCurrentJava(name);
        // END Android-changed: Java 8 behaviour is more lenient and the new implementation
        // might break apps (b/254278943).
    }

如下是java8 的判断方式(跟原来一致)

代码语言:javascript
复制
  /**
     * Extracted for testing purposes only.
     * @hide
     */
    public static UUID fromStringJava8(String name) {
        String[] components = name.split("-");
        if (components.length != 5)
            throw new IllegalArgumentException("Invalid UUID string: "+ name);
        for (int i=0; i<5; i++)
            components[i] = "0x"+components[i];

        long mostSigBits = Long.decode(components[0]).longValue();
        mostSigBits <<= 16;
        mostSigBits |= Long.decode(components[1]).longValue();
        mostSigBits <<= 16;
        mostSigBits |= Long.decode(components[2]).longValue();

        long leastSigBits = Long.decode(components[3]).longValue();
        leastSigBits <<= 48;
        leastSigBits |= Long.decode(components[4]).longValue();

        return new UUID(mostSigBits, leastSigBits);
    }

如下是执行34或者开启严格验证的方法:

代码语言:javascript
复制
/**
     * Extracted for testing purposes only.
     * @hide
     */
    public static UUID fromStringCurrentJava(String name) {
        if (name.length() == 36) {
            char ch1 = name.charAt(8);
            char ch2 = name.charAt(13);
            char ch3 = name.charAt(18);
            char ch4 = name.charAt(23);
            if (ch1 == '-' && ch2 == '-' && ch3 == '-' && ch4 == '-') {
                long msb1 = parse4Nibbles(name, 0);
                long msb2 = parse4Nibbles(name, 4);
                long msb3 = parse4Nibbles(name, 9);
                long msb4 = parse4Nibbles(name, 14);
                long lsb1 = parse4Nibbles(name, 19);
                long lsb2 = parse4Nibbles(name, 24);
                long lsb3 = parse4Nibbles(name, 28);
                long lsb4 = parse4Nibbles(name, 32);
                if ((msb1 | msb2 | msb3 | msb4 | lsb1 | lsb2 | lsb3 | lsb4) >= 0) {
                    return new UUID(
                            msb1 << 48 | msb2 << 32 | msb3 << 16 | msb4,
                            lsb1 << 48 | lsb2 << 32 | lsb3 << 16 | lsb4);
                }
            }
        }
        return fromString1(name);
    }

    private static UUID fromString1(String name) {
        int len = name.length();
        if (len > 36) {
            throw new IllegalArgumentException("UUID string too large");
        }

        int dash1 = name.indexOf('-', 0);
        int dash2 = name.indexOf('-', dash1 + 1);
        int dash3 = name.indexOf('-', dash2 + 1);
        int dash4 = name.indexOf('-', dash3 + 1);
        int dash5 = name.indexOf('-', dash4 + 1);

        // For any valid input, dash1 through dash4 will be positive and dash5
        // negative, but it's enough to check dash4 and dash5:
        // - if dash1 is -1, dash4 will be -1
        // - if dash1 is positive but dash2 is -1, dash4 will be -1
        // - if dash1 and dash2 is positive, dash3 will be -1, dash4 will be
        //   positive, but so will dash5
        if (dash4 < 0 || dash5 >= 0) {
            throw new IllegalArgumentException("Invalid UUID string: " + name);
        }

        long mostSigBits = Long.parseLong(name, 0, dash1, 16) & 0xffffffffL;
        mostSigBits <<= 16;
        mostSigBits |= Long.parseLong(name, dash1 + 1, dash2, 16) & 0xffffL;
        mostSigBits <<= 16;
        mostSigBits |= Long.parseLong(name, dash2 + 1, dash3, 16) & 0xffffL;
        long leastSigBits = Long.parseLong(name, dash3 + 1, dash4, 16) & 0xffffL;
        leastSigBits <<= 48;
        leastSigBits |= Long.parseLong(name, dash4 + 1, len, 16) & 0xffffffffffffL;

        return new UUID(mostSigBits, leastSigBits);
    }

解析: 从代码的角度看起来是多了好多验证,梳理一下:

代码语言:javascript
复制
1. 判断是否34(sdk版本),且未开启严格验证的情况下,还是按照原有代码执行,仅仅判断 以-分割的数组长度是否等于5,若不等于5,则主动抛出异常;

2. 如果sdk版本大于等于34,且开启了严格验证,则会执行fromStringCurrentJava()& fromString1()方法,

fromStringCurrentJava方法中没有主动抛出异常的代码,判断长度是否=36,不等于则执行 fromString1,若等于则继续执行,获取字符串下标8、13、18、23的值,若这四个值不等于 - ,则执行 fromString1;
在fromString1; 方法中,传递的字符串长度不得大于36,若超出则主动抛异常;

继续判断;对于任何有效输入,dash1 到 dash4 将为正数,dash5 将为正数,负数,但检查 dash4 和 dash5 就足够了:
若是dash4小于0,dash5大于等于0,则主动抛出异常;

正则表达式的更改

原有代码逻辑~

代码语言:javascript
复制
/**
     * Attempts to match the entire region against the pattern.
     *
     * <p> If the match succeeds then more information can be obtained via the
     * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods.  </p>
     *
     * @return  <tt>true</tt> if, and only if, the entire region sequence
     *          matches this matcher's pattern
     */
    public boolean matches() {
        synchronized (this) {
            matchFound = nativeMatcher.matches(groups);
        }
        return matchFound;

新代码逻辑~

代码语言:javascript
复制
 /**
     * Attempts to match the entire region against the pattern.
     *
     * <p> If the match succeeds then more information can be obtained via the
     * {@code start}, {@code end}, and {@code group} methods.  </p>
     *
     * @return  {@code true} if, and only if, the entire region sequence
     *          matches this matcher's pattern
     */
    public boolean matches() {
        synchronized (this) {
            matchFound = nativeMatcher.matches(groups);
        }
        //主要增加一个这个
        modCount++;
        return matchFound;
    }

modCount的描述 :记录该匹配器状态被修改的次数

代码语言:javascript
复制
    /**
     * Number of times this matcher's state has been modified
     */
    int modCount;

结束

不是我说哈,你都是系统代码了,还起个 fromString1 这样的方法名称,丢人不~ 就这,有问题私聊我~ 再会~

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-01-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 前言
  • UUID 处理的更改
  • 正则表达式的更改
  • 结束
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档