最近在工作的过程中,遇到了不少奇怪自己或者同事的Bug,都是一些出乎意料的,不太容易发现的,记录一下来帮助可能也遇到了这些Bug的人

1. 编译时泛型校验失效

Map<String, String> nameToType = new HashMap<>();
nameToType.put( "testName", 123 ); // java: 不兼容的类型: int无法转换为java.lang.String

上面的代码,我们很容易看出来,无法通过编译,因为Map的value需要的是一个String,但我们传的是一个int。但我只要稍微改一下:

package generic;

import java.util.HashMap;
import java.util.Map; public class RecContext<T>{ private Map<String, String> nameToType = new HashMap<>(); public Map<String, String> getNameToType(){ return nameToType;
} public void setNameToType( Map<String, String> nameToType ){ this.nameToType = nameToType;
} public static void main( String[] args ){ RecContext recContextRaw = new RecContext();
recContextRaw.getNameToType().put( "testName", 123 ); }
}

同样是一个value要求为String的Map, 放到一个对象里面就可以通过编译了

不过这不是一个普通的对象,这个Class本身带泛型,但我们在使用的时候,没有指定这个泛型,也就是IDEA中常常报的错,说你在Raw Use这个类型

也正是因为Raw Use了这个类,所以导致它的泛型属性也被类型擦除了,具体可以看StackOverflow-What is a raw type and why shouldn't we use it?

这篇文章里面是这么说的

In simpler terms, when a raw type is used, the constructors, instance methods and non-static fields are also erased

简单地讲,当使用了原始类型,构造器、实例方法和非静态的字段都会被擦除

我们有一个老的项目里面有不少这样的Raw use,也正好有另外一个同事把一个其他的类型插入了这个Map,于是就报了一个类型转换错误,同事们都很震惊,认为这个Map不是有泛型吗,怎么可能插入别的类型,一番排查,才发现是这个问题

解决方法

  1. 不要Raw use类,会使编译校验失效,也有很多其他的理由,可以参考上面那篇文章,我不使用的原因是因为IDEA每次都会发出告警。还有如果发现这个类一直在Raw use也没啥问题,说明这个类本身就不需要泛型,可以考虑是一下是不是需要重构一下

  • 我的告警配置的是黄色的背景,看起来很惹眼
  • IDEA的告警会是Raw use,不可能的条件判断,可以更换写法的代码(完全不影响效果),甚至可能是bug(之前碰到过,修复的时候发现IDEA已经提示了,但是可能别人的告警不是很明显,没看到)
  1. 如果是真的Raw use了类,那检查类型是否错误的责任就落到我们自己的头上,确保不要传进错误的类型,确保取出来的类型不要转换错误

2. 数组删除中的“刻舟求剑”

线上代码中有这样一个逻辑,想从帖子列表中筛选出一部分帖子然后从原列表中删除,其代码逻辑如下:

import java.util.ArrayList;
import java.util.List; public class ListDelTest{ public static void main( String[] args ){ List<Integer> jobIds = new ArrayList<>();
for( int i = 0; i < 10; i++ ){
jobIds.add( i );
} List<Integer> delIndex = new ArrayList<>();
for( int i = 0; i < jobIds.size(); i++ ){ // 线上是其他的筛选逻辑,在这我们用偶数代替
if( jobIds.get( i ) % 2 == 0 ){ delIndex.add( i );
}
} for( int i = 0; i < jobIds.size(); i++ ){
if( delIndex.contains( i ) ){
jobIds.remove( jobIds.get( i ) );
}
} System.out.println( jobIds );
// [1, 2, 4, 5, 7, 8]
}
}

可以看到输出结果中,并不符合我们的预期,我们希望的是把所有的偶数删除,结果中不但有偶数,而且一些奇数也不见了

这个其实很容易理解,因为我们记得位置是0,2,4,6,8

原始数据是0,1,2,3,4,5,6,7,8,9

当我们删除了0时,数据变成了1,2,3,4,5,6,7,8,9

这时候我们再去删除index是2的值,结果就把3这个值给删除了

解决方法

  1. 使用stream filter collect,这种其实不是原地删除,而是新建了一个List, 不过我们把这个List覆盖原来的引用,效果一样
  2. 常见的边遍历边删除的方法,使用Iterator,可以避免ConcurrentModificationException异常
		int i = 0;
Iterator<Integer> iterator = jobIds.iterator();
while( iterator.hasNext() ){
iterator.next();
if( delIndex.contains( i ) ){
iterator.remove();
}
i++;
} System.out.println( jobIds );
// [1, 3, 5, 7, 9]
  1. 倒着删除,这样不会影响我们已经记录过的index,我记得当时我在华为OD面试的时候一个面试官问的我的一个问题,我没答出来,他告诉我的答案
		for( int i = jobIds.size() - 1; i > -1; i-- ){
if( delIndex.contains( i ) ){
jobIds.remove( jobIds.get( i ) );
}
}

3. Java8 HashMap死循环

线上同事上线了一个新的过滤器,我们的过滤器是并发执行的,比如,帖子敏感词过滤,会将帖子分成10份,用10个线程分别执行,执行完了就把结果放到一个公共的map中

很明显,这个map是有线程安全问题的,因为会有多个线程同时去put,然而,因为没考虑到,同事使用了普通的HashMap

线上的现象就是,每过一段时间,某个机器的CPU使用率就到了90%以上,需要重启

按照我们的理解,就算是有并发问题,怎么会使CPU使用变高呢

我们都背过,在Java1.7中的HashMap会因为并发插入产生死循,1.8使用尾插法代替头插法解决了死循环

可我们用的是Java1.8,看起来好像还是有死循环的问题

