天天看点

FindBugs错误描述

FindBugs错误描述

本文档列出了FindBugs 3.0.1版报告的标准错误模式 。

概要

描述 类别

- BC:Equals方法不应该假定它的参数类型 坏习惯

位:检查按位操作的符号 坏习惯

CN:类实现可克隆但不定义或使用克隆方法 坏习惯

CN:克隆方法不调用super.clone() 坏习惯

CN:类定义clone()但不实现Cloneable 坏习惯

CNT:已知常数的粗糙值 坏习惯

Co:抽象类定义协变compareTo()方法 坏习惯

Co:compareTo()/ compare()不正确地处理float或double值 坏习惯

Co:compareTo()/ compare()返回Integer.MIN_VALUE 坏习惯

Co:协变量compareTo()方法定义 坏习惯

DE:方法可能会丢弃异常 坏习惯

DE:方法可能会忽略异常 坏习惯

DMI:由于Entry对象的重用,添加条目集的元素可能会失败 坏习惯

DMI:创建并使用一次随机对象 坏习惯

DMI:不要使用removeAll清除集合 坏习惯

Dm:方法调用System.exit(…) 坏习惯

Dm:方法调用危险方法runFinalizersOnExit 坏习惯

ES:使用==或!=比较String参数 坏习惯

ES:使用==或!=比较String对象 坏习惯

Eq:抽象类定义协变量equals()方法 坏习惯

Eq:等于检查不兼容的操作数 坏习惯

Eq:Class定义compareTo(…)并使用Object.equals() 坏习惯

Eq:equals方法对于子类型失败 坏习惯

方程:协方差equals()方法定义 坏习惯

FI:空终止器应该被删除 坏习惯

FI:显式调用终结器 坏习惯

FI:Finalizer nulls字段 坏习惯

FI:Finalizer只有nulls字段 坏习惯

FI:Finalizer不调用超类终结器 坏习惯

FI:Finalizer使超类终结器无效 坏习惯

FI:Finalizer只能调用超类终结器 坏习惯

FS:格式字符串应使用%n而不是\ n 坏习惯

GC:通用调用中未选中的类型 坏习惯

HE:类定义equals()但不是hashCode() 坏习惯

HE:类定义equals()并使用Object.hashCode() 坏习惯

HE:类定义hashCode()但不等于() 坏习惯

HE:类定义hashCode()并使用Object.equals() 坏习惯

HE:类继承equals()并使用Object.hashCode() 坏习惯

IC:超类在初始化时使用子类 坏习惯

IMSE:非法捕获IllegalMonitorStateException 坏习惯

ISC:只提供静态方法的类的不必要的实例化 坏习惯

它:Iterator next()方法不能抛出NoSuchElementException 坏习惯

J2EE:将不可序列化的对象存储到HttpSession中 坏习惯

JCIP:不可变类的领域应该是最终的 坏习惯

ME:公开枚举方法无条件设置其字段 坏习惯

ME:枚举字段是公共和可变的 坏习惯

NP:具有布尔返回类型的方法返回显式为null 坏习惯

NP:克隆方法可能返回null 坏习惯

NP:equals()方法不检查null参数 坏习惯

NP:toString方法可能返回null 坏习惯

Nm:类名应以大写字母开头 坏习惯

Nm:类不是从异常导出的,即使它被命名为这样 坏习惯

Nm:混淆方法名称 坏习惯

Nm:字段名称应以小写字母开头 坏习惯

Nm:在更高版本的Java中使用作为关键字的标识符 坏习惯

Nm:在更高版本的Java中使用作为关键字的标识符 坏习惯

Nm:方法名称应以小写字母开头 坏习惯

Nm:类名不应该隐藏实现接口的简单名称 坏习惯

Nm:类名不应该隐藏超类的简单名称 坏习惯

Nm:非常混乱的方法名称(但也许是故意的) 坏习惯

Nm:由于参数错误,方法不会覆盖超类中的方法 坏习惯

ODR:方法可能无法关闭数据库资源 坏习惯

ODR:方法可能无法关闭异常时的数据库资源 坏习惯

操作系统:方法可能无法关闭流 坏习惯

操作系统:方法可能无法关闭异常流 坏习惯

PZ:不要在迭代器中重新使用条目对象 坏习惯

RC:可疑参考比较与常数 坏习惯

RC:布尔值的可疑引用比较 坏习惯

RR:方法忽略InputStream.read()的结果 坏习惯

RR:方法忽略InputStream.skip()的结果 坏习惯

RV:否定compareTo()/ compare()的结果 坏习惯

RV:方法忽略异常返回值 坏习惯

SI:静态初始化程序在分配所有静态最终字段之前创建实例 坏习惯

SW:某些swing方法需要在Swing线程中被调用 坏习惯

Se:可序列化类中的非瞬态非可序列化实例字段 坏习惯

Se:不可序列化的类有一个可序列化的内部类 坏习惯

Se:可序列化的值存储在可序列化类的实例字段中 坏习惯

Se:比较器不实现Serializable 坏习惯

Se:可序列化的内部类 坏习惯

Se:serialVersionUID不是final 坏习惯

Se:serialVersionUID不长 坏习惯

Se:serialVersionUID不是静态的 坏习惯

Se:Class是Serializable,但是它的超类没有定义一个void构造函数 坏习惯

Se:Class是Externalizable,但没有定义一个void构造函数 坏习惯

Se:readResolve方法必须以Object的返回类型声明。 坏习惯

Se:不是通过反序列化设置的瞬态字段。 坏习惯

SnVI:Class是Serializable,但不定义serialVersionUID 坏习惯

UI:如果类被扩展,GetResource的使用可能不安全 坏习惯

BC:不可能投 正确性

BC:不可能的downcast 正确性

BC:不可能downcast toArray()的结果 正确性

BC:instanceof将永远返回false 正确性

BIT:按位添加有符号字节值 正确性

位:不兼容的位掩码 正确性

BIT:检查((…)&0)== 0 正确性

位:不兼容的位掩码 正确性

BIT:带符号字节值的按位OR 正确性

位:检查按位操作的符号 正确性

BOA:类覆盖超类适配器错误地实现的方法 正确性

BSHIFT:可能的错误解析移位操作 正确性

BSHIFT:32位int移位量不在-31..31范围内 正确性

DLS:在return语句中无用增量 正确性

DLS:类文字的死存储 正确性

DLS:覆盖增量 正确性

DMI:反转方法参数 正确性

DMI:月份不变值 正确性

DMI:BigDecimal由双精度构造,未精确表示 正确性

DMI:hasNext方法调用下一个 正确性

DMI:集合不应该包含自己 正确性

DMI:喔!一个无意义的方法调用 正确性

DMI:在数组上调用hashCode 正确性

DMI:在int上调用Double.longBitsToDouble 正确性

DMI:追求收藏 正确性

Dm:无法使用反射来检查注释的存在,而无需运行时保留 正确性

Dm:尝试更改ScheduledThreadPoolExecutor的最大池大小的尝试 正确性

Dm:创建具有零核心线程的ScheduledThreadPoolExecutor 正确性

Dm:对EasyMock方法无用/空虚调用 正确性

Dm:Math.max和Math.min的组合不正确 正确性

EC:equals()用于比较数组和非数组 正确性

EC:在数组上调用equals(),相当于== 正确性

EC:equals(…)用于比较不兼容的数组 正确性

EC:调用equals(null) 正确性

EC:调用equals()比较不相关的类和接口 正确性

EC:调用equals()比较不同的接口类型 正确性

EC:调用equals()比较不同类型 正确性

EC:使用指针相等来比较不同的类型 正确性

Eq:equals方法总是返回false 正确性

Eq:equals方法总是返回true 正确性

Eq:equals方法比较类名而不是类对象 正确性

方程:为枚举定义的协方差equals()方法 正确性

Eq:equals()方法定义为不覆盖equals(Object) 正确性

方程式:equals()方法定义不覆盖Object.equals(Object) 正确性

Eq:equals方法覆盖在超类中等于可能不对称 正确性

方程:协变量equals()方法定义,Object.equals(Object)继承 正确性

FE:对NaN平等的测试 正确性

FS:格式化字符串占位符与传递的参数不兼容 正确性

FS:提供的参数的类型与格式说明符不匹配 正确性

FS:MessageFormat提供了预期的printf样式格式 正确性

FS:比格式化字符串中实际使用的参数更多 正确性

FS:非法格式字符串 正确性

FS:格式字符串引用缺少参数 正确性

FS:格式字符串以前没有参数 正确性

GC:泛型参数和方法参数之间没有关系 正确性

HE:签名声明在散列结构中使用不可分级的类 正确性

HE:在散列数据结构中使用没有hashCode()方法的类 正确性

ICAST:将int值转换为long并用作绝对时间 正确性

ICAST:将积分值转换为double,然后传递给Math.ceil 正确性

ICAST:将int值转换为float,然后传递给Math.round 正确性

IJU:JUnit不会注意到run方法中的JUnit断言 正确性

IJU:TestCase声明一个坏的套件方法 正确性

IJU:TestCase没有测试 正确性

IJU:TestCase定义不调用super.setUp()的setUp 正确性

IJU:TestCase实现了非静态套件方法 正确性

IJU:TestCase定义了不调用super.tearDown()的tearDown 正确性

IL:一个集合被添加到它自己 正确性

IL:一个明显的无限循环 正确性

IL:一个明显的无限递归循环 正确性

IM:整数余数的整数乘法 正确性

INT:int值与长常数的比较差 正确性

INT:非负值与负常数或零比较不良 正确性

INT:有符号字节的比较差 正确性

IO:注定尝试附加到对象输出流 正确性

IP:参数在输入方法后死机,但被覆盖 正确性

MF:类定义屏蔽超类字段的字段 正确性

MF:方法定义了一个模糊字段的变量 正确性

NP:空指针取消引用 正确性

NP:异常路径中方法中的空指针取消引用 正确性

NP:方法不检查null参数 正确性

NP:对始终为空的值调用close() 正确性

NP:空值保证被取消引用 正确性

NP:值为空,并保证在异常路径上被取消引用 正确性

NP:非空字段未初始化 正确性

NP:方法调用将null传递给非空参数 正确性

NP:方法可能返回null,但声明为@Nonnull 正确性

NP:检查一个已知的空值,看它是否是一个类型的实例 正确性

NP:可能的空指针取消引用 正确性

NP:在异常路径中的方法中可能的空指针取消引用 正确性

NP:方法调用对非空参数传递null 正确性

NP:方法调用对非空参数传递null 正确性

NP:非虚函数调用对非空参数传递null 正确性

NP:具有可选返回类型的方法返回显式为null 正确性

NP:将空值存储到字段注释的@Nonnull中 正确性

NP:读取未写字段 正确性

Nm:类定义相等(Object); 应该是等于(Object)吗? 正确性

Nm:类定义hashcode(); 应该是hashCode()? 正确性

Nm:类定义了tostring(); 应该是toString()? 正确性

Nm:表观方法/构造器混淆 正确性

Nm:非常混乱的方法名称 正确性

Nm:由于参数错误,方法不会覆盖超类中的方法 正确性

QBA:方法在布尔表达式中分配布尔文本 正确性

RANGE:数组索引超出范围 正确性

范围:数组长度超出范围 正确性

RANGE:数组偏移超出范围 正确性

RANGE:字符串索引超出范围 正确性

RC:可疑参考比较 正确性

RCN:以前取消引用的值的空值 正确性

RE:正则表达式的语法无效 正确性

RE:用于正则表达式的File.separator 正确性

回覆: ”。” 或“|” 用于正则表达式 正确性

RV:从0到1的随机值被强制为整数0 正确性

RV:尝试计算带符号的32位哈希码的绝对值 正确性

RV:尝试计算带符号随机整数的绝对值 正确性

RV:代码检查compareTo返回的特定值 正确性

RV:异常创建并丢弃而不是抛出 正确性

RV:方法忽略返回值 正确性

RpC:重复条件测试 正确性

SA:自我指派领域 正确性

SA:自己与自己的比较 正确性

SA:涉及领域的无意识的自我计算(例如,x&x) 正确性

SA:自我分配的本地而不是分配到字段 正确性

SA:自我价值与自身的比较 正确性

SA:涉及变量的无意识的自我计算(例如,x&x) 正确性

SF:由于switch语句的死存储掉落 正确性

SF:由于切换语句的死存储掉落到扔 正确性

SIC:致力于拥抱非静态内部类和线程本地 正确性

SIO:使用instanceof运算符进行不必要的类型检查 正确性

SQL:方法尝试使用索引0访问准备好的语句参数 正确性

SQL:方法尝试访问索引为0的结果集字段 正确性

STI:不需要使用currentThread()调用,调用interrupt() 正确性

STI:在线程实例上调用静态Thread.interrupted()方法 正确性

Se:方法必须是私有的才能使序列化工作 正确性

Se:readResolve方法不能被声明为静态方法。 正确性

TQ:标注为携带类型限定符的值,用于不需要携带该限定词的值 正确性

TQ:将值与不兼容的类型限定符进行比较 正确性

TQ:可能不携带类型限定符的值始终以某种方式使用,需要该类型限定符 正确性

