Sonar提示将常量类的public final static Map改为protected后编译报错如何解决?
问题根因说明
- Sonar触发"Make this member protected"提示的核心原因是:你定义的
public static finalMap是可变集合,外部可以直接调用put、remove等方法修改常量值,存在数据安全风险,Sonar规则要求要么降低访问权限,要么对可变集合做封装。 - 改protected后编译报错的常见原因:
- 若该常量定义在接口中,Java接口的成员变量强制为
public static final,不支持protected修饰符,直接修改会直接编译失败 - 若该常量定义在普通类中,编译报错是因为已有外部包的代码直接引用了这个public常量,protected仅允许同包或子类访问,跨包访问会触发权限校验错误
- 若该常量定义在接口中,Java接口的成员变量强制为
- 你当前贴的原始代码本身存在运行时异常隐患:键
T4重复出现2次,Collectors.toMap默认遇到重复键会直接抛出IllegalStateException,必须先修复该问题。
重构解决方案
方案1:保留public权限,消除Sonar告警(最常用,无需修改现有引用)
将Map封装为不可变集合,从根源解决可变集合的安全风险,Sonar告警会自动消失,无需修改访问权限:
public static final Map<String, String> TYPES = Stream.of(new String[][]{ {"T1", "ABC"}, {"T2", "ABC1"}, {"T3", "ABC2"}, {"T4", "ABC3"}, {"T4", "ABC4"} }) // 第三个参数指定重复键合并规则,此处保留先出现的value,可按需调整 .collect(Collectors.collectingAndThen( Collectors.toMap(data -> data[0], data -> data[1], (oldVal, newVal) -> oldVal), Collections::unmodifiableMap ));
Java 11也可以改用Map.ofEntries写法更简洁,生成的本身就是不可变Map,无需额外封装:
public static final Map<String, String> TYPES = Map.ofEntries( Map.entry("T1", "ABC"), Map.entry("T2", "ABC1"), Map.entry("T3", "ABC2"), Map.entry("T4", "ABC3") // 重复的T4按需保留需要的entry即可 );
方案2:按Sonar要求改为protected权限
如果确认该常量不需要对外暴露,按以下步骤修改:
- 若常量定义在接口中,先将其移动到同包的普通常量类/工具类中,接口不支持protected修饰符
- 修复重复键问题,调整Map定义:
protected static final Map<String, String> TYPES = Stream.of(new String[][]{ {"T1", "ABC"}, {"T2", "ABC1"}, {"T3", "ABC2"}, {"T4", "ABC3"}, {"T4", "ABC4"} }) .collect(Collectors.toMap(data -> data[0], data -> data[1], (oldVal, newVal) -> oldVal));
- 处理编译报错:若有跨包代码引用该常量,要么将引用代码移到同包下,要么给常量类加public的getter方法对外暴露:
public static Map<String, String> getTypes() { return Collections.unmodifiableMap(TYPES); }
内容的提问来源于stack exchange,提问作者Pallavi Singh
相关产品推荐
相关产品推荐