具体原因我就不仔细分析了,是在链表转换树或者对树进行操作的时候会出现线程安全的问题

可以参考HashMap在jdk1.8也会出现死循环的问题

解决方法

  1. 多线程还是需要使用ConcurrentHashMap

参考

[1] StackOverflow-What is a raw type and why shouldn't we use it?

[2] HashMap在jdk1.8也会出现死循环的问题

Java中代码Bug记录--泛型失效、数组删除、HashMap死循环的更多相关文章

  1. JAVA 中LinkedHashMap要点记录

    JAVA 中LinkedHashMap要点记录 构造函数中可能出现的几个参数说明如下: 1.initialCapacity 初始容量大小,使用无参构造方法时,此值默认是16 2.loadFactor ...

  2. Java 中为什么不能创建泛型数组?

    之前只是知道在 Java 中不能创建泛型数组,今天翻看 <Effective Java>其中对这个部分有讲解,记录一下. 现在我们假设在 Java 中可以创建泛型数组,看看可能会发生什么情 ...

  3. slf4j+log4j在Java中实现日志记录

    小Alan今天来跟大家聊聊开发中既简单又常用但必不可少的一样东西,那是什么呢?那就是日志记录,日志输出,日志保存. 后面就统一用日志记录四个字来形容啦. 日志记录是项目的开发中必不可少的一个环节,特别 ...

  4. JAVA中一些需要记录的知识点(进阶部分)···持续更新

    1.JAVA中的相对路径 file = new file("")与file = new file("./")方式相同,该路径为整个project的根目录(实际上 ...

  5. Java中代码点与代码单元(转)

    摘要 本文介绍 Java 平台支持增补字符的方式.增补字符是 Unicode 标准中代码点超出 U+FFFF 的字符,因此它们无法在 Java 编程语言中描述为单个的 16 位实体(例如char数据类 ...

  6. java中Arrays.sort()对二位数组进行排序

    int [][]a = new int [5][2]; //定义一个二维数组,其中所包含的一维数组具有两个元素 对于一个已定义的二位数组a经行如下规则排序,首先按照每一个对应的一维数组第一个元素进行升 ...

  7. JAVA 中日志的记录于使用

    java中常用的日志框架 日志接口 Commons Logging Apache Commons Logging是一个基于Java的日志记录实用程序,是用于日志记录和其他工具包的编程模型.它通过其他一 ...

  8. Java中定义不了可变长数组怎么办---集合 泛型

    一.集合(Collections) Java使用集合来组织和管理对象. 1.Java的集合类 集合类主要负责保存.盛装和管理对象,因此集合类也被称为容器类. 集合类分为Set.List.Map和Que ...

  9. CDH:5.14.0 中 Hive BUG记录

    CDH5.14.0使用的HIVE版本: 自建表log: +----------------------------------------------------+--+ | createtab_st ...

  10. 【开发技术】java中代码检查checkStyle结果分析

    编写Javadoc代码在Java代码的类.函数.数据成员前中输入/**回车,Eclipse能够自动生成相应的Javadoc代码.可以在后面添加相关的文字说明. Type is missing a ja ...

随机推荐

  1. M3U8下载器加嗅探浏览器

    M3U8下载器太多了,随便一抓一大把,没什么新奇的. 下载地址: https://www.zhaimaojun.cn/P/%e8%a7%86%e9%a2%91%e7%bd%91%e7%ab%99%e5 ...

  2. Golang 开发常用代码片段

    Struct to JsonString type BaseRequest struct { httpMethod string domain string path string params ma ...

  3. uni-app 安卓和IOS更新方案

    一.安卓平台 整包更新(apk),即常规的整个App安装包重新下载安装. 资源热更新(wgt),即App并重新安装,里面的js等前端代码进行更新. Android App,可以直接下载新的apk,只要 ...

  4. postgresql 自动类型转换

    一.错误案例 1.赋值错误: ERROR druid.sql.Statement:149 - {conn-10005, pstmt-20005} execute error. UPDATE sys_p ...

  5. lca总结+树上差分

    lca lca简称最近公共祖先--简介在此,不过多赘述 这里主要写的是倍增算法,oi-wiki上用的是vector,由于本人不会,只会用链表,所以这里就放链表的代码了 例题 加一个数组按倍增数组的方式 ...

  6. 前端scale负数表示翻转

    https://blog.csdn.net/wang_yu_shun/article/details/121299208 极力推荐这个博主写的,前端有关负数的小技巧

  7. IceRPC之服务器地址与TLS的安全性->快乐的RPC

    作者引言 很高兴啊,我们来到了IceRPC之服务器地址与TLS的安全性->快乐的RPC, 基础引导,让自已不在迷茫,快乐的畅游世界. 服务器地址 ServerAddress 了解服务器地址的概念 ...

  8. 原创->CommonsCollections1-DefaultMap链

    今天我打算整点儿不一样的内容,通过之前学习的TransformerMap和LazyMap链,想搞点不一样的,所以我关注了另外一条链DefaultedMap链,主要调用链为: 调用链详细描述: Obje ...

  9. 用pageOffice文档控件实现 office文档在线编辑

    第三方文档控件,pageOffice 系统开发中经常要处理办公文档,如果word,excel,ppt,编辑整理,保存,归档. 开发市场上也有很多第三文文档控件,多年的总结,还是认为pageOffice ...

  10. LLM实战:LLM微调加速神器-Unsloth + Qwen1.5

    1. 背景 上一篇介绍了基于训练加速框架Unsloth,微调训练Llama3的显卡资源占用及训练时间对比. 近期Unsloth新增了Qwen1.5的模型适配,因此本qiang~马不停蹄地又进行了一次实 ...