TQ:可能携带类型限定符的值总是以某种方式禁止它使用该类型限定符 正确性

TQ:注释为从不携带类型限定符的值,用于需要携带该限定词的值 正确性

TQ:没有类型限定符的值用于需要具有该限定符的值 正确性

UMAC:匿名类中定义的不可调用方法 正确性

UR:构造函数中未初始化的字段读取 正确性

UR:从超类的构造函数调用的字段方法的未初始化读 正确性

USELESS_STRING:在未命名的数组上调用toString 正确性

USELESS_STRING:在数组上调用toString 正确性

USELESS_STRING:使用格式字符串以无用的方式格式化的数组 正确性

UwF:字段只有设置为null 正确性

UwF:未写字段 正确性

VA:原始数组传递给函数,期望可变数目的对象参数 正确性

LG:由于OpenJDK中的弱参考,潜在的记录器变化 试验

OBL:方法可能无法清理流或资源 试验

OBL:方法可能无法清除已检查异常的流或资源 试验

Dm:考虑使用调用方法的Locale参数化版本 国际化

Dm:依赖于默认编码 国际化

DP:只能在doPrivileged块内创建类加载器 恶意代码漏洞

DP:只应在doPrivileged块中调用的方法 恶意代码漏洞

EI:可以通过返回对可变对象的引用来暴露内部表示 恶意代码漏洞

EI2:通过引用可变对象可能会暴露内部表示 恶意代码漏洞

FI:Finalizer应该被保护,而不是public 恶意代码漏洞

MS:可以通过将可变对象存储到静态字段中来暴露内部静态 恶意代码漏洞

MS:字段不是最终的,不能受到恶意代码的保护 恶意代码漏洞

MS:公共静态方法可能会通过返回数组暴露内部表示 恶意代码漏洞

MS:字段应该是final和package protected 恶意代码漏洞

MS:Field是一个可变数组 恶意代码漏洞

MS:Field是一个可变的集合 恶意代码漏洞

MS:Field是一个可变的集合,应该被包保护 恶意代码漏洞

MS:Field是一个可变的Hashtable 恶意代码漏洞

MS:字段应该从界面移出并使其受到保护 恶意代码漏洞

MS:字段应该被包保护 恶意代码漏洞

MS:领域不是最后的,但应该是 恶意代码漏洞

MS:领域不是最终的,但应该重构 恶意代码漏洞

AT:调用并发抽象的顺序可能不是原子的 多线程正确性

DC:可以双重检查字段 多线程正确性

DC:可能暴露部分初始化的对象 多线程正确性

DL:布尔型同步 多线程正确性

DL:盒装原始图像上的同步 多线程正确性

DL:内联字符串同步 多线程正确性

DL:对盒装原始值进行同步 多线程正确性

Dm:监视Wait()调用条件 多线程正确性

Dm:使用默认的空运行方法创建一个线程 多线程正确性

ESync:清空同步块 多线程正确性

IS:不一致的同步 多线程正确性

IS:字段没有防止并发访问 多线程正确性

JLM:在锁上执行同步 多线程正确性

JLM:在util.concurrent实例上执行同步 多线程正确性

JLM:在util.concurrent抽象上使用监视器样式等待方法 多线程正确性

LI:静态字段的懒惰初始化不正确 多线程正确性

LI:不正确的懒惰初始化和静态字段的更新 多线程正确性

ML:野外同步,试图守卫这一领域 多线程正确性

ML:方法在更新的字段上同步 多线程正确性

MSF:可变的servlet字段 多线程正确性

MWN:不匹配的notify() 多线程正确性

MWN:不匹配wait() 多线程正确性

NN:裸体通知 多线程正确性

NP:在同一字段上进行同步和空检查。 多线程正确性

否:使用notify()而不是notifyAll() 多线程正确性

RS:Class的readObject()方法是同步的 多线程正确性

RV:putIfAbsent的返回值被忽略,传递给putIfAbsent的值被重用 多线程正确性

Ru:调用一个线程运行(你的意思是启动它吗?) 多线程正确性

SC:构造函数调用Thread.start() 多线程正确性

SP:方法在现场旋转 多线程正确性

STCAL:调用静态日历 多线程正确性

STCAL:调用静态DateFormat 多线程正确性

STCAL:静态日历字段 多线程正确性

STCAL:静态DateFormat 多线程正确性

SWL:方法调用带有锁的Thread.sleep() 多线程正确性

TLW:等待两个锁 多线程正确性

UG:非同步get方法,同步集方法 多线程正确性

UL:方法不释放所有路径上的锁定 多线程正确性

UL:方法不释放所有异常路径上的锁定 多线程正确性

UW:无条件等待 多线程正确性

VO:对volatile字段的增量不是原子的 多线程正确性

VO:对数组的易失性引用不会将数组元素视为volatile 多线程正确性

WL:同步在getClass而不是类文字 多线程正确性

WS:类的writeObject()方法是同步的,但没有其他的 多线程正确性

Wa:Condition.await()不在循环中 多线程正确性

Wa:等待不循环 多线程正确性

Bx:原始值被盒装,然后立即取消装箱 性能

Bx:原始值被装箱,然后取出盒装,以执行原始强制 性能

Bx:原始值被取消装箱,并被胁迫用于三元运算符 性能

Bx:装箱值取消装箱,然后立即重新装箱 性能

Bx:拳击一个原始的比较 性能

Bx:打包/取消装箱来解析原始图形 性能

Bx:方法分配一个盒子的原语只是调用toString 性能

Bx:方法调用无效的浮点数构造函数; 使用static valueOf代替 性能

Bx:方法调用无效数字构造函数; 使用static valueOf代替 性能

Dm:URL的equals和hashCode方法被阻止 性能

Dm:地图和URL集可以是性能指标 性能

Dm:方法调用无效的布尔构造函数; 使用Boolean.valueOf(…)代替 性能

Dm:显式垃圾收集; 非常可疑,除了基准代码 性能

Dm:方法分配对象,仅用于获取类对象 性能

Dm:使用nextInt方法,而不是nextDouble来生成随机整数 性能

Dm:方法调用无效的新String(String)构造函数 性能

Dm:方法在String上调用toString()方法 性能

Dm:方法调用无效的新的String()构造函数 性能

HSC:巨大的字符串常量在多个类文件中重复 性能

SBSC:方法使用循环中的+连接字符串 性能

SIC:应该是一个静态的内部类 性能

SIC:可以重构成一个命名的静态内部类 性能

SIC:可以重构成静态内部类 性能

SS:未读字段:该字段应该是静态的吗? 性能

UM:方法调用一个常量值的静态Math类方法 性能

UPM:私有方法从不被调用 性能

UrF:未读字段 性能

UuF:未使用的字段 性能

WMI:使用keySet迭代器而不是entrySet迭代器 性能

Dm:硬编码常数数据库密码 安全

Dm:空数据库密码 安全

HRS:由不受信任的输入形成的HTTP cookie 安全

HRS:HTTP响应分裂漏洞 安全

PT:servlet中绝对路径遍历 安全

PT:servlet中的相对路径遍历 安全

SQL:在SQL语句上传递给execute或addBatch方法的非常数字符串 安全

SQL:从非常数字符串生成一个准备语句 安全

XSS:JSP反映了跨站点脚本漏洞 安全

XSS:Servlet反映了错误页面中的跨站点脚本漏洞 安全

XSS:Servlet反映了跨站脚本的漏洞 安全

BC:可疑的转换为抽象集合 Dodgy代码

BC:具体收藏可疑 Dodgy代码

BC:未经检查/未确认的演员 Dodgy代码

BC:从方法中取消选中/未确认的返回值 Dodgy代码

BC:instanceof将永远返回true Dodgy代码

BSHIFT:无符号右移转换为短/字节 Dodgy代码

CI:类是最终的,但声明保护字段 Dodgy代码

DB:方法对两个分支使用相同的代码 Dodgy代码

DB:方法对两个switch子句使用相同的代码 Dodgy代码

DLS:死存储到本地变量 Dodgy代码

DLS:在return语句中无用的赋值 Dodgy代码

DLS:null存储为局部变量 Dodgy代码

DLS:死存储到阴影场的局部变量 Dodgy代码

DMI:代码包含对绝对路径名的硬编码引用 Dodgy代码

DMI:写入ObjectOutput的非可序列化对象 Dodgy代码

DMI:调用子串(0),返回原始值 Dodgy代码

Dm:Runnable预期的线程通过 Dodgy代码

方程式:类不超过等级超类 Dodgy代码

方程式:不寻常的等于方法 Dodgy代码

FE:测试浮点数相等 Dodgy代码

FS:使用%b格式说明符格式化的非布尔参数 Dodgy代码

IA:潜移默化地调用继承方法或外部方法 Dodgy代码

IC:初始化圆形度 Dodgy代码

ICAST:积分分割结果转换为双倍或浮动 Dodgy代码

ICAST:整数乘法的结果转换为long Dodgy代码

IM:平均值的计算可能溢出 Dodgy代码

IM:检查对负数不起作用的奇数 Dodgy代码

INT:整数余数模1 Dodgy代码

INT:对整数值进行空值位掩码操作 Dodgy代码

INT:整数值的比较 Dodgy代码

MTIA:Class扩展Servlet类并使用实例变量 Dodgy代码

MTIA:Class扩展Struts Action类并使用实例变量 Dodgy代码

NP:对readLine()的结果的引用没有nullcheck Dodgy代码

NP:立即取消引用readLine()的结果 Dodgy代码

NP:加载已知的空值 Dodgy代码

NP:方法收紧参数上的无效注释 Dodgy代码

NP:方法放宽返回值的无效注释 Dodgy代码

NP:由于调用方法的返回值,可能的空指针取消引用 Dodgy代码

NP:对分支可能是不可行的可能的null指针取消引用 Dodgy代码

NP:参数必须为非空值,但标记为可空 Dodgy代码

NP:阅读不成文的公共或受保护的字段 Dodgy代码

NS:潜在危险的使用非短路逻辑 Dodgy代码

NS:可疑使用非短路逻辑 Dodgy代码

PZLA:考虑返回零长度数组而不是null Dodgy代码

QF:循环中复杂,微妙或错误的增量 Dodgy代码

RCN:将非空值与零的冗余比较 Dodgy代码

RCN:两个空值的冗余比较 Dodgy代码

RCN:已知为非空的值的冗余nullcheck Dodgy代码

RCN:已知为null的值的冗余nullcheck Dodgy代码

REC:异常未被抛出时被捕获 Dodgy代码

RI:类实现与超类相同的接口 Dodgy代码

RV:方法检查String.indexOf的结果是否为正 Dodgy代码

RV:方法在检查是否为非空之后丢弃readLine的结果 Dodgy代码

RV:hashCode的剩余值可能为负 Dodgy代码

RV:32位有符号随机整数的余数 Dodgy代码

RV:方法忽略返回值,是吗? Dodgy代码

RV:无副作用的方法的返回值被忽略 Dodgy代码

SA:双重分配字段 Dodgy代码

SA:局部变量的双重赋值 Dodgy代码

SA:局部变量的自我赋值 Dodgy代码

SF:在下一个案例中发现一个案例的switch语句 Dodgy代码

SF:在默认情况下缺少找到的switch语句 Dodgy代码

ST:从实例方法写入静态字段 Dodgy代码

Se:Private readResolve方法不由子类继承 Dodgy代码

Se:不可序列化的类的瞬态字段。 Dodgy代码

TQ:具有类型限定符但标记为未知的值 Dodgy代码

TQ:不需要类型限定符,但标记为未知的值 Dodgy代码

UC:条件没有影响 Dodgy代码

UC:由于变量类型,条件没有影响 Dodgy代码

UC:无用的对象创建 Dodgy代码

UC:在堆栈上创建无用的对象 Dodgy代码

UC:无用的非空void方法 Dodgy代码

UCF:无用的控制流程 Dodgy代码

UCF:无用的控制流程到下一行 Dodgy代码

Urf:未公开/受保护的字段 Dodgy代码

UuF:未使用的公共或受保护的字段 Dodgy代码

UwF:字段未在构造函数中初始化,但未引用,不进行空检查 Dodgy代码

UwF:未公开或受保护的字段 Dodgy代码

XFB:方法直接分配xml接口的特定实现 Dodgy代码

说明

BC:Equals方法不应该假定它的参数类型(BC_EQUALS_METHOD_SHOULD_WORK_FOR_ALL_OBJECTS)

该equals(Object o)方法不应该对该类型做出任何假设o。它应该简单地返回false,如果o不是相同的类型this。

BIT:检查按位操作的符号(BIT_SIGNED_CHECK)

这个方法比较了一个表达式

((event.detail&SWT.SELECTED)> 0)

使用位运算然后与大于运算符进行比较会导致意想不到的结果(当然取决于SWT.SELECTED的值)。如果SWT.SELECTED是负数,这是一个bug的候选者。即使SWT.SELECTED不是负数,使用’!= 0’而不是’> 0’似乎是很好的习惯。

鲍里斯·博科夫斯基

CN:类实现可克隆但不定义或使用克隆方法(CN_IDIOM)

类实现可克隆但不定义或使用克隆方法。

CN:克隆方法不调用super.clone()(CN_IDIOM_NO_SUPER_CALL)

