两个基本功不足导致的bug

作为程序员,基本功不好,可能会在工作中经常碰到一些看起来很隐蔽的 bug,乍看没毛病,自己半天还找不到问题所在。

但是,如果基本功扎实的同学可能一眼就能看出来。

一、HashMap 取不到值

java 复制代码
Map<Integer, Integer> map = new HashMap<>();
resMap.put(1, 1);
System.out.println(map.get(1L));
System.out.println(map.get(1));

大家可以看下,上面的代码输出是什么?我稍后公布答案。

1、源码分析

HashMap的get方法源码如下(已增加自己的注释):

java 复制代码
public V get(Object key) {
    Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}

/**
 * Implements Map.get and related methods.
 *
 * @param hash hash for key
 * @param key the key
 * @return the node, or null if none
 */
final Node<K,V> getNode(int hash, Object key) {
    Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
    // 如果map不为空
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & hash]) != null) {
        // 如果直接通过传进来的key找到了值,直接返回
        // 1)比较传进来key的hash值和在map中对应位置找到的结点的hash值是否一致
        // 2)比较传进来的key对象和在map中对应位置找到的结点的key对象(object)是否相等
        if (first.hash == hash && // always check first node
            ((k = first.key) == key || (key != null && key.equals(k))))
            return first;
        // 如果通过hash找到的结点的下一个节点不为空,说明是链表
        if ((e = first.next) != null) {
            // 如果是红黑树,直接红黑树查找
            if (first instanceof TreeNode)
                return ((TreeNode<K,V>)first).getTreeNode(hash, key);
            // 如果是普通链表,链表遍历查找
            do {
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    // 上述都不满足,返回null
    return null;
}

如果传的 key 对应的 hash 值,能够匹配到 map 中的结点(只能说 hash 表(map)中这个位置有东西),还需要进行下面两个判断。

1)比较传进来 key 的 hash 值和在 map 中对应位置找到的结点的 hash 值是否一致

2)比较传进来的 key 对象和在 map 中对应位置找到的结点的key对象(object)是否相等。

看了上述源码分析之后,我们公布答案:

java 复制代码
null
1

最终的差异就是

java 复制代码
(k = first.key) == key || (key != null && key.equals(k))

这段代码,相当于 Objects.equals(key, k)

这里比较的是,map 中存储的对象的key,命名为k,以及get方法传给map的 key,命名为 key。

相当于比较new Integer(1)new Long(1L),我们知道它们是两个不同的对象,所以结果肯定不相等。所以 key 是1L的时候,结果是 null

2、结论

Map 获取值的时候,key类型不匹配,获取不到value。

二、日期计算

大家可以看看下面这段代码,分别输出的是什么?

复制代码
long nowTime = new Date().getTime();
System.out.println(nowTime);
System.out.println(new Date(nowTime - 7 * 24 * 60 * 60 * 1000));
System.out.println(new Date(nowTime - 25 * 24 * 60 * 60 * 1000));
System.out.println(new Date(nowTime - 30 * 24 * 60 * 60 * 1000));
System.out.println(new Date(nowTime - 60 * 24 * 60 * 60 * 1000));

我们可以把代码扔给 GPT,看它是否能识别其中的 bug。

上面的代码中,存在一个潜在的问题。Date 的构造函数中传入的时间戳参数是 long 类型,而 days * 24 * 60 * 60 * 1000 的计算结果是 int 类型,存在可能的整数溢出问题。

因为 days 和其他整数相乘后超过了 int 类型能表示的范围,所以这会导致计算的结果出现错误。

修复的代码可以将 int 类型的计算结果强制转换为 long 类型,确保计算的精度不会丢失。修复后的代码如下:

复制代码
int days = Integer.valueOf(daysStr);
long millisecondsInDay = (long) days * 24 * 60 * 60 * 1000;
Date startDate = new Date(System.currentTimeMillis() - millisecondsInDay);

这样就可以避免由于整数溢出而导致的计算错误。

所以,这里的知识点是 int 数组进行计算结果是 int 类型,而 int 类型的范围是 21 亿(2^31 - 1)左右。

如果用来计算时间戳,很容易就会越界,导致非预期结果。

三、总结一下

虽然,非科班、培训出身、转行的程序员,可能会存在基本功不好的情况,但是在 AI 时代,这些相关的 bug 能够更快的解决。

只要你会用 AI,这些有固定答案的领域很容易被 AI 取代。

我们更需要的是深入思考、创造性等,只有人能干的事情。

相关推荐
PypYCCcccCc几秒前
支付系统架构图
java·网络·金融·系统架构
华科云商xiao徐22 分钟前
Java HttpClient实现简单网络爬虫
java·爬虫
扎瓦35 分钟前
ThreadLocal 线程变量
java·后端
BillKu1 小时前
Java后端检查空条件查询
java·开发语言
jackson凌1 小时前
【Java学习笔记】String类(重点)
java·笔记·学习
刘白Live1 小时前
【Java】谈一谈浅克隆和深克隆
java
一线大码1 小时前
项目中怎么确定线程池的大小
java·后端
要加油哦~1 小时前
vue · 插槽 | $slots:访问所有命名插槽内容 | 插槽的使用:子组件和父组件如何书写?
java·前端·javascript
crud1 小时前
Spring Boot 3 整合 Swagger:打造现代化 API 文档系统(附完整代码 + 高级配置 + 最佳实践)
java·spring boot·swagger
天天摸鱼的java工程师2 小时前
从被测试小姐姐追着怼到运维小哥点赞:我在项目管理系统的 MySQL 优化实战
java·后端·mysql