必须用自定义checkstyle规则在编译前拦截集合滥用:识别空集合调用get(0)/element()、arraylist/linkedlist作共享缓存、map.put(key,null)三类高危模式,基于ast扫描method_call和new_class节点,无有效防护即报错阻断,并配套修复模板与安全替代方案。

直接在源码中拦截集合滥用,不能靠运行时或人工提醒——必须用自定义 Checkstyle 规则,在编译前就报错。核心是识别高危模式并阻断,不是提示或警告。
识别三类典型集合滥用场景
静态检查要盯紧以下明确违反安全红线的行为:
-
空集合直接调用 get(0)、element()、remove(0) 等下标/首元素操作:如
list.get(0)出现在未判空或未校验 size 的上下文中 -
用 ArrayList 或 LinkedList 做高频读写共享缓存:检测到
new ArrayList()/new LinkedList()出现在被@Service、@Component或静态字段修饰的类中,且方法体含多线程访问特征(如含synchronized、Lock、volatile关键字) -
Map.put(key, null) 或 List.add(null):对泛型为非
?的集合执行显式null插入,且该集合声明未标注@Nullable
编写自定义 Checkstyle 检查器
继承 AbstractCheck,重写 visitToken 方法,基于 AST 节点做语义判断:
- 扫描
METHOD_CALL节点,匹配get、element、remove等方法名,并向上查找最近的VARIABLE_DEF或PARAMETER_DEF,确认其类型是否为List/Deque子类 - 沿父节点回溯,检查是否被
if、while或assert包裹,且条件中含.size() > 0、!= null、!isEmpty()等有效防护逻辑;若无,则报错 - 对
NEW_CLASS节点,提取构造器参数类型与所在作用域(类注解、字段修饰符),结合白名单包名(如test、mock)做排除
集成到构建与开发流程
规则生效需闭环落地:
- 在
checkstyle.xml中启用自定义模块:<module name="ProhibitUnsafeCollectionAccess"><br> <property name="allowedCollections" value="java.util.concurrent.CopyOnWriteArrayList,com.google.common.collect.ImmutableList"></property><br></module>
- Maven 配置中设置
<failsonerror>true</failsonerror>,CI 流水线中触发mvn validate即阻断 - IDEA 中配置 Checkstyle 插件指向同一
checkstyle.xml,开启实时高亮,错误行直接标红不可提交 - 对历史代码允许临时豁免,但需在
suppressions.xml中按行号精确声明,并绑定 Jira 编号与整改时限
配套规范与替代方案引导
只报错不给路会引发抵触,规则需自带“出口”:
- 当检测到
list.get(0)无防护时,建议快速修复模板:list.isEmpty() ? null : list.get(0)或list.stream().findFirst().orElse(null) - 对共享缓存场景,自动提示替换为
ConcurrentHashMap、CacheBuilder.newBuilder().build()或团队封装的SafeCache工具类 - 所有集合字段声明强制要求加
@NonNull/@Nullable注解(通过另一个 Checkstyle 规则保障),让 null 安全可追溯