这个非最终类定义了一个不调用super.clone()的clone()方法。如果该类(“ A ”)被子类(“ B ”)扩展,并且子类B调用super.clone(),则很可能 B的clone()方法将返回A类型的对象,这违反了克隆()的标准合同。

如果所有的clone()方法调用super.clone(),那么它们将保证使用Object.clone(),它始终返回正确类型的对象。

CN:Class定义clone()但不实现Cloneable(CN_IMPLEMENTS_CLONE_BUT_NOT_CLONEABLE)

该类定义了一个clone()方法,但该类不实现Cloneable。在某些情况下,这是可以的(例如,您想要控制子类如何克隆自己),但只要确保这是您的意图。

CNT:已知常数的粗糙值(CNT_ROUGH_CONSTANT_VALUE)

建议使用预定义的库常量来实现代码清晰度和更高的精度。

Co:抽象类定义协变量compareTo()方法(CO_ABSTRACT_SELF)

这个类定义了一个协变的版本compareTo()。要正确覆盖接口中的compareTo()方法 Comparable,参数compareTo() 必须具有类型java.lang.Object。

Co:compareTo()/ compare()不正确地处理float或double值(CO_COMPARETO_INCORRECT_FLOATING)

这个方法比较double或float值,使用像这样的模式:val1> val2?1:val1

}

进口beta.Foo;

公共类B扩展A {

public int f(Foo x){return 42; }

public int f(alpha.Foo x){return 27; }

}

在f(Foo)类定义的方法B不会覆盖 f(Foo)在类中定义的方法A,因为参数类型Foo的不同包。

在这种情况下,子类确定了一个方法,该方法的签名与超类中的方法相同,因此可以理解这一点。然而,这种方法格外混乱。您应该强烈地考虑使用类似但不相同的签名来删除或弃用该方法。

ODR:方法可能无法关闭数据库资源(ODR_OPEN_DATABASE_RESOURCE)

该方法创建数据库资源(例如数据库连接或行集),不将其分配给任何字段,将其传递给其他方法或返回它,并且不会在方法之外的所有路径上关闭对象。如果在方法之外的所有路径上关闭数据库资源都可能导致性能下降,并可能导致应用程序与数据库通信时出现问题。

ODR:方法可能无法关闭异常时的数据库资源(ODR_OPEN_DATABASE_RESOURCE_EXCEPTION_PATH)

该方法创建数据库资源(例如数据库连接或行集),不将其分配给任何字段,将其传递给其他方法或返回它,并且不会将所有异常路径上的对象关闭,方法。如果在方法之外的所有路径上关闭数据库资源都可能导致性能下降,并可能导致应用程序与数据库通信时出现问题。

操作系统:方法可能无法关闭流(OS_OPEN_STREAM)

该方法创建一个IO流对象,不将其分配给任何字段,将其传递给可能关闭它的其他方法,或返回它,并且不会将所有路径上的流关闭出来。这可能导致文件描述符泄漏。通常一个好主意是使用finally块来确保流被关闭。

操作系统:方法可能无法关闭异常流(OS_OPEN_STREAM_EXCEPTION_PATH)

该方法创建一个IO流对象,不将其分配给任何字段,将其传递给其他方法或返回它,并且似乎不会将其关闭在方法之外的所有可能的异常路径上。这可能导致文件描述符泄漏。通常一个好主意是使用finally块来确保流被关闭。

PZ:不要在迭代器中重新使用条目对象(PZ_DONT_REUSE_ENTRY_OBJECTS_IN_ITERATORS)

entrySet()方法允许返回一个迭代器和Map.Entry的底层Map的视图。这个聪明的想法在几个Map实现中被使用,但是引入了令人讨厌的编码错误的可能性。如果地图m为一个entrySet返回这样一个迭代器,那么 c.addAll(m.entrySet())将会出错。OpenJDK 1.7中的所有Map实现都被重写,以避免这种情况。

RC:与常量的可疑引用比较(RC_REF_COMPARISON_BAD_PRACTICE)

该方法使用==或!=运算符将引用值与常量进行比较,其中用于比较此类型实例的正确方法通常为equals()方法。可以创建不相同但不与==比较的不同实例,因为它们是不同的对象。通常不能通过引用比较的类的示例是java.lang.Integer,java.lang.Float等

RC:布尔值的可疑引用比较(RC_REF_COMPARISON_BAD_PRACTICE_BOOLEAN)

该方法使用==或!=运算符比较两个布尔值。通常,只有两个布尔值(Boolean.TRUE和Boolean.FALSE),但是可以使用new Boolean(b) 构造函数创建其他布尔对象。最好避免这样的对象,但是如果它们确实存在,那么使用==或者!=来检查布尔对象是否相等会给出不同于使用的结果.equals(…)

RR:方法忽略InputStream.read()(RR_NOT_CHECKED)的结果

此方法忽略其中一个变体java.io.InputStream.read()返回多个字节的返回值 。如果未检查返回值,则调用者将无法正确处理读取的字节少于调用方请求的情况。这是一个特别阴险的错误,因为在许多程序中,从输入流读取通常会读取所需数据的全部数量,导致程序只能偶尔失败。

RR:方法忽略InputStream.skip()(SR_NOT_CHECKED)的结果

此方法忽略返回值 java.io.InputStream.skip()可以跳过多个字节。如果未检查返回值,则调用者将无法正确处理跳过少于调用方请求的字节数的情况。这是一个特别阴险的错误,因为在许多程序中,从输入流中跳过通常会跳过所请求的全部数据,导致程序只能偶尔失败。然而,使用缓冲流,skip()只会跳过缓冲区中的数据,并且将常规地跳过请求的字节数。

RV:取消compareTo()/ compare()(RV_NEGATING_RESULT_OF_COMPARETO)的结果

此代码对比较方法或比较方法的返回值进行否定。这是一个有问题或不好的编程实践,因为如果返回值为Integer.MIN_VALUE,否则返回值不会取消结果的符号。您可以通过反转操作数的顺序而不是否定结果来实现相同的预期结果。

RV:方法忽略异常返回值(RV_RETURN_VALUE_IGNORED_BAD_PRACTICE)

此方法返回未检查的值。应检查返回值,因为它可以指示异常或意外的功能执行。例如,File.delete()如果文件无法成功删除(而不是抛出异常),则该方法返回false。如果不检查结果,则不会注意到方法调用是否通过返回非典型返回值来发出意外行为。

SI:静态初始化程序在分配所有静态最终字段之前创建实例(SI_INSTANCE_BEFORE_FINALS_ASSIGNED)

该类的静态初始化程序在分配所有静态final字段之前创建一个类的实例。

SW:某些swing方法需要在Swing线程中调用(SW_SWING_METHODS_INVOKED_IN_SWING_THREAD)

(从JDC技术提示):Swing方法show(),setVisible()和pack()将为该帧创建关联的对等体。通过创建对等体,系统创建事件调度线程。这使事情有问题,因为事件发送线程可能通知监听器,而包和验证仍在处理中。这种情况可能导致两个线程通过基于Swing组件的GUI - 这是一个严重的缺陷,可能会导致死锁或其他相关的线程问题。一个包呼叫导致组件被实现。当它们被实现(即不一定可见)时,他们可以在事件发送线程上触发监听器通知。

Se:可序列化类中的非瞬态非可序列化实例字段(SE_BAD_FIELD)

此Serializable类定义了一个非原始实例字段既不是瞬时的,序列化的,或java.lang.Object,并没有出现以实现Externalizable接口或 readObject()和writeObject()方法。如果非可序列化对象存储在此字段中,则此类的对象将不会正确反序列化。

Se:非可序列化类有一个可序列化的内部类(SE_BAD_FIELD_INNER_CLASS)

这个Serializable类是一个不可序列化类的内部类。因此,尝试序列化它也将尝试将与其相关联的外部类的实例关联,从而导致运行时错误。

如果可能,使内部类成为一个静态的内部类应该可以解决问题。使外部类可序列化也可以工作,但这意味着序列化内部类的实例将始终也将外部类的实例序列化,这通常不是您真正想要的。

Se:存储在可序列化类的实例字段中的非可序列化值(SE_BAD_FIELD_STORE)

非可序列化的值存储在可序列化类的非瞬态字段中。

Se:Comparator不实现Serializable(SE_COMPARATOR_SHOULD_BE_SERIALIZABLE)

该类实现了Comparator接口。你应该考虑是否也应该实现Serializable 接口。如果使用比较器来构造一个有序集合,如a TreeMap,则TreeMap 只有比较器也可串行化,才可以串行化。由于大多数比较者很少或没有状态,使得它们可序列化通常是容易和良好的防御性编程。

Se:可序列化的内部类(SE_INNER_CLASS)

这个Serializable类是一个内部类。任何尝试序列化它也将序列化相关联的外部实例。外部实例是可序列化的,所以这不会失败,但是它可能会比预期的序列化更多的数据。如果可能,使内部类成为静态内部类(也称为嵌套类)应该可以解决问题。

Se:serialVersionUID不是final(SE_NONFINAL_SERIALVERSIONID)

这个类定义一个serialVersionUID不是final 的字段。如果打算为了序列化目的指定版本UID,那么该字段应该是最终的。

Se:serialVersionUID不长(SE_NONLONG_SERIALVERSIONID)

这个类定义一个serialVersionUID不长的字段。如果要为序列化目的指定版本UID,那么该字段应该很长。

Se:serialVersionUID不是静态的(SE_NONSTATIC_SERIALVERSIONID)

这个类定义一个serialVersionUID不是静态的字段。如果旨在指定用于序列化的UID版本,则该字段应该是静态的。

Se:Class是Serializable,但是它的超类没有定义一个void构造函数(SE_NO_SUITABLE_CONSTRUCTOR)

这个类实现了Serializable接口,它的超类没有。当这样的对象反序列化时,超类的字段需要通过调用超类的void构造函数进行初始化。由于超类没有一个,序列化和反序列化将在运行时失败。

Se:Class是Externalizable,但没有定义一个void构造函数(SE_NO_SUITABLE_CONSTRUCTOR_FOR_EXTERNALIZATION)

这个类实现了Externalizable接口,但没有定义一个void构造函数。当Externalizable对象被反序列化时,它们首先需要通过调用void构造函数来构造。由于此类没有一个,因此序列化和反序列化将在运行时失败。

Se:readResolve方法必须以Object的返回类型声明。(SE_READ_RESOLVE_MUST_RETURN_OBJECT)

为了使readResolve方法被序列化机制识别,它必须被声明为具有Object的返回类型。

Se:不是通过反序列化设置的瞬态字段。(SE_TRANSIENT_FIELD_NOT_RESTORED)

该类包含一个在类中的多个位置更新的字段,因此它似乎是类的一部分。但是,由于该字段被标记为transient并且未在readObject或readResolve中设置,因此它将包含该类的任何反序列化实例中的默认值。

SnVI:Class是Serializable,但不定义serialVersionUID(SE_NO_SERIALVERSIONID)

该类实现Serializable接口,但不定义一个serialVersionUID字段。添加对.class对象的引用的简单更改将会将合成字段添加到类中,这将不幸地更改隐式serialVersionUID(例如,添加引用String.class 将生成静态字段class java lang$String)。而且,对于字节码编译器的不同源代码可能会为为类对象或内部类引用生成的合成变量使用不同的命名约定。要确保Serializable跨版本的互操作性,请考虑添加一个显式的serialVersionUID。

UI:如果扩展类(UI_INHERITANCE_UNSAFE_GETRESOURCE),GetResource的使用可能不安全

this.getClass().getResource(…)如果此类由另一个包中的类扩展,则调用可能会给出预期结果。

BC:不可能的演员(BC_IMPOSSIBLE_CAST)

这个演员总是会抛出一个ClassCastException。FindBugs跟踪来自instanceof检查的类型信息,并且还使用关于从方法返回并从字段加载的值的类型的更精确的信息。因此,它可能有更精确的信息,只是声明的变量类型,并且可以使用它来确定转换将在运行时总是引发异常。

BC:不可能downcast(BC_IMPOSSIBLE_DOWNCAST)

这个演员总是会抛出一个ClassCastException。分析认为它知道正在投放的值的确切类型,并且尝试将其转换为子类型将始终通过抛出ClassCastException而失败。

BC:不可能的downArray()结果(BC_IMPOSSIBLE_DOWNCAST_OF_TOARRAY)

这个代码是将toArray()一个集合的调用结果转换成一个更具体的类型Object[],如:

String [] getAsArray(Collection c){

return(String [])c.toArray();

}

这通常会通过抛出ClassCastException而失败。在toArray() 几乎所有的集合返回Object[]。它们不能做任何其他事情,因为Collection对象没有引用所声明的通用类型的集合。

从集合中获取特定类型的数组的正确方法是使用 c.toArray(new String[]); 或c.toArray(new String[c.size()]);(后者稍微更有效)。

有一个常见/已知的异常例外。toArray() 返回的列表的方法Arrays.asList(…)将返回一个协变类型的数组。例如,Arrays.asArray(new String[] { “a” }).toArray() 将返回一个String []。FindBugs尝试检测和抑制这种情况,但可能会错过一些。

BC:instanceof将始终返回false(BC_IMPOSSIBLE_INSTANCEOF)

这个测试的例子总是返回false。虽然这是安全的,但确保它不是一些误会或其他逻辑错误的迹象。

BIT:按位添加有符号字节值(BIT_ADD_OF_SIGNED_BYTE)

添加一个字节值和已知具有8个较低位清除的值。在对值执行任何按位操作之前,从字节数组加载的值将被扩展为32位。因此,如果b[0]包含值0xff,并且 x最初为0,则代码 ((x << 8) + b[0]) 将对扩展0xff 进行符号扩展0xffffffff,从而给出该值 0xffffffff作为结果。

特别地,将字节数组打包到int中的以下代码是非常错误的:

int result = 0;

for(int i = 0; i <4; i ++)

result =((result << 8)+ b [i]);

以下成语将改为:

int result = 0;

for(int i = 0; i <4; i ++)

result =((result << 8)+(b [i]&0xff));

位:不兼容位掩码(BIT_AND)

该方法将形式(e&C)与D的表达式进行比较,由于常数C和D的具体值,它总是将不相等。这可能表示逻辑错误或打字错误。

BIT:检查(())&0)== 0(BIT_AND_ZZ)

该方法将形式(e&0)的表达式与0进行比较,总是相等。这可能表示逻辑错误或打字错误。

位:不兼容的位掩码(BIT_IOR)

该方法将形式(e | C)与D.的表达式进行比较,由于常数C和D的特定值,它将始终比较不等式。这可能表示逻辑错误或打字错误。

通常,此错误发生是因为代码要在位集中执行成员资格测试,但使用按位OR运算符(“|”)而不是按位AND(“&”)。

BIT:带符号字节值的比特或(BIT_IOR_OF_SIGNED_BYTE)

加载字节值(例如,从字节数组加载的值或由返回类型字节的方法返回),并对该值执行按位OR。在对该值执行任何按位操作之前,字节值被扩展为32位。因此,如果b[0]包含值0xff,并且 x最初为0,则代码 ((x << 8) | b[0]) 将对扩展0xff 进行符号扩展0xffffffff,从而给出该值 0xffffffff作为结果。

特别地,将字节数组打包到int中的以下代码是非常错误的:

int result = 0;

for(int i = 0; i <4; i ++)

result =((result << 8)| b [i]);

以下成语将改为:

int result = 0;

for(int i = 0; i <4; i ++)

result =((result << 8)|(b [i]&0xff));

BIT:检查按位操作的符号(BIT_SIGNED_CHECK_HIGH_BIT)

这个方法比较了一个表达式

((event.detail&SWT.SELECTED)> 0)

使用位运算然后与大于运算符进行比较会导致意想不到的结果(当然取决于SWT.SELECTED的值)。如果SWT.SELECTED是负数,这是一个bug的候选者。即使SWT.SELECTED不是负数,使用’!= 0’而不是’> 0’似乎是很好的习惯。

鲍里斯·博科夫斯基

BOA:Class覆盖超类适配器错误地实现的方法(BOA_BADLY_OVERRIDDEN_ADAPTER)

此方法覆盖在父类中找到的方法,其中该类是实现java.awt.event或javax.swing.event包中定义的侦听器的适配器。因此,当事件发生时,此方法将不会被调用。

BSHIFT:可能的差错解析(BSHIFT_WRONG_ADD_PRIORITY)

代码执行像(x << 8 + y)这样的操作。虽然这可能是正确的,可能它的意思是执行(x << 8)+ y,但是移位运算具有较低的优先级,所以它实际上被解析为x <<(8 + y)。

BSHIFT:32位int移动量不在-31..31范围内(ICAST_BAD_SHIFT_AMOUNT)

代码执行一个32位int的移位一个恒定的量在-31..31范围之外。这样做的效果是使用整数值的低5位来决定要移动多少(例如,移位40位与移位8位相同,移位32位与移位零相同位)。这可能不是预期的,至少令人困惑。

DLS:return语句中的无用增量(DLS_DEAD_LOCAL_INCREMENT_IN_RETURN)

这个声明有一个回报,如return x++;。后缀增加/减量不会影响表达式的值,因此此增量/减量不起作用。请验证此声明是否正确。

DLS:类文字的死存储(DLS_DEAD_STORE_OF_CLASS_LITERAL)

此指令将类文字分配给变量,然后再不使用它。 在Java 1.4和Java 5中,这种行为有所不同。 在Java 1.4及更早版本中,如果尚未执行Foo.class静态初始化程序的引用,则会强制执行静态初始化Foo程序。在Java 5及更高版本中,它不会。

有关 更多详细信息和示例,请参阅Sun 关于Java SE兼容性的文章,以及有关如何在Java 5中强制类初始化的建议。

DLS:覆盖增量(DLS_OVERWRITTEN_INCREMENT)

代码执行增量操作(例如i++),然后立即覆盖它。例如,i = i++立即用增加的值覆盖原始值。

DMI:反转方法参数(DMI_ARGUMENTS_WRONG_ORDER)

这个方法调用的参数似乎是错误的顺序。例如,一个调用Preconditions.checkNotNull(“message”, message) 具有保留参数:要检查的值是第一个参数。

DMI:月份不变值(DMI_BAD_MONTH)

该代码将一个恒定的月值超出了0..11的预期范围。

DMI:BigDecimal由双精度构造,未精确表示(DMI_BIGDECIMAL_CONSTRUCTED_FROM_DOUBLE)

此代码从双精度值创建一个BigDecimal,该值不能很好地转换为十进制数。例如,可以假设在Java中编写新的BigDecimal(0.1)会创建一个完全等于0.1的BigDecimal(非标尺值为1,比例为1),但实际上等于0.1000000000000000055511151231257827021181583404541015625。你可能想要使用BigDecimal.valueOf(double d)方法,它使用Double的String表示来创建BigDecimal(例如,BigDecimal.valueOf(0.1)给出0.1)。

DMI:hasNext方法调用next(DMI_CALLING_NEXT_FROM_HASNEXT)

hasNext()方法调用next()方法。这几乎肯定是错误的,因为hasNext()方法不应该改变迭代器的状态,而下一个方法应该改变迭代器的状态。

DMI:集合不应包含自己(DMI_COLLECTIONS_SHOULD_NOT_CONTAIN_THEMSELVES)

对一个集合的方法的这个调用只有在一个集合包含它的时候才会有意义(例如,如果s.contains(s)是真的)。这不太可能是真实的,如果它是真的(如计算哈希码导致无限递归),会导致问题。有可能错误的值作为参数传递。

DMI:喔!一个无意义的方法调用(DMI_DOH)

这种局部方法的调用没有任何意义,因为从检查中应该是明显的。

DMI:在数组上调用hashCode(DMI_INVOKING_HASHCODE_ON_ARRAY)

代码在数组上调用hashCode。在数组上调用hashCode返回与System.identityHashCode相同的值,并且会隐藏数组的内容和长度。如果需要一个取决于数组的内容的hashCode a,请使用java.util.Arrays.hashCode(a)。

DMI:在int上调用Double.longBitsToDouble(DMI_LONG_BITS_TO_DOUBLE_INVOKED_ON_INT)

Double.longBitsToDouble方法被调用,但32位int值作为参数传递。这绝对不是意图,也不太可能给出预期的结果。

DMI:对集合进行空虚调用(DMI_VACUOUS_SELF_COLLECTION_CALL)

这个电话没有意义。对于任何集合c,调用c.containsAll(c)应始终为真,并且c.retainAll(c)不应有效果。

Dm:无法使用反射来检查没有运行时保留的注释的存在(DMI_ANNOTATION_IS_NOT_VISIBLE_TO_REFLECTION)

除非注释本身已经使用@Retention(RetentionPolicy.RUNTIME)进行注释,否则不能使用反射来观察注释(例如,通过使用isAnnotationPresent方法)。。

Dm:尝试更改ScheduledThreadPoolExecutor的最大池大小(DMI_FUTILE_ATTEMPT_TO_CHANGE_MAXPOOL_SIZE_OF_SCHEDULED_THREAD_POOL_EXECUTOR)

(Javadoc)虽然ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,但其中一些继承的调优方法对此没有帮助。特别是,由于它使用corePoolSize线程和无界队列作为固定大小的池,对最大PoolSize的调整没有任何有用的效果。

Dm:创建具有零核心线程的ScheduledThreadPoolExecutor(DMI_SCHEDULED_THREAD_POOL_EXECUTOR_WITH_ZERO_CORE_THREADS)

(Javadoc)具有零内核线程的ScheduledThreadPoolExecutor将永远不会执行任何操作; 对最大池大小的更改将被忽略。

Dm:对EasyMock方法无用/空虚调用(DMI_VACUOUS_CALL_TO_EASYMOCK_METHOD)

此调用不会将任何对象传递给EasyMock方法,因此调用不执行任何操作。

Dm:Math.max和Math.min(DM_INVALID_MIN_MAX)的组合不正确

此代码尝试使用Math.min(0,Math.max(100,value))之类的构造来限制值边界。但常数的顺序是不正确的:它应该是Math.min(100,Math.max(0,value))。因此,此代码总是产生相同的结果(如果值为NaN,则为NaN)。

EC:equals()用于比较数组和非数组(EC_ARRAY_AND_NONARRAY)

该方法调用.equals(Object o)来比较数组和一个似乎不是数组的引用。如果被比较的东西是不同的类型,那么它们被保证是不平等的,并且比较几乎肯定是一个错误。即使它们都是数组,数组上的equals方法只能确定两个数组是相同的对象。要比较数组的内容,请使用java.util.Arrays.equals(Object [],Object [])。

EC:在数组上调用equals(),相当于==(EC_BAD_ARRAY_COMPARE)

该方法调用数组上的.equals(Object o)方法。由于数组不覆盖Object的equals方法,所以调用数组上的equals与比较它们的地址是一样的。要比较数组的内容,请使用java.util.Arrays.equals(Object[], Object[])。为了比较数组的地址,使用这个方法来明确地检查指针的相等性就不那么困惑了==。

EC:equals(…)用于比较不兼容的数组(EC_INCOMPATIBLE_ARRAY_COMPARE)

该方法调用.equals(Object o)来比较两个数组,但不兼容类型的数组(例如String []和StringBuffer []或String []和int [])。他们永远不会平等。另外,当equals(…)用于比较数组时,它只检查它们是否是相同的数组,并忽略数组的内容。

EC:调用equals(null)(EC_NULL_ARG)

该方法调用equals(Object),传递一个空值作为参数。根据equals()方法的合同,此调用应始终返回false。

EC:调用equals()比较不相关的类和接口(EC_UNRELATED_CLASS_AND_INTERFACE)

这个方法在两个引用上调用equals(Object),其中一个是一个类,另一个是接口,其中类和它的任何非抽象子类都不实现接口。因此,正在比较的对象在运行时不太可能是同一类的成员(除非某些应用程序类未被分析,或者动态类加载可能在运行时发生)。根据equals()的合同,不同类的对象总是应该不相等; 因此,根据java.lang.Object.equals(Object)定义的合同,此比较的结果在运行时始终为false。

EC:调用equals()比较不同的接口类型(EC_UNRELATED_INTERFACES)

该方法在两个不相关的接口类型的引用上调用equals(Object),其中两个都不是另一个的子类型,并且没有已知的非抽象类实现两个接口。因此,正在比较的对象在运行时不太可能是同一类的成员(除非某些应用程序类未被分析,或者动态类加载可能在运行时发生)。根据equals()的合同,不同类的对象总是应该不相等; 因此,根据java.lang.Object.equals(Object)定义的合同,此比较的结果在运行时始终为false。

EC:调用equals()比较不同类型(EC_UNRELATED_TYPES)

这个方法在两个类型的引用上调用了equals(Object),分析表明它们将在运行时处于不同类的对象。此外,对被调用的equals方法的检查表明这个调用总是返回false,否则equals方法不是对称的(这是类Object中的equals的合同所需的属性)。

EC:使用指针相等来比较不同类型(EC_UNRELATED_TYPES_USING_POINTER_EQUALITY)

该方法使用指针相等来比较两个似乎是不同类型的引用。这个比较的结果在运行时总是假的。

Eq:equals方法总是返回false(EQ_ALWAYS_FALSE)

这个类定义一个总是返回false的equals方法。这意味着一个对象不等于它自己,并且不可能创建这个类的有用的地图或集合。更基本的是,这意味着平等不是反身,而是等价法的要求之一。

可能的意图语义是对象标识:一个对象等于它自己。这是从类继承的行为Object。如果需要覆盖从不同的超类继承的equals,可以使用:

public boolean equals(Object o){return this == o; }

Eq:equals方法总是返回true(EQ_ALWAYS_TRUE)

这个类定义一个总是返回true的equals方法。这是有想象力的,但不是很聪明。此外,这意味着equals方法不对称。

Eq:equals方法比较类名而不是类对象(EQ_COMPARING_CLASS_NAMES)

此方法通过检查其类的名称是否相等来检查两个对象是否是同一个类。如果由不同的类加载器加载,则可以使用具有相同名称的不同类。只需检查类对象是否相同。

方程:为枚举定义的协方差equals()方法(EQ_DONT_DEFINE_EQUALS_FOR_ENUM)

这个类定义一个枚举,枚举的等式使用对象标识来定义。定义枚举值的协方差方法是非常糟糕的做法,因为它可能导致使用协变量枚举方法比较两个不同的枚举值,并且在正常比较时不等于。不要这样做

Eq:equals()方法定义为不覆盖equals(Object)(EQ_OTHER_NO_OBJECT)

这个类定义一个equals() 方法,不会覆盖equals(Object)基java.lang.Object类中定义的常规方法。相反,它继承了一个超类的equals(Object)方法。该类应该可以定义一个boolean equals(Object)方法。

Eq:equals()方法定义不覆盖Object.equals(Object)(EQ_OTHER_USE_OBJECT)

这个类定义一个equals() 方法,不会覆盖equals(Object)基java.lang.Object类中定义的常规方法。该类应该可以定义一个boolean equals(Object)方法。

Eq:equals方法覆盖在超类中等于可能不对称(EQ_OVERRIDING_EQUALS_NOT_SYMMETRIC)

此类定义了覆盖超类中的equals方法的equals方法。两者都是方法方法用于instanceof确定两个对象是否相等。这是充满危险的,因为重要的是equals方法是对称的(换句话说a.equals(b) == b.equals(a))。如果B是A的子类型,并且A的equals方法检查参数是A的实例,并且B的equals方法检查参数是B的实例,则很可能由这些方法定义的等价关系不对称。

方程:协变量equals()方法定义,Object.equals(Object)继承(EQ_SELF_USE_OBJECT)

该类定义了该equals() 方法的协变版本,但继承equals(Object)了基java.lang.Object类中定义的常规方法。该类应该可以定义一个boolean equals(Object)方法。

FE:对NaN进行平等测试(FE_TEST_IF_EQUAL_TO_NOT_A_NUMBER)

此代码检查浮点值是否等于特殊的非A数值(例如,if (x == Double.NaN))。但是,由于具有特殊的语义NaN,没有价值等于Nan包括NaN。因此, x == Double.NaN总是评估为false。要检查包含的值x 是否为特殊的非数字值,请使用 Double.isNaN(x)(或Float.isNaN(x)如果 x是浮点精度)。

FS:格式化字符串占位符与传递的参数不兼容(VA_FORMAT_STRING_BAD_ARGUMENT)

格式字符串占位符与相应的参数不兼容。例如, System.out.println(“%d\n”, “hello”);

%d占位符需要一个数字参数,但是会传递字符串值。执行此语句时将发生运行时异常。

FS:提供的参数的类型与格式说明符不匹配(VA_FORMAT_STRING_BAD_CONVERSION)

其中一个参数与相应的格式字符串说明符不兼容。因此,这将在执行时生成运行时异常。例如,String.format(“%d”, “1”)将生成异常,因为String“1”与格式说明符%d不兼容。

FS:MessageFormat提供了预期的printf样式格式(VA_FORMAT_STRING_EXPECTED_MESSAGE_FORMAT_SUPPLIED)

调用一种方法,它期望Java printf格式的字符串和参数列表。但是,格式字符串不包含任何格式说明符(例如,%s),但包含消息格式元素(例如{0})。当需要printf风格的格式字符串时,代码很可能会提供MessageFormat字符串。在运行时,所有的参数将被忽略,格式字符串将按照提供的方式完全返回,而不需要任何格式化。

FS:比格式字符串中实际使用的参数更多(VA_FORMAT_STRING_EXTRA_ARGUMENTS_PASSED)

调用具有可变数量参数的格式字符串方法,但是传递的参数比格式字符串实际使用的参数多。这不会导致运行时异常,但代码可能会默认省略打算包含在格式化字符串中的信息。

FS:非法格式字符串(VA_FORMAT_STRING_ILLEGAL)

格式字符串在语法上无效,并且执行此语句时将发生运行时异常。

FS:格式字符串引用缺少参数(VA_FORMAT_STRING_MISSING_ARGUMENT)

没有足够的参数传递以满足格式字符串中的占位符。执行此语句时将发生运行时异常。

FS:格式字符串以前没有参数(VA_FORMAT_STRING_NO_PREVIOUS_ARGUMENT)

格式字符串指定一个相对索引,以请求重新使用先前格式说明符的参数。但是,以前没有论据。例如,

formatter.format(“%

}

进口beta.Foo;

公共类B扩展A {

public int f(Foo x){return 42; }

}

在f(Foo)类定义的方法B不会覆盖 f(Foo)在类中定义的方法A,因为参数类型Foo的不同包。

QBA:方法以布尔表达式(QBA_QUESTIONABLE_BOOLEAN_ASSIGNMENT)分配布尔文本

此方法为if或while表达式中的布尔变量分配一个文字布尔值(true或false)。很可能这应该是使用==的布尔比较,而不是使用=的赋值。

RANGE:数组索引超出范围(RANGE_ARRAY_INDEX)

执行数组操作,但是数组索引超出范围,这将在运行时导致ArrayIndexOutOfBoundsException。

RANGE:数组长度超出范围(RANGE_ARRAY_LENGTH)

方法使用array参数和length参数调用,但长度超出范围。这将导致运行时的IndexOutOfBoundsException。

RANGE:数组偏移超出范围(RANGE_ARRAY_OFFSET)

方法使用数组参数和偏移参数调用,但偏移量超出范围。这将导致运行时的IndexOutOfBoundsException。

RANGE:字符串索引超出范围(RANGE_STRING_INDEX)

String方法被调用,指定的字符串索引是超出范围的。这将在运行时导致StringIndexOutOfBoundsException。

RC:可疑参考比较(RC_REF_COMPARISON)

该方法使用==或!=运算符比较两个参考值,其中正确的方式来比较此类型的实例通常为equals()方法。可以创建不相同但不与==比较的不同实例,因为它们是不同的对象。通常不能通过引用比较的类的示例是java.lang.Integer,java.lang.Float等

RCN:以前取消引用的值的空值(RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE)

此处检查一个值以查看它是否为空,但是此值不能为null,因为它先前已被取消引用,并且如果该值为null,则在早期的引用引用时将会发生空指针异常。本质上,该代码和以前的取消引用不同意这个值是否被允许为null。检查是多余的,或者以前的引用是错误的。

RE:正则表达式的语法无效(RE_BAD_SYNTAX_FOR_REGULAR_EXPRESSION)

这里的代码使用根据正则表达式的语法无效的正则表达式。这个语句在执行时会抛出一个PatternSyntaxException。

RE:用于正则表达式的File.separator(RE_CANT_USE_FILE_SEPARATOR_AS_REGULAR_EXPRESSION)

这里的代码使用File.separator 正则表达式所需的位置。这将在Windows平台上失败,这File.separator是一个反斜杠,它以正则表达式解释为转义字符。其他的选择,你可以只是使用 File.separatorChar==’\’ ? “\\” : File.separator而不是 File.separator

回覆: ”。” 或“|” 用于正则表达式(RE_POSSIBLE_UNINTENDED_PATTERN)

正在调用String函数,“。” 或“|” 被传递给一个参数,它将一个正则表达式作为一个参数。这是你的意图吗?例如

s.replaceAll(“。”,“/”)将返回一个字符串,其中每个字符已被“/”字符替换

s.split(“。”)总是返回一个零长度的String数组

“ab | cd”.replaceAll(“|”,“/”)将返回“/ a / b / | / c / d /”

“ab | cd”.split(“|”)将返回六个(!)元素的数组:[,a,b,|,c,d]

RV:从0到1的随机值被强制为整数0(RV_01_TO_INT)

从0到1的随机值被强制为整数值0.您可能希望在将其强制转换为整数之前,以其他方式将其随机值加倍,或使用该Random.nextInt(n)方法。

RV:尝试计算带符号的32位哈希码的绝对值(RV_ABSOLUTE_VALUE_OF_HASHCODE)

此代码生成一个哈希码,然后计算该哈希码的绝对值。如果哈希码是Integer.MIN_VALUE,则结果也将为负(因为 Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE)。

2 ^ 32个字符串中的一个字符串具有Integer.MIN_VALUE的hashCode,包括“多重创建者”“GydZG_”和“设计工作室”。

RV:尝试计算带符号随机整数的绝对值(RV_ABSOLUTE_VALUE_OF_RANDOM_INT)

该代码生成随机符号整数,然后计算该随机整数的绝对值。如果随机数发生器返回的数字是Integer.MIN_VALUE,则结果也将为负(因为 Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE)。(同样的问题也是长期价值的)。

RV:代码检查compareTo返回的特定值(RV_CHECK_COMPARETO_FOR_SPECIFIC_RETURN_VALUE)

此代码调用了compareTo或compare方法,并检查返回值是否为特定值,例如1或-1。调用这些方法时,应该只检查结果的符号,而不是任何特定的非零值。虽然许多或大多数compareTo和比较方法只返回-1,0或1,但有些返回其他值。

RV:异常创建并丢弃而不是抛出(RV_EXCEPTION_NOT_THROWN)

此代码创建一个异常(或错误)对象,但不做任何事情。例如,像

如果(x <0)

新的IllegalArgumentException(“x必须是非负数”);

这可能是程序员抛出创建异常的意图:

如果(x <0)

抛出新的IllegalArgumentException(“x必须是非负的”);

RV:方法忽略返回值(RV_RETURN_VALUE_IGNORED)

应检查此方法的返回值。这个警告的一个常见原因是调用不可变对象上的方法,认为它更新对象。例如,在下面的代码片段中,

String dateString = getHeaderField(name);

dateString.trim();

程序员似乎认为trim()方法会更新由dateString引用的String。但是由于Strings是不可变的,所以trim()函数返回一个新的String值,这在这里被忽略。代码应更正为:

String dateString = getHeaderField(name);

dateString = dateString.trim();

RpC:重复条件测试(RpC_REPEATED_CONDITIONAL_TEST)

该代码包含条件测试两次执行,一个紧随其后(例如x == 0 || x == 0)执行。也许第二次发生是为了别的东西(例如,x == 0 || y == 0)。

SA:字段的自分配(SA_FIELD_SELF_ASSIGNMENT)

该方法包含一个字段的自我分配; 例如

int x;

public void foo(){

x = x;

}

这样的分配是无用的,可能表示逻辑错误或打字错误。

SA:自身与自己的比较(SA_FIELD_SELF_COMPARISON)

该方法将一个字段与其自身进行比较,并可能表示错字或逻辑错误。确保你正在比较正确的事情。

SA:涉及字段的无意识自我计算(例如,x&x)(SA_FIELD_SELF_COMPUTATION)

该方法对具有相同字段(例如,x和x或xx)的另一个引用的字段进行无意义的计算。由于计算的本质,此操作似乎没有任何意义,可能会显示错字或逻辑错误。仔细检查计算。

SA:自分配本地而不是分配到字段(SA_LOCAL_SELF_ASSIGNMENT_INSTEAD_OF_FIELD)

该方法包含一个局部变量的自我分配,并且有一个名称相同的字段。作业似乎是 例如

int foo

public void setFoo(int foo){

foo = foo;

}

作业没用。你是否意味着转让给该领域?

SA:自身与价值的比较(SA_LOCAL_SELF_COMPARISON)

该方法将局部变量与自身进行比较,并可能表示错字或逻辑错误。确保你正在比较正确的事情。

SA:涉及变量(例如x&x)的无意识的自我计算(SA_LOCAL_SELF_COMPUTATION)

该方法对另一个引用相同变量(例如x和x或xx)的局部变量执行无意义的计算。由于计算的本质,此操作似乎没有任何意义,可能会显示错字或逻辑错误。仔细检查计算。

SF:由于switch语句掉落死区(SF_DEAD_STORE_DUE_TO_SWITCH_FALLTHROUGH)

由于交换机掉落,存储在先前交换机案例中的值将被覆盖。在以前的情况下,你很可能忘了休息或回来。

SF:由于switch语句的死存储掉落到(SF_DEAD_STORE_DUE_TO_SWITCH_FALLTHROUGH_TO_THROW)

由于交换机掉落到抛出异常的地方,存储在先前交换机案例中的值将被忽略。在以前的情况下,你很可能忘了休息或回来。

SIC:非静态内部类和线程本地(SIC_THREADLOCAL_DEADLY_EMBRACE)的致命拥抱

这个类是一个内部类,但应该是一个静态的内部类。就这样,内部阶级和外部阶层当地的线程之间是一个致命的拥抱的严重危险。因为内部类不是静态的,它保留对外部类的引用。如果线程本地包含对内部类的实例的引用,则内部和外部实例都将可访问,并且不符合垃圾回收的资格。

SIO:使用instanceof运算符完成不必要的类型检查(SIO_SUPERFLUOUS_INSTANCEOF)

使用instanceof运算符执行类型检查,可以静态确定对象是否为请求类型。

SQL:方法尝试使用索引0访问准备好的语句参数(SQL_BAD_PREPARED_STATEMENT_ACCESS)

对参数索引为0的准备语句的setXXX方法进行调用。由于参数索引从索引1开始,因此总是出错。

SQL:方法尝试访问索引为0的结果集字段(SQL_BAD_RESULTSET_ACCESS)

调用结果集的getXXX或updateXXX方法,其中字段索引为0.由于ResultSet字段从索引1开始,因此总是出错。

STI:不需要使用currentThread()调用,调用interrupt()(STI_INTERRUPTED_ON_CURRENTTHREAD)

此方法调用Thread.currentThread()调用,只是调用interrup()方法。as blocked()是一个静态方法,使用Thread.interrupted()更简单明了。

STI:线程实例调用静态Thread.interrupted()方法(STI_INTERRUPTED_ON_UNKNOWNTHREAD)

该方法调用线程对象上的Thread.interrupted()方法,该对象似乎是不是当前线程的Thread对象。由于blocked()方法是静态的,所以中断的方法将被调用在与作者所期望的不同的对象上。

Se:方法必须是私有的才能使序列化工作(SE_METHOD_MUST_BE_PRIVATE)

该类实现了Serializable接口,并定义了一种自定义序列化/反序列化方法。但由于该方法未声明为私有,因此序列化/反序列化API将被忽略。

Se:readResolve方法不能被声明为静态方法。(SE_READ_RESOLVE_IS_STATIC)

为了使readResolve方法被序列化机制识别,它不能被声明为静态方法。

TQ:标注为携带一个类型限定符的值,用于不需要携带该限定符的值(TQ_ALWAYS_VALUE_USED_WHERE_NEVER_REQUIRED)

指定为携带类型限定符注释的值在需要该值不携带该注释的位置或位置中消耗。

更准确地说,使用类型限定符注释的值指定when = ALWAYS被保证达到使用或使用相同类型限定符指定何时= NEVER的位置。

例如,说@NonNegative是类型限定符注释@Negative(when = When.NEVER)的昵称。以下代码将生成此警告,因为return语句需要一个@NonNegative值,但会收到一个标记为@Negative的值。

public @NonNegative整数示例(@Negative Integer value){

返回值;

}

TQ:将值与不兼容的类型限定符进行比较(TQ_COMPARING_VALUES_WITH_INCOMPATIBLE_TYPE_QUALIFIERS)

将指定为携带类型限定符注释的值与不具有该限定符的值进行比较。

更确切地说,用类型限定符注释的值指定when = ALWAYS与同一类型限定符指定when = NEVER的值进行比较。

例如,说@NonNegative是类型限定符注释@Negative(when = When.NEVER)的昵称。以下代码将生成此警告,因为return语句需要一个@NonNegative值,但会收到一个标记为@Negative的值。

public boolean example(@Negative Integer value1,@NonNegative Integer value2){

返回值1.equals(value2);

}

TQ:可能不会携带类型限定符的值总是以某种方式使用,需要该类型限定符(TQ_MAYBE_SOURCE_VALUE_REACHES_ALWAYS_SINK)

被注释为可能性的值不是由类型限定符表示的值的实例,并且该值被保证以需要由该类型限定符表示的值的方式使用。

TQ:可能携带类型限定符的值总是以某种方式禁止它使用该类型限定符(TQ_MAYBE_SOURCE_VALUE_REACHES_NEVER_SINK)

注释为可能性的值是由类型限定符表示的值的实例,并且该值被保证以禁止该类型限定符表示的值的方式使用。

TQ:注释为不带有类型限定符的值,用于需要携带该限定词的值(TQ_NEVER_VALUE_USED_WHERE_ALWAYS_REQUIRED)

指定为不携带类型限定符注释的值将被保证在要求该值确实携带该注释的位置或位置中使用。

更确切地说,使用指定when = NEVER的类型限定符注释的值将被保证达到使用或使用相同类型限定符指定when = ALWAYS的位置。

TODO:例子

TQ:没有类型限定符的值用于需要具有该限定词的值(TQ_UNKNOWN_VALUE_USED_WHERE_ALWAYS_STRICTLY_REQUIRED)

正在以一种需要使用类型限定符注释该值的方式使用值。类型限定符是严格的,因此该工具拒绝任何没有适当注释的值。

要强制一个值以进行严格注释,请定义一个身份函数,其中返回值使用strict注释进行注释。这是将非注释值转换为具有严格类型限定符注释的值的唯一方法。

UMAC:匿名类中定义的不可调用方法(UMAC_UNCALLABLE_METHOD_OF_ANONYMOUS_CLASS)

这个匿名类定义了一个不直接调用的方法,并且不覆盖超类中的方法。由于其他类中的方法不能直接调用在匿名类中声明的方法,所以似乎这种方法是不可接受的。该方法可能只是死代码,但也可能该方法旨在覆盖超类中声明的方法,并且由于打字错误或其他错误,该方法实际上不会覆盖其打算的方法。

UR:构造函数(UR_UNINIT_READ)中未初始化的字段读取

此构造函数读取尚未分配值的字段。这通常是由程序员错误地使用该字段而不是构造函数的参数之一引起的。

UR:从超类的构造函数(UR_UNINIT_READ_CALLED_FROM_SUPER_CONSTRUCTOR)调用的字段方法的未初始化读取

该方法在超类的构造函数中被调用。此时,类的字段尚未初始化。

为了使这个更具体,考虑以下类:

抽象类A {

int hashCode;

abstract Object getValue();

一个() {

hashCode = getValue()。hashCode();

}

}

B级延伸A {

对象值;

B(Object v){

this.value = v;

}

Object getValue(){

返回值;

}

}

当一个B被构造,对于构造A类被调用 之前的构造B集value。因此,当用于A调用getValue的构造函数时,读取未初始化的值value

USELESS_STRING:在未命名的数组上调用toString(DMI_INVOKING_TOSTRING_ON_ANONYMOUS_ARRAY)

代码在(匿名)数组上调用toString。在数组上调用toString会产生一个相当无用的结果,如[C @ 16f0472]。考虑使用Arrays.toString将数组转换为可读的String,该字符串给出了数组的内容。参见编程益智游戏,第3章,拼图12。

USELESS_STRING:对数组调用toString(DMI_INVOKING_TOSTRING_ON_ARRAY)

代码在数组中调用toString,这将产生一个相当无用的结果,如[C @ 16f0472]。考虑使用Arrays.toString将数组转换为可读的String,该字符串给出了数组的内容。参见编程益智游戏,第3章,拼图12。

USELESS_STRING:使用格式字符串以无用的方式格式化的数组(VA_FORMAT_STRING_BAD_CONVERSION_FROM_ARRAY)

使用格式字符串格式化的参数之一是数组。这将使用相当无用的格式进行格式化,例如[I @ 304282,其实际上不显示数组的内容。考虑在将数组Arrays.asList(…)处理为格式化之前,使用数组。

UwF:字段只有设置为null(UWF_NULL_FIELD)

对此字段的所有写入都为常量值为null,因此字段的所有读取将返回null。检查错误,或删除它,如果它是无用的。

UwF:未写字段(UWF_UNWRITTEN_FIELD)

该字段永远不会写入。它的所有读取将返回默认值。检查错误(应该已经被初始化了吗?),或者如果没有用的话,删除它。

VA:将原始数组传递给函数,期望可变数目的对象参数(VA_PRIMITIVE_ARRAY_PASSED_TO_OBJECT_VARARG)

该代码将原始数组传递给一个可变数目的对象参数的函数。这将创建一个长度为1的数组来保存原始数组并将其传递给函数。

LG:由于OpenJDK中的弱参考,潜在的记录器变化(LG_LOST_LOGGER_DUE_TO_WEAK_REFERENCE)

OpenJDK引入了潜在的不兼容性。特别地,java.util.logging.Logger行为已更改。而不是使用强引用,它现在在内部使用弱引用。这是一个合理的改变,但不幸的是,一些代码依赖于旧的行为 - 当更改logger配置时,它只是删除logger引用。这意味着垃圾收集器可以自由地回收该内存,这意味着记录器配置丢失。例如,考虑:

public static void initLogging()throws Exception {

Logger logger = Logger.getLogger(“edu.umd.cs”);

logger.addHandler(new FileHandler()); //调用更改记录器配置

logger.setUseParentHandlers(假); //另一个调用更改记录器配置

}

记录器引用在方法结束时丢失(它不会转义该方法),因此如果在调用initLogging之后有一个垃圾回收循环,则记录器配置将丢失(因为Logger仅保留弱引用)。

public static void main(String [] args)throws Exception {

initLogging(); //向记录器添加文件处理程序

的System.gc(); //记录器配置丢失

Logger.getLogger(“edu.umd.cs”)。info(“Some message”); //这没有按预期方式记录到文件中

}

Ulf Ochsenfahrt和Eric Fellheimer

OBL:方法可能无法清理流或资源(OBL_UNSATISFIED_OBLIGATION)

此方法可能无法清除(关闭,处理)流,数据库对象或需要显式清除操作的其他资源。

通常,如果方法打开流或其他资源,则该方法应使用try / finally块来确保流或资源在方法返回之前被清除。

这个错误模式基本上与OS_OPEN_STREAM和ODR_OPEN_DATABASE_RESOURCE错误模式相同,但是基于不同的(希望更好的)静态分析技术。我们有兴趣得到关于这种错误模式的有用性的反馈。要发送反馈:

发送电子邮件到[email protected]

提交错误报告:http : //findbugs.sourceforge.net/reportingBugs.html

特别是,这种错误模式的假阳性抑制启发式未被广泛调整,因此关于假阳性的报告对我们有帮助。

有关分析技术的描述,请参阅Weimer和Necula,查找和预防运行时错误处理错误。

OBL:方法可能无法清除已检查异常的流或资源(OBL_UNSATISFIED_OBLIGATION_EXCEPTION_EDGE)

此方法可能无法清除(关闭,处理)流,数据库对象或需要显式清除操作的其他资源。

通常,如果方法打开流或其他资源,则该方法应使用try / finally块来确保流或资源在方法返回之前被清除。

这个错误模式基本上与OS_OPEN_STREAM和ODR_OPEN_DATABASE_RESOURCE错误模式相同,但是基于不同的(希望更好的)静态分析技术。我们有兴趣得到关于这种错误模式的有用性的反馈。要发送反馈:

发送电子邮件到[email protected]

提交错误报告:http : //findbugs.sourceforge.net/reportingBugs.html

特别是,这种错误模式的假阳性抑制启发式未被广泛调整,因此关于假阳性的报告对我们有帮助。

有关分析技术的描述,请参阅Weimer和Necula,查找和预防运行时错误处理错误。

Dm:考虑使用调用方法(DM_CONVERT_CASE)的Locale参数化版本

使用平台的默认编码将字符串转换为大写或小写。当与国际字符一起使用时,可能会导致转换不当。使用

String.toUpperCase(Locale l)

String.toLowerCase(Locale l)

版本。

Dm:依赖于默认编码(DM_DEFAULT_ENCODING)

发现一个方法的调用将执行一个字节到String(或字符串到字节)的转换,并假设默认的平台编码是合适的。这将导致应用程序行为在平台之间变化。使用替代API并明确指定字符集名称或Charset对象。

DP:只能在doPrivileged块内创建类加载器(DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED)

此代码创建一个类加载器,如果安装了安全管理,则需要该权限。如果此代码可能由不具有安全权限的代码调用,则需要在doPrivileged块中进行类加载器创建。

DP:只应在doPrivileged块中调用的方法(DP_DO_INSIDE_DO_PRIVILEGED)

此代码调用需要安全权限检查的方法。如果此代码将被授予安全权限,但可能由不具有安全权限的代码调用,则调用需要在doPrivileged块中进行。

EI:可以通过返回对可变对象(EI_EXPOSE_REP)的引用来暴露内部表示

返回对存储在其中一个对象的字段中的可变对象值的引用,会公开对象的内部表示。如果实例由不受信任的代码访问,并且对可变对象的未检查更改将危及安全性或其他重要属性,则需要执行其他操作。在许多情况下,返回对象的新副本是更好的方法。

EI2:通过引用可变对象(EI_EXPOSE_REP2)可能会暴露内部表示

此代码将对外部可变对象的引用存储到对象的内部表示中。如果实例由不受信任的代码访问,并且对可变对象的未检查更改将危及安全性或其他重要属性,则需要执行其他操作。存储对象的副本在许多情况下是更好的方法。

FI:Finalizer应该被保护,而不是public(FI_PUBLIC_SHOULD_BE_PROTECTED)

类的finalize()方法应该具有受保护的访问权限,而不是公共的。

MS:可以通过将可变对象存储到静态字段中来暴露内部静态(EI_EXPOSE_STATIC_REP2)

此代码将对外部可变对象的引用存储到静态字段中。如果对可变对象的未选中更改会影响安全性或其他重要属性,则需要执行其他操作。存储对象的副本在许多情况下是更好的方法。

MS:字段不是最终的,不能受到恶意代码的保护(MS_CANNOT_BE_FINAL)

可变静态字段可能会被恶意代码或意外地从另一个包中更改。不幸的是,使用该字段的方式不容易解决这个问题。

MS:公共静态方法可能会通过返回数组(MS_EXPOSE_REP)来暴露内部表示

public static方法返回对类的静态状态的一部分的数组的引用。任何调用此方法的代码都可以自由修改底层数组。一个修复是返回数组的副本。

MS:字段应为最终和封装保护(MS_FINAL_PKGPROTECT)

可变静态字段可能会被恶意代码或意外地从另一个包中更改。该领域可以被包保护和/或做出最终以避免这种漏洞。

MS:字段是可变数组(MS_MUTABLE_ARRAY)

最后的静态字段引用了一个数组,可以被恶意代码访问,也可能被其他程序包意外地访问。该代码可以自由修改数组的内容。

MS:字段是可变集合(MS_MUTABLE_COLLECTION)

可变集合实例被分配给最终的静态字段,因此可以由恶意代码或意外地从另一个包改变。考虑将此字段包装到Collections.unmodifiableSet / List / Map / etc中。以避免此漏洞。

MS:Field是一个可以被包保护的可变集合(MS_MUTABLE_COLLECTION_PKGPROTECT)

可变集合实例被分配给最终的静态字段,因此可以由恶意代码或意外地从另一个包改变。该字段可以被包保护以避免此漏洞。或者,您可以将此字段包装到Collections.unmodifiableSet / List / Map / etc中。以避免此漏洞。

MS:Field是一个可变的Hashtable(MS_MUTABLE_HASHTABLE)

最后一个静态字段引用了一个Hashtable,可以被恶意代码或其他程序包意外地访问。该代码可以自由修改Hashtable的内容。

MS:应将字段移出界面并使其受到保护(MS_OOI_PKGPROTECT)

在界面中定义的最终静态字段引用了可变对象,如数组或散列表。这个可变对象可能被恶意代码或意外地从另一个包改变。为了解决这个问题,需要将该字段移动到一个类并使其受保护,以避免此漏洞。

MS:字段应为包保护(MS_PKGPROTECT)

可变静态字段可能会被恶意代码或意外更改。该字段可以被包保护以避免此漏洞。

MS:字段不是最终的,但应该是(MS_SHOULD_BE_FINAL)

这个静态字段是public但不是final,并且可能被恶意代码或意外地从另一个包改变。该领域可以做到最后,以避免这个漏洞。

MS:字段不是最终的,但应该被重构为(MS_SHOULD_BE_REFACTORED_TO_BE_FINAL)

这个静态字段是public但不是final,并且可能被恶意代码或意外地从另一个包改变。该领域可以做到最后,以避免这个漏洞。但是,静态初始化器包含多个写入字段,因此这样做将需要一些重构。

AT:调用并发抽象的顺序可能不是原子(AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION)

此代码包含对并发抽象的一系列调用(如并发哈希映射)。这些调用不会原子执行。

DC:可以双重检查字段(DC_DOUBLECHECK)

此方法可能包含双重检查锁定的实例。根据Java内存模型的语义,这个成语是不正确的。有关更多信息,请参阅网页 http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html。

DC:可能暴露部分初始化对象(DC_PARTIALLY_CONSTRUCTED)

看起来这个方法使用延迟字段初始化与双重检查锁定。虽然该字段被正确地声明为易失性,但在字段分配后可能会更改对象的内部结构,因此另一个线程可能会看到部分初始化的对象。

要解决此问题,请考虑将对象存储到本地变量中,并将其保存到易失性字段,只有在完全构造之后。

DL:布尔同步(DL_SYNCHRONIZATION_ON_BOOLEAN)

代码在一个盒装的原始常量(如布尔值)上同步。

private static Boolean inited = Boolean.FALSE;

同步(inited){

if(!inited){

在里面();

inited = Boolean.TRUE;

}

}

由于通常只有两个布尔对象,所以该代码可能与其他不相关的代码在同一个对象上进行同步,导致无响应和可能的死锁

见CERT CON08-J。不要对可能被重复使用的对象进行同步以获取更多信息。

DL:盒装图元上的同步(DL_SYNCHRONIZATION_ON_BOXED_PRIMITIVE)

代码在一个盒装的原始常数(如整数)上同步。

private static Integer count = 0;

synchronized(count){

计数++;

}

由于Integer对象可以被缓存和共享,所以这个代码可以与其他不相关的代码在同一个对象上进行同步,导致无响应和可能的死锁

见CERT CON08-J。不要对可能被重复使用的对象进行同步以获取更多信息。

DL:内联字符串同步(DL_SYNCHRONIZATION_ON_SHARED_CONSTANT)

代码在interned String上同步。

private static String LOCK =“LOCK”;

同步(LOCK){…}

常量字符串被实体化并由JVM加载的所有其他类共享。因此,这可能是锁定其他代码也可能被锁定的东西。这可能会导致非常奇怪,难以诊断阻塞和死锁行为。见http://www.javalobby.org/java/forums/t96352.html和http://jira.codehaus.org/browse/JETTY-352。

见CERT CON08-J。不要对可能被重复使用的对象进行同步以获取更多信息。

DL:对盒装原始值进行同步(DL_SYNCHRONIZATION_ON_UNSHARED_BOXED_PRIMITIVE)

代码在一个明显不共享的盒装原语(如整数)上同步。

private static final整数fileLock = new整数(1);

synchronized(fileLock){

.. 做一点事 ..

}

在这段代码中,要重新声明fileLock会更好,

private static final Object ObjectLock = new Object();

现有的代码可能是可以的,但它是混乱的,未来的重构(例如IntelliJ中的“删除Boxing”重构)可能会使用整个JVM中共享的实体Integer对象来替代它,从而导致非常混乱的行为和潜在僵局。

Dm:Monitor上调用wait()(DM_MONITOR_WAIT_ON_CONDITION)

此方法调用wait()一个的 java.util.concurrent.locks.Condition对象。Condition应该使用界面await() 定义的方法之一来等待一个Condition。

Dm:使用默认的空运行方法(DM_USELESS_THREAD)创建一个线程,

该方法通过从Thread类派生或通过传递Runnable对象来创建一个线程,而不指定运行方法。那么,这个线程什么都不用浪费时间。

ESync:空同步块(ESync_EMPTY_SYNC)

代码包含一个空的同步块:

synchronized(){}

空的同步块比大多数人认可的更加微妙和难以正确使用,而空的同步块几乎不是比较少设计的解决方案更好的解决方案。

IS:不一致的同步(IS2_INCONSISTENT_SYNC)

这个类的字段在同步方面似乎被访问不一致。这个bug报告表明bug模式检测器判断

该类包含锁定和解锁访问的混合,

该类没有注释为javax.annotation.concurrent.NotThreadSafe,

至少一个锁定访问是由类自己的方法之一执行的

不同步的字段访问(读取和写入)的数量不超过所有访问的三分之一,写入的权重是读取的两倍

匹配此错误模式的一个典型的错误是忘记同步一个打算线程安全的类中的一个方法。

您可以选择标记为“未同步访问”的节点,以显示检测器认为未同步访问域的代码位置。

请注意,该检测器有各种不准​​确的来源; 例如,检测器不能静态地检测保持锁的所有情况。此外,即使检测器准确地区分锁定和解锁访问,所述代码仍然可能是正确的。

IS:不保护并发访问的字段(IS_FIELD_NOT_GUARDED)

该字段使用net.jcip.annotations.GuardedBy或javax.annotation.concurrent.GuardedBy注释,但可以以似乎违反这些注释的方式进行访问。

JLM:在Lock(JLM_JSR166_LOCK_MONITORENTER)上执行的同步

此方法执行实现java.util.concurrent.locks.Lock的对象的同步。使用acquire()/ release()而不是使用构造来锁定/解锁这样的对象 synchronized (…)。

JLM:在util.concurrent实例上执行的同步(JLM_JSR166_UTILCONCURRENT_MONITORENTER)

此方法执行与java.util.concurrent包(或其子类)中的类的实例对象的同步。这些类的实例具有与Java关键字提供的同步正交的自己的并发控制机制synchronized。例如,同步在一个AtomicBoolean不会阻止其他线程修改 AtomicBoolean。

此类代码可能是正确的,但应仔细检查和记录,并可能会混淆以后维护代码的人。

JLM:在util.concurrent抽象(JML_JSR166_CALLING_WAIT_RATHER_THAN_AWAIT)上使用监视器样式等待方法

此方法调用 wait(), notify()或 notifyAll()() 一个对象,还提供了一个上 await(), signal(), signalAll()方法(如util.concurrent程序条件对象)。这可能不是你想要的,即使你想要它,你应该考虑改变你的设计,因为其他开发者会发现它特别混乱。

LI:静态字段的延迟初始化不正确(LI_LAZY_INIT_STATIC)

该方法包含非易失性静态字段的非同步延迟初始化。因为编译器或处理器可能会重新排序指令,所以线程不能保证看到完全初始化的对象, 如果该方法可以被多个线程调用。您可以使该字段为volatile来纠正问题。有关更多信息,请参阅 Java内存模型网站。

LI:不正确的懒惰初始化和更新的静态字段(LI_LAZY_INIT_UPDATE_STATIC)

该方法包含静态字段的不同步延迟初始化。设置该字段后,存储在该位置的对象将进一步更新或访问。其他线程一旦设置就可以看到该字段的设置。如果设置字段的方法中的进一步访问用于初始化对象,那么您有一个非常严重的多线程错误,除非有别的东西阻止任何其他线程在完全初始化之前访问存储的对象。

即使您确信该方法从不被多个线程调用,最好不要设置静态字段,直到您设置的值被完全填充/初始化为止。

ML:无效尝试保护该字段的字段上的同步(ML_SYNC_ON_FIELD_TO_GUARD_CHANGING_THAT_FIELD)

该方法在一个字段中同步,似乎是试图防止同时更新该字段。但是保护一个字段可以在引用的对象上锁定,而不是在该字段上。这可能不会提供您需要的互斥,而其他线程可能会在引用的对象上获取锁(用于其他目的)。这种模式的一个例子是:

private long myNtfSeqNbrCounter = new Long(0);

private Long getNotificationSequenceNumber(){

Long result = null;

synchronized(myNtfSeqNbrCounter){

result = new Long(myNtfSeqNbrCounter.longValue()+ 1);

myNtfSeqNbrCounter = new Long(result.longValue());

}

返回结果;

}

ML:方法在更新的字段上同步(ML_SYNC_ON_UPDATED_FIELD)

此方法可以对从可变字段引用的对象进行同步。这不太可能有有用的语义,因为不同的线程可能会在不同的对象上进行同步。

MSF:可变的servlet字段(MSF_MUTABLE_SERVLET_FIELD)

Web服务器通常只创建servlet或jsp类的一个实例(即将该类视为Singleton),并且将有多个线程调用该实例上的方法来为多个同时发送的请求提供服务。因此,拥有可变实例字段通常会创建竞争条件。

MWN:不匹配notify()(MWN_MISMATCHED_NOTIFY)

该方法调用Object.notify()或Object.notifyAll(),而不会明显地在对象上保持锁定。调用notify()或notifyAll()而不锁定将导致IllegalMonitorStateException被抛出。

MWN:不匹配wait()(MWN_MISMATCHED_WAIT)

该方法调用Object.wait(),而不会明显地保持对象的锁定。调用wait()而不锁定将导致IllegalMonitorStateException被抛出。

NN:裸体通知(NN_NAKED_NOTIFY)

没有任何(明显)伴随的修改对可变对象状态的调用notify()或被调用notifyAll()。一般来说,在监视器上调用notify方法是因为另一个线程正在等待的某些条件成为true。但是,为了使条件有意义,它必须涉及到两个线程都可见的堆对象。

这个错误并不一定表示错误,因为对可变对象状态的更改可能发生在一个方法中,然后调用包含通知的方法。

NP:在同一字段上进行同步和空检查。(NP_SYNC_AND_NULL_CHECK_FIELD)

由于该字段已同步,似乎不太可能为空。如果它为空,然后在NullPointerException上同步,则将抛出该检查,并且该检查将是无意义的。更好地在另一个字段上进行同步。

否:使用notify()而不是notifyAll()(NO_NOTIFY_NOT_NOTIFYALL)

这个方法调用notify()而不是notifyAll()。Java监视器通常用于多个条件。调用notify() 只唤醒一个线程,这意味着线程唤醒可能不是等待调用者满足的条件的线程。

RS:Class的readObject()方法同步(RS_READOBJECT_SYNC)

这个可序列化的类定义了readObject()哪个是同步的。根据定义,通过反序列化创建的对象只能由一个线程访问,因此不需要 readObject()同步。如果readObject() 方法本身导致对象变得对另一个线程可见,那就是非常可疑的编码风格的例子。

RV:putIfAbsent的返回值被忽略,传递给putIfAbsent的值被重用(RV_RETURN_VALUE_OF_PUTIFABSENT_IGNORED)

该putIfAbsent方法通常用于确保单个值与给定键相关联(如果不存在成功,则为第一个值)。如果您忽略返回值并保留对传入的值的引用,则可能会导致保留与映射关键字不相关的值的风险。如果您使用的是重要的,并且使用未存储在地图中的那个,则您的程序将表现不正确。

Ru:调用一个线程运行(你的意思是启动它吗?)(RU_INVOKE_RUN)

该方法显式地调用run()对象。通常,类实现Runnable接口,因为它们将run()在新线程中调用它们的方法,在这种情况下Thread.start()是正确的调用方法。

SC:构造函数调用Thread.start()(SC_START_IN_CTOR)

构造函数启动一个线程。如果类被扩展/子类化,这可能是错误的,因为线程将在子类构造函数启动之前启动。

SP:方法在字段上旋转(SP_SPIN_ON_FIELD)

该方法旋转读取一个字段的循环。编译器可以合法地提升读出的循环,将代码转换成无限循环。应该更改类,以便使用正确的同步(包括等待和通知调用)。

STCAL:调用静态日历(STCAL_INVOKE_ON_STATIC_CALENDAR_INSTANCE)

即使JavaDoc不包含关于它的提示,日历对于多层次的使用本质上是不安全的。检测器已经发现已经通过静态字段获得的日历实例的调用。这看起来很可疑

有关更多信息,请参阅Sun Bug#6231579 和Sun Bug#6178997。

STCAL:调用静态DateFormat(STCAL_INVOKE_ON_STATIC_DATE_FORMAT_INSTANCE)

正如JavaDoc所述,DateFormats对于多线程使用本质上是不安全的。检测器发现已经通过静态字段获取的DateFormat实例的调用。这看起来很可疑

有关更多信息,请参阅Sun Bug#6231579 和Sun Bug#6178997。

STCAL:静态日历字段(STCAL_STATIC_CALENDAR_INSTANCE)

即使JavaDoc不包含关于它的提示,日历对于多层次的使用本质上是不安全的。在线程边界之间共享单个实例而不进行适当的同步将导致应用程序的不规则行为。在1.4以下的问题似乎比Java 5更不频繁,您可能会在sun.util.calendar.BaseCalendar.getCalendarDateFromFixedDate()中看到随机ArrayIndexOutOfBoundsExceptions或IndexOutOfBoundsExceptions。

您可能还会遇到序列化问题。

建议使用实例字段。

有关更多信息,请参阅Sun Bug#6231579 和Sun Bug#6178997。

STCAL:Static DateFormat(STCAL_STATIC_SIMPLE_DATE_FORMAT_INSTANCE)

正如JavaDoc所述,DateFormats对于多线程使用本质上是不安全的。在线程边界之间共享单个实例而不进行适当的同步将导致应用程序的不规则行为。

您可能还会遇到序列化问题。

建议使用实例字段。

有关更多信息,请参阅Sun Bug#6231579 和Sun Bug#6178997。

SWL:方法调用带有锁的Thread.sleep()(SWL_SLEEP_WITH_LOCK_HELD)

此方法调用Thread.sleep()并保持锁定。这可能导致非常差的性能和可扩展性或死锁,因为其他线程可能正在等待获取锁定。在锁上调用wait()是一个更好的主意,它释放锁并允许其他线程运行。

TLW:等待两个锁(TLW_TWO_LOCK_WAIT)

在握住两个锁时等待显示器可能会导致死锁。执行等待只释放正在等待的对象上的锁,而不是任何其他锁。这不一定是一个bug,但值得仔细检查。

UG:非同步get方法,同步集方法(UG_SYNC_SET_UNSYNC_GET)

此类包含类似命名的get和set方法,其中set方法是同步的,get方法不是。这可能会在运行时导致不正确的行为,因为get方法的调用者不一定会看到对象的一致状态。get方法应该同步。

UL:方法不释放所有路径的锁定(UL_UNRELEASED_LOCK)

此方法获取一个JSR-166(java.util.concurrent)锁,但不会在方法之外的所有路径上释放它。一般来说,使用JSR-166锁的正确习语是:

锁l = ...;
l.lock();
尝试{
    // 做一点事
} finally {
    l.unlock();
}
           

UL:方法不释放所有异常路径上的锁定(UL_UNRELEASED_LOCK_EXCEPTION_PATH)

此方法获取JSR-166(java.util.concurrent)锁,但不会在方法之外的所有异常路径上释放它。一般来说,使用JSR-166锁的正确习语是:

锁l = ...;
l.lock();
尝试{
    // 做一点事
} finally {
    l.unlock();
}
           

UW:无条件等待(UW_UNCOND_WAIT)

该方法包含一个java.lang.Object.wait()不受条件控制流程保护的调用。代码应该验证其打算等待的条件在调用等待之前尚未满足; 任何先前的通知都将被忽略。

VO:对volatile字段的增量不是原子(VO_VOLATILE_INCREMENT)

该代码会增加一个volatile字段。挥发性场的增量不是原子的。如果多个线程同时增加字段,则增量可能会丢失。

VO:对数组的易失性引用不将数组元素视为volatile(VO_VOLATILE_REFERENCE_TO_ARRAY)

这声明了对数组的易失性引用,这可能不是你想要的。通过对数组的易失性引用,对数组的引用的读取和写入将被视为易失性,但是数组元素是非易失性的。要获取volatile数组元素,您将需要使用java.util.concurrent中的一个原子数组类(在Java 5.0中提供)。

WL:同步在getClass而不是类文字(WL_USING_GETCLASS_RATHER_THAN_CLASS_LITERAL)

此实例方法同步this.getClass()。如果这个类是子类,子类将在类对象上进行同步,这个子类是不可能的。例如,考虑java.awt.Label中的这个代码:

private static final String base =“label”;
 private static int nameCounter = 0;
 String constructComponentName(){
    synchronized(getClass()){
        返回base + nameCounter ++;
    }
 }
           

的子类Label不会对同一小类同步,便出现了争用。相反,这段代码应该是同步的Label.class

private static final String base =“label”;
 private static int nameCounter = 0;
 String constructComponentName(){
    synchronized(Label.class){
        返回base + nameCounter ++;
    }
 }
           

由Jason Mehrens贡献的Bug模式

WS:Class的writeObject()方法是同步的,但没有别的(WS_WRITEOBJECT_SYNC)

这个类有一个writeObject()同步的方法; 然而,类的其他方法没有同步。

Wa:Condition.await()不在循环(WA_AWAIT_NOT_IN_LOOP)

此方法包含一个java.util.concurrent.await() 不在循环中的调用(或变体)。如果对象用于多个条件,则呼叫者打算等待的条件可能不是实际发生的情况。

Wa:等待不在循环(WA_NOT_IN_LOOP)

此方法包含一个java.lang.Object.wait() 不在循环中的调用。如果监视器用于多个条件,则呼叫者打算等待的条件可能不是实际发生的情况。

Bx:原始值被盒装,然后立即取消装箱(BX_BOXING_IMMEDIATELY_UNBOXED)

一个原始物被装箱,然后立即取消装箱。这可能是由于需要手动装箱的地方,因此强制编译器立即撤销拳击的工作。

Bx:原始值被打包,然后取消装箱以执行原始强制(BX_BOXING_IMMEDIATELY_UNBOXED_TO_PERFORM_COERCION)

一个原始的盒装值被构造,然后立即转换成不同的基元类型(例如,new Double(d).intValue())。只需执行直接的原始胁迫(例如,(int) d)。

Bx:原始值被取消装箱并被胁迫用于三元运算符(BX_UNBOXED_AND_COERCED_FOR_TERNARY_OPERATOR)

包装的原始值被取消装箱,并作为条件三元运算符( b ? e1 : e2运算符)的评估的一部分转换为另一个原始类型。爪哇任务的语义,如果e1和e2被包裹的数字值,该值是装箱和转换/强制转换成它们的共同类型(例如,如果e1是类型的Integer 和e2是类型的Float,则e1是装箱,转换成浮点值,并且盒装见JLS第15.25节。

Bx:装箱值取消装箱,然后立即重新装箱(BX_UNBOXING_IMMEDIATELY_REBOXED)

盒装值被取消装箱,然后立即重新装箱。

Bx:拳击原始比较(DM_BOXED_PRIMITIVE_FOR_COMPARE)

创建一个boxed原语只是为了调用compareTo方法。使用静态比较方法(对于双重和浮动,因为Java 1.4,对于Java 1.7以外的其他原始类型),它直接适用于基元更有效。

Bx:打包/取消装箱以解析原语(DM_BOXED_PRIMITIVE_FOR_PARSING)

一个盒子的原语是从一个String创建的,只是为了提取未装箱的原始值。调用静态parseXXX方法更有效。

Bx:方法分配一个盒子的原语只是调用toString(DM_BOXED_PRIMITIVE_TOSTRING)

一个盒装的原语被分配来调用toString()。使用静态形式的toString更接近于原始值是更有效的。所以,

更换… 有了这个…

new Integer(1).toString() Integer.toString(1)

new Long(1).toString() Long.toString(1)

new Float(1.0).toString() Float.toString(1.0)

new Double(1.0).toString() Double.toString(1.0)

新字节(1).toString() Byte.toString(1)

new Short(1).toString() Short.toString(1)

new Boolean(true).toString() Boolean.toString(真)

Bx:方法调用无效的浮点数构造函数; 使用static valueOf(DM_FP_NUMBER_CTOR)

使用new Double(double)保证总是导致一个新对象,而 Double.valueOf(double)允许缓存由编译器,类库或JVM完成的值。使用缓存的值可避免对象分配,代码将更快。

除非类必须与比罗马的JVM Java 1.5的兼容,使用自动装箱或valueOf()创建的实例时方法Double和Float。

Bx:方法调用无效数字构造函数; 使用static valueOf(DM_NUMBER_CTOR)

使用new Integer(int)保证总是导致一个新对象,而 Integer.valueOf(int)允许缓存由编译器,类库或JVM完成的值。使用缓存的值可避免对象分配,代码将更快。

-128和127之间的值保证具有相应的缓存实例,并且使用valueOf大约是使用构造函数的3.5倍。对于恒定范围之外的值,两种样式的性能是一样的。

除非类必须与比罗马的JVM Java 1.5的兼容,使用自动装箱或valueOf()创建的实例时方法 Long,Integer,Short,Character,和Byte。

Dm:URL的equals和hashCode方法被阻止(DMI_BLOCKING_METHODS_ON_URL)

URL的equals和hashCode方法执行域名解析,可能会导致性能下降。见http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html以获取更多信息。考虑使用java.net.URI。

Dm:地图和网址集可以是性能指标(DMI_COLLECTION_OF_URLS)

此方法或字段是或使用地图或一组网址。由于URL的equals和hashCode方法都执行域名解析,因此可能会导致性能下降。见http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html以获取更多信息。考虑使用java.net.URI。

Dm:方法调用无效的布尔构造函数; 使用Boolean.valueOf(…)代替(DM_BOOLEAN_CTOR)

创建java.lang.Boolean浪费内存的新实例,因为Boolean对象是不可变的,并且只有两个这样有用的值。使用Boolean.valueOf() 方法(或Java 1.5自动装箱)来创建Boolean对象。

Dm:显式垃圾收集; 非常可疑,除了基准代码(DM_GC)

代码显式地调用垃圾收集。除了具体用于基准测试,这是非常可疑的。

在过去,人们明确地在例程中调用垃圾收集器的情况,例如close或finalize方法,导致了巨大的性能黑洞。垃圾收集可能是昂贵的。任何迫使数以百计的垃圾收集的情况都会使机器进行爬网。

Dm:方法分配对象,只能获取类对象(DM_NEW_FOR_GETCLASS)

这个方法分配一个对象来调用它的getClass(),以便检索它的Class对象。只需访问该类的.class属性就更简单了。

Dm:使用nextInt方法,而不是nextDouble来生成随机整数(DM_NEXTINT_VIA_NEXTDOUBLE)

如果r是java.util.Random,你可以生成一个随机数0来n-1 使用r.nextInt(n),而不是使用(int)(r.nextDouble() * n)。

nextInt的论证必须是积极的。例如,如果要生成从-99到0的随机值,请使用-r.nextInt(100)。

Dm:方法调用无效的新String(String)构造函数(DM_STRING_CTOR)

使用java.lang.String(String)构造函数会浪费内存,因为如此构造的对象在功能上与String传递的参数无法区分。直接使用参数String。

Dm:方法在String(DM_STRING_TOSTRING)上调用toString()方法

呼叫String.toString()只是一个冗余操作。只需使用String。

Dm:方法调用无效的新的String()构造函数(DM_STRING_VOID_CTOR)

java.lang.String使用无参数构造函数创建新对象会浪费内存,因为如此创建的对象在功能上与空字符串常量无法区分 “”。Java保证相同的字符串常量将由相同的String对象表示。因此,您应该直接使用空字符串常量。

HSC:巨大的字符串常量在多个类文件(HSC_HUGE_SHARED_STRING_CONSTANT)之间复制

一个大的String常量在多个类文件中重复。这很可能是因为最后一个字段被初始化为一个String常量,并且Java语言要求将来自其他类的最后一个字段的引用内联到该类文件中。有关JDK 中此错误发生的描述,请参阅JDK bug 6447475,以及如何解决它将JDK的大小减少1兆字节。

SBSC:方法使用循环中的+连接字符串(SBSC_USE_STRINGBUFFER_CONCATENATION)

该方法似乎在循环中使用连接构建一个String。在每次迭代中,String被转换为StringBuffer / StringBuilder,附加到并转换为String。这可以导致迭代次数中的成本二次方,因为每个迭代中重新生成不断增长的字符串。

通过使用StringBuffer(或Java 1.5中的StringBuilder)可以获得更好的性能。

例如:

// 这不好

String s =“”;

for(int i = 0; i