1006 lines
38 KiB
XML
1006 lines
38 KiB
XML
<?xml version="1.0"?>
|
|
|
|
<ruleset name="Performance"
|
|
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
|
|
|
<description>
|
|
Rules that flag suboptimal code.
|
|
</description>
|
|
|
|
<rule name="AddEmptyString"
|
|
language="java"
|
|
since="4.0"
|
|
message="Do not add empty strings"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#addemptystring">
|
|
<description>
|
|
The conversion of literals to strings by concatenating them with empty strings is inefficient.
|
|
It is much better to use one of the type-specific toString() methods instead.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//AdditiveExpression/PrimaryExpression/PrimaryPrefix/Literal[@Image='""']
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
String s = "" + 123; // inefficient
|
|
String t = Integer.toString(456); // preferred approach
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AppendCharacterWithChar"
|
|
since="3.5"
|
|
message="Avoid appending characters as strings in StringBuffer.append."
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.AppendCharacterWithCharRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#appendcharacterwithchar">
|
|
<description>
|
|
Avoid concatenating characters as strings in StringBuffer/StringBuilder.append methods.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
StringBuffer sb = new StringBuffer();
|
|
sb.append("a"); // avoid this
|
|
|
|
StringBuffer sb = new StringBuffer();
|
|
sb.append('a'); // use this instead
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidArrayLoops"
|
|
language="java"
|
|
since="3.5"
|
|
message="System.arraycopy is more efficient"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#avoidarrayloops">
|
|
<description>
|
|
Instead of manually copying data between two arrays, use the efficient Arrays.copyOf or System.arraycopy method instead.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//Statement[(ForStatement or WhileStatement) and
|
|
count(*//AssignmentOperator[@Image = '='])=1
|
|
and
|
|
*/Statement
|
|
[
|
|
./Block/BlockStatement/Statement/StatementExpression/PrimaryExpression
|
|
/PrimaryPrefix/Name/../../PrimarySuffix/Expression
|
|
[(PrimaryExpression or AdditiveExpression) and count
|
|
(.//PrimaryPrefix/Name)=1]//PrimaryPrefix/Name/@Image
|
|
and
|
|
./Block/BlockStatement/Statement/StatementExpression/Expression/PrimaryExpression
|
|
/PrimaryPrefix/Name/../../PrimarySuffix[count
|
|
(..//PrimarySuffix)=1]/Expression[(PrimaryExpression
|
|
or AdditiveExpression) and count(.//PrimaryPrefix/Name)=1]
|
|
//PrimaryPrefix/Name/@Image
|
|
]]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class Test {
|
|
public void bar() {
|
|
int[] a = new int[10];
|
|
int[] b = new int[10];
|
|
for (int i=0;i<10;i++) {
|
|
b[i]=a[i];
|
|
}
|
|
|
|
int[] c = new int[10];
|
|
// this will trigger the rule
|
|
for (int i=0;i<10;i++) {
|
|
b[i]=a[c[i]];
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidFileStream"
|
|
since="6.0.0"
|
|
message="Avoid instantiating FileInputStream, FileOutputStream, FileReader, or FileWriter"
|
|
language="java"
|
|
minimumLanguageVersion="1.7"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#avoidfilestream">
|
|
<description>
|
|
The FileInputStream and FileOutputStream classes contains a finalizer method which will cause garbage
|
|
collection pauses.
|
|
See [JDK-8080225](https://bugs.openjdk.java.net/browse/JDK-8080225) for details.
|
|
|
|
The FileReader and FileWriter constructors instantiate FileInputStream and FileOutputStream,
|
|
again causing garbage collection issues while finalizer methods are called.
|
|
|
|
* Use `Files.newInputStream(Paths.get(fileName))` instead of `new FileInputStream(fileName)`.
|
|
* Use `Files.newOutputStream(Paths.get(fileName))` instead of `new FileOutputStream(fileName)`.
|
|
* Use `Files.newBufferedReader(Paths.get(fileName))` instead of `new FileReader(fileName)`.
|
|
* Use `Files.newBufferedWriter(Paths.get(fileName))` instead of `new FileWriter(fileName)`.
|
|
|
|
Please note, that the `java.nio` API does not throw a `FileNotFoundException` anymore, instead
|
|
it throws a `NoSuchFileException`. If your code dealt explicitly with a `FileNotFoundException`,
|
|
then this needs to be adjusted. Both exceptions are subclasses of `IOException`, so catching
|
|
that one covers both.
|
|
</description>
|
|
<priority>1</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//PrimaryPrefix/AllocationExpression/ClassOrInterfaceType[
|
|
pmd-java:typeIs('java.io.FileInputStream')
|
|
or pmd-java:typeIs('java.io.FileOutputStream')
|
|
or pmd-java:typeIs('java.io.FileReader')
|
|
or pmd-java:typeIs('java.io.FileWriter')
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
// these instantiations cause garbage collection pauses, even if properly closed
|
|
|
|
FileInputStream fis = new FileInputStream(fileName);
|
|
FileOutputStream fos = new FileOutputStream(fileName);
|
|
FileReader fr = new FileReader(fileName);
|
|
FileWriter fw = new FileWriter(fileName);
|
|
|
|
// the following instantiations help prevent Garbage Collection pauses, no finalization
|
|
|
|
try(InputStream is = Files.newInputStream(Paths.get(fileName))) {
|
|
}
|
|
try(OutputStream os = Files.newOutputStream(Paths.get(fileName))) {
|
|
}
|
|
try(BufferedReader br = Files.newBufferedReader(Paths.get(fileName), StandardCharsets.UTF_8)) {
|
|
}
|
|
try(BufferedWriter wr = Files.newBufferedWriter(Paths.get(fileName), StandardCharsets.UTF_8)) {
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidInstantiatingObjectsInLoops"
|
|
since="2.2"
|
|
message="Avoid instantiating new objects inside loops"
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.AvoidInstantiatingObjectsInLoopsRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#avoidinstantiatingobjectsinloops">
|
|
<description>
|
|
New objects created within loops should be checked to see if they can created outside them and reused.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Something {
|
|
public static void main( String as[] ) {
|
|
for (int i = 0; i < 10; i++) {
|
|
Foo f = new Foo(); // Avoid this whenever you can it's really expensive
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="AvoidUsingShortType"
|
|
language="java"
|
|
since="4.1"
|
|
message="Do not use the short type"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#avoidusingshorttype">
|
|
<description>
|
|
Java uses the 'short' type to reduce memory usage, not to optimize calculation. In fact, the JVM does not have any
|
|
arithmetic capabilities for the short type: the JVM must convert the short into an int, do the proper calculation
|
|
and convert the int back to a short. Thus any storage gains found through use of the 'short' type may be offset by
|
|
adverse impacts on performance.
|
|
</description>
|
|
<priority>1</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//FieldDeclaration/Type/PrimitiveType[@Image = 'short']
|
|
|
|
|
//ClassOrInterfaceBodyDeclaration[not(Annotation/MarkerAnnotation/Name[pmd-java:typeIs('java.lang.Override')])]
|
|
/MethodDeclaration/ResultType/Type/PrimitiveType[@Image = 'short']
|
|
|
|
|
//ClassOrInterfaceBodyDeclaration[not(Annotation/MarkerAnnotation/Name[pmd-java:typeIs('java.lang.Override')])]
|
|
/MethodDeclaration/MethodDeclarator/FormalParameters/FormalParameter/Type/PrimitiveType[@Image = 'short']
|
|
|
|
|
//LocalVariableDeclaration/Type/PrimitiveType[@Image = 'short']
|
|
|
|
|
//AnnotationMethodDeclaration/Type/PrimitiveType[@Image = 'short']
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class UsingShort {
|
|
private short doNotUseShort = 0;
|
|
|
|
public UsingShort() {
|
|
short shouldNotBeUsed = 1;
|
|
doNotUseShort += shouldNotBeUsed;
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="BigIntegerInstantiation"
|
|
since="3.9"
|
|
message="Don't create instances of already existing BigInteger and BigDecimal (ZERO, ONE, TEN)"
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.BigIntegerInstantiationRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#bigintegerinstantiation">
|
|
<description>
|
|
Don't create instances of already existing BigInteger (BigInteger.ZERO, BigInteger.ONE) and
|
|
for Java 1.5 onwards, BigInteger.TEN and BigDecimal (BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN)
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
BigInteger bi = new BigInteger(1); // reference BigInteger.ONE instead
|
|
BigInteger bi2 = new BigInteger("0"); // reference BigInteger.ZERO instead
|
|
BigInteger bi3 = new BigInteger(0.0); // reference BigInteger.ZERO instead
|
|
BigInteger bi4;
|
|
bi4 = new BigInteger(0); // reference BigInteger.ZERO instead
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="BooleanInstantiation"
|
|
since="1.2"
|
|
message="Avoid instantiating Boolean objects; reference Boolean.TRUE or Boolean.FALSE or call Boolean.valueOf() instead."
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.BooleanInstantiationRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#booleaninstantiation">
|
|
<description>
|
|
Avoid instantiating Boolean objects; you can reference Boolean.TRUE, Boolean.FALSE, or call Boolean.valueOf() instead.
|
|
Note that new Boolean() is deprecated since JDK 9 for that reason.
|
|
</description>
|
|
<priority>2</priority>
|
|
<example>
|
|
<![CDATA[
|
|
Boolean bar = new Boolean("true"); // unnecessary creation, just reference Boolean.TRUE;
|
|
Boolean buz = Boolean.valueOf(false); // ...., just reference Boolean.FALSE;
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="ByteInstantiation"
|
|
language="java"
|
|
since="4.0"
|
|
message="Avoid instantiating Byte objects. Call Byte.valueOf() instead"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#byteinstantiation">
|
|
<description>
|
|
Calling new Byte() causes memory allocation that can be avoided by the static Byte.valueOf().
|
|
It makes use of an internal cache that recycles earlier instances making it more memory efficient.
|
|
Note that new Byte() is deprecated since JDK 9 for that reason.
|
|
</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//AllocationExpression
|
|
[not (ArrayDimsAndInits)
|
|
and ClassOrInterfaceType[pmd-java:typeIs('java.lang.Byte')]]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
private Byte i = new Byte(0); // change to Byte i = Byte.valueOf(0);
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="ConsecutiveAppendsShouldReuse"
|
|
language="java"
|
|
since="5.1"
|
|
message="StringBuffer (or StringBuilder).append is called consecutively without reusing the target variable."
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.ConsecutiveAppendsShouldReuseRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#consecutiveappendsshouldreuse">
|
|
<description>
|
|
Consecutive calls to StringBuffer/StringBuilder .append should be chained, reusing the target object. This can improve the performance
|
|
by producing a smaller bytecode, reducing overhead and improving inlining. A complete analysis can be found [here](https://github.com/pmd/pmd/issues/202#issuecomment-274349067)
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
String foo = " ";
|
|
|
|
StringBuffer buf = new StringBuffer();
|
|
buf.append("Hello"); // poor
|
|
buf.append(foo);
|
|
buf.append("World");
|
|
|
|
StringBuffer buf = new StringBuffer();
|
|
buf.append("Hello").append(foo).append("World"); // good
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="ConsecutiveLiteralAppends"
|
|
since="3.5"
|
|
message="StringBuffer (or StringBuilder).append is called {0} consecutive times with literals. Use a single append with a single combined String."
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.ConsecutiveLiteralAppendsRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#consecutiveliteralappends">
|
|
<description>
|
|
Consecutively calling StringBuffer/StringBuilder.append(...) with literals should be avoided.
|
|
Since the literals are constants, they can already be combined into a single String literal and this String
|
|
can be appended in a single method call.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
StringBuilder buf = new StringBuilder();
|
|
buf.append("Hello").append(" ").append("World"); // poor
|
|
buf.append("Hello World"); // good
|
|
|
|
buf.append('h').append('e').append('l').append('l').append('o'); // poor
|
|
buf.append("hello"); // good
|
|
|
|
buf.append(1).append('m'); // poor
|
|
buf.append("1m"); // good
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="InefficientEmptyStringCheck"
|
|
since="3.6"
|
|
message="String.trim().length() == 0 / String.trim().isEmpty() is an inefficient way to validate a blank String."
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.InefficientEmptyStringCheckRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#inefficientemptystringcheck">
|
|
<description>
|
|
<![CDATA[
|
|
String.trim().length() == 0 (or String.trim().isEmpty() for the same reason) is an inefficient
|
|
way to check if a String is really blank, as it creates a new String object just to check its size.
|
|
Consider creating a static function that loops through a string, checking Character.isWhitespace()
|
|
on each character and returning false if a non-whitespace character is found. A Smarter code to
|
|
check for an empty string would be:
|
|
|
|
```java
|
|
private boolean checkTrimEmpty(String str) {
|
|
for(int i = 0; i < str.length(); i++) {
|
|
if(!Character.isWhitespace(str.charAt(i))) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
```
|
|
|
|
You can refer to Apache's StringUtils#isBlank (in commons-lang),
|
|
Spring's StringUtils#hasText (in the Spring framework) or Google's
|
|
CharMatcher#whitespace (in Guava) for existing implementations (some might
|
|
include the check for != null).
|
|
]]>
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public void bar(String string) {
|
|
if (string != null && string.trim().length() > 0) {
|
|
doSomething();
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="InefficientStringBuffering"
|
|
since="3.4"
|
|
message="Avoid concatenating nonliterals in a StringBuffer/StringBuilder constructor or append()."
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.InefficientStringBufferingRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#inefficientstringbuffering">
|
|
<description>
|
|
Avoid concatenating non-literals in a StringBuffer constructor or append() since intermediate buffers will
|
|
need to be be created and destroyed by the JVM.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
// Avoid this, two buffers are actually being created here
|
|
StringBuffer sb = new StringBuffer("tmp = "+System.getProperty("java.io.tmpdir"));
|
|
|
|
// do this instead
|
|
StringBuffer sb = new StringBuffer("tmp = ");
|
|
sb.append(System.getProperty("java.io.tmpdir"));
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="InsufficientStringBufferDeclaration"
|
|
since="3.6"
|
|
message="StringBuffer constructor is initialized with size {0}, but has at least {1} characters appended."
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.InsufficientStringBufferDeclarationRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#insufficientstringbufferdeclaration">
|
|
<description>
|
|
Failing to pre-size a StringBuffer or StringBuilder properly could cause it to re-size many times
|
|
during runtime. This rule attempts to determine the total number the characters that are actually
|
|
passed into StringBuffer.append(), but represents a best guess "worst case" scenario. An empty
|
|
StringBuffer/StringBuilder constructor initializes the object to 16 characters. This default
|
|
is assumed if the length of the constructor can not be determined.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
StringBuffer bad = new StringBuffer();
|
|
bad.append("This is a long string that will exceed the default 16 characters");
|
|
|
|
StringBuffer good = new StringBuffer(41);
|
|
good.append("This is a long string, which is pre-sized");
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="IntegerInstantiation"
|
|
language="java"
|
|
since="3.5"
|
|
message="Avoid instantiating Integer objects. Call Integer.valueOf() instead."
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#integerinstantiation">
|
|
<description>
|
|
Calling new Integer() causes memory allocation that can be avoided by the static Integer.valueOf().
|
|
It makes use of an internal cache that recycles earlier instances making it more memory efficient.
|
|
Note that new Integer() is deprecated since JDK 9 for that reason.
|
|
</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//AllocationExpression
|
|
[not (ArrayDimsAndInits)
|
|
and ClassOrInterfaceType[pmd-java:typeIs('java.lang.Integer')]]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
private Integer i = new Integer(0); // change to Integer i = Integer.valueOf(0);
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="LongInstantiation"
|
|
language="java"
|
|
since="4.0"
|
|
message="Avoid instantiating Long objects.Call Long.valueOf() instead"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#longinstantiation">
|
|
<description>
|
|
Calling new Long() causes memory allocation that can be avoided by the static Long.valueOf().
|
|
It makes use of an internal cache that recycles earlier instances making it more memory efficient.
|
|
Note that new Long() is deprecated since JDK 9 for that reason.
|
|
</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//AllocationExpression
|
|
[not (ArrayDimsAndInits)
|
|
and ClassOrInterfaceType[pmd-java:typeIs('java.lang.Long')]]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
private Long i = new Long(0); // change to Long i = Long.valueOf(0);
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="OptimizableToArrayCall"
|
|
language="java"
|
|
since="1.8"
|
|
minimumLanguageVersion="1.6"
|
|
message="This call to Collection.toArray() may be optimizable"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#optimizabletoarraycall">
|
|
<description>
|
|
Calls to a collection's `toArray(E[])` method should specify a target array of zero size. This allows the JVM
|
|
to optimize the memory allocation and copying as much as possible.
|
|
|
|
Previous versions of this rule (pre PMD 6.0.0) suggested the opposite, but current JVM implementations
|
|
perform always better, when they have full control over the target array. And allocation an array via
|
|
reflection is nowadays as fast as the direct allocation.
|
|
|
|
See also [Arrays of Wisdom of the Ancients](https://shipilev.net/blog/2016/arrays-wisdom-ancients/)
|
|
|
|
Note: If you don't need an array of the correct type, then the simple `toArray()` method without an array
|
|
is faster, but returns only an array of type `Object[]`.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//PrimaryExpression
|
|
[PrimaryPrefix/Name[ends-with(@Image, 'toArray')]]
|
|
[
|
|
PrimarySuffix/Arguments/ArgumentList/Expression
|
|
/PrimaryExpression/PrimaryPrefix/AllocationExpression
|
|
/ArrayDimsAndInits/Expression/PrimaryExpression/PrimaryPrefix[not(Literal[@Image='0'])]
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
List<Foo> foos = getFoos();
|
|
|
|
// much better; this one allows the jvm to allocate an array of the correct size and effectively skip
|
|
// the zeroing, since each array element will be overridden anyways
|
|
Foo[] fooArray = foos.toArray(new Foo[0]);
|
|
|
|
// inefficient, the array needs to be zeroed out by the jvm before it is handed over to the toArray method
|
|
Foo[] fooArray = foos.toArray(new Foo[foos.size()]);
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="RedundantFieldInitializer"
|
|
language="java"
|
|
since="5.0"
|
|
message="Avoid using redundant field initializer for ''${variableName}''"
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.RedundantFieldInitializerRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#redundantfieldinitializer">
|
|
<description>
|
|
Java will initialize fields with known default values so any explicit initialization of those same defaults
|
|
is redundant and results in a larger class file (approximately three additional bytecode instructions per field).
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class C {
|
|
boolean b = false; // examples of redundant initializers
|
|
byte by = 0;
|
|
short s = 0;
|
|
char c = 0;
|
|
int i = 0;
|
|
long l = 0;
|
|
|
|
float f = .0f; // all possible float literals
|
|
doable d = 0d; // all possible double literals
|
|
Object o = null;
|
|
|
|
MyClass mca[] = null;
|
|
int i1 = 0, ia1[] = null;
|
|
|
|
class Nested {
|
|
boolean b = false;
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="SimplifyStartsWith"
|
|
language="java"
|
|
since="3.1"
|
|
message="This call to String.startsWith can be rewritten using String.charAt(0)"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#simplifystartswith">
|
|
<description>
|
|
Since it passes in a literal of length 1, calls to (string).startsWith can be rewritten using (string).charAt(0)
|
|
at the expense of some readability.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//PrimaryExpression
|
|
[PrimaryPrefix/Name
|
|
[ends-with(@Image, '.startsWith')] or PrimarySuffix[@Image='startsWith']]
|
|
[PrimarySuffix/Arguments/ArgumentList
|
|
/Expression/PrimaryExpression/PrimaryPrefix
|
|
/Literal
|
|
[string-length(@Image)=3]
|
|
[starts-with(@Image, '"')]
|
|
[ends-with(@Image, '"')]
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
|
|
boolean checkIt(String x) {
|
|
return x.startsWith("a"); // suboptimal
|
|
}
|
|
|
|
boolean fasterCheckIt(String x) {
|
|
return x.charAt(0) == 'a'; // faster approach
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="ShortInstantiation"
|
|
language="java"
|
|
since="4.0"
|
|
message="Avoid instantiating Short objects. Call Short.valueOf() instead"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
typeResolution="true"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#shortinstantiation">
|
|
<description>
|
|
Calling new Short() causes memory allocation that can be avoided by the static Short.valueOf().
|
|
It makes use of an internal cache that recycles earlier instances making it more memory efficient.
|
|
Note that new Short() is deprecated since JDK 9 for that reason.
|
|
</description>
|
|
<priority>2</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//AllocationExpression
|
|
[not (ArrayDimsAndInits)
|
|
and ClassOrInterfaceType[pmd-java:typeIs('java.lang.Short')]]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
private Short i = new Short(0); // change to Short i = Short.valueOf(0);
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="StringInstantiation"
|
|
since="1.0"
|
|
message="Avoid instantiating String objects; this is usually unnecessary."
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.StringInstantiationRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#stringinstantiation">
|
|
<description>
|
|
Avoid instantiating String objects; this is usually unnecessary since they are immutable and can be safely shared.
|
|
</description>
|
|
<priority>2</priority>
|
|
<example>
|
|
<![CDATA[
|
|
private String bar = new String("bar"); // just do a String bar = "bar";
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="StringToString"
|
|
since="1.0"
|
|
message="Avoid calling toString() on String objects; this is unnecessary."
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.StringToStringRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#stringtostring">
|
|
<description>
|
|
Avoid calling toString() on objects already known to be string instances; this is unnecessary.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
private String baz() {
|
|
String bar = "howdy";
|
|
return bar.toString();
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="TooFewBranchesForASwitchStatement"
|
|
language="java"
|
|
since="4.2"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
message="A switch with less than three branches is inefficient, use a 'if statement' instead."
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#toofewbranchesforaswitchstatement">
|
|
<description>
|
|
Switch statements are intended to be used to support complex branching behaviour. Using a switch for only a few
|
|
cases is ill-advised, since switches are not as easy to understand as if-then statements. In these cases use the
|
|
if-then statement to increase code readability.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="minimumNumberCaseForASwitch" type="Integer" description="Minimum number of branches for a switch" min="1" max="100" value="3"/>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//SwitchStatement[
|
|
(count(.//SwitchLabel) < $minimumNumberCaseForASwitch)
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
// With a minimumNumberCaseForASwitch of 3
|
|
public class Foo {
|
|
public void bar() {
|
|
switch (condition) {
|
|
case ONE:
|
|
instruction;
|
|
break;
|
|
default:
|
|
break; // not enough for a 'switch' stmt, a simple 'if' stmt would have been more appropriate
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UnnecessaryWrapperObjectCreation"
|
|
since="3.8"
|
|
message="Unnecessary wrapper object creation"
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.UnnecessaryWrapperObjectCreationRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#unnecessarywrapperobjectcreation">
|
|
<description>
|
|
Most wrapper classes provide static conversion methods that avoid the need to create intermediate objects
|
|
just to create the primitive forms. Using these avoids the cost of creating objects that also need to be
|
|
garbage-collected later.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public int convert(String s) {
|
|
int i, i2;
|
|
|
|
i = Integer.valueOf(s).intValue(); // this wastes an object
|
|
i = Integer.parseInt(s); // this is better
|
|
|
|
i2 = Integer.valueOf(i).intValue(); // this wastes an object
|
|
i2 = i; // this is better
|
|
|
|
String s3 = Integer.valueOf(i2).toString(); // this wastes an object
|
|
s3 = Integer.toString(i2); // this is better
|
|
|
|
return i2;
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UseArrayListInsteadOfVector"
|
|
language="java"
|
|
since="3.0"
|
|
message="Use ArrayList instead of Vector"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#usearraylistinsteadofvector">
|
|
<description>
|
|
ArrayList is a much better Collection implementation than Vector if thread-safe operation is not required.
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//CompilationUnit[count(ImportDeclaration) = 0 or count(ImportDeclaration/Name[@Image='java.util.Vector']) > 0]
|
|
//AllocationExpression/ClassOrInterfaceType
|
|
[@Image='Vector' or @Image='java.util.Vector']
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class SimpleTest extends TestCase {
|
|
public void testX() {
|
|
Collection c1 = new Vector();
|
|
Collection c2 = new ArrayList(); // achieves the same with much better performance
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UseArraysAsList"
|
|
language="java"
|
|
since="3.5"
|
|
message="Use asList instead of tight loops"
|
|
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#usearraysaslist">
|
|
<description>
|
|
<![CDATA[
|
|
The java.util.Arrays class has a "asList" method that should be used when you want to create a new List from
|
|
an array of objects. It is faster than executing a loop to copy all the elements of the array one by one.
|
|
|
|
Note that the result of Arrays.asList() is backed by the specified array,
|
|
changes in the returned list will result in the array to be modified.
|
|
For that reason, it is not possible to add new elements to the returned list of Arrays.asList() (UnsupportedOperationException).
|
|
You must use new ArrayList<>(Arrays.asList(...)) if that is inconvenient for you (e.g. because of concurrent access).
|
|
]]>
|
|
</description>
|
|
<priority>3</priority>
|
|
<properties>
|
|
<property name="xpath">
|
|
<value>
|
|
<![CDATA[
|
|
//Statement[
|
|
(ForStatement) and (ForStatement//VariableInitializer//Literal[@IntLiteral='true' and @Image='0']) and (count(.//IfStatement)=0)
|
|
]
|
|
//StatementExpression[
|
|
PrimaryExpression/PrimaryPrefix/Name[
|
|
substring-before(@Image,'.add') = ancestor::MethodDeclaration//LocalVariableDeclaration[
|
|
./Type//ClassOrInterfaceType[
|
|
@Image = 'Collection' or
|
|
@Image = 'List' or @Image='ArrayList'
|
|
]
|
|
]
|
|
/VariableDeclarator/VariableDeclaratorId[
|
|
count(..//AllocationExpression/ClassOrInterfaceType[
|
|
@Image="ArrayList"
|
|
]
|
|
)=1
|
|
]/@Image
|
|
]
|
|
and
|
|
PrimaryExpression/PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Name
|
|
[
|
|
@Image = ancestor::MethodDeclaration[1]//LocalVariableDeclaration/VariableDeclarator/VariableDeclaratorId[@ArrayType="true"]/@Image
|
|
or
|
|
@Image = ancestor::MethodDeclaration[1]//FormalParameter/VariableDeclaratorId/@Image
|
|
]
|
|
/../..[count(.//PrimarySuffix)
|
|
=1]/PrimarySuffix/Expression/PrimaryExpression/PrimaryPrefix
|
|
/Name
|
|
]
|
|
]]>
|
|
</value>
|
|
</property>
|
|
</properties>
|
|
<example>
|
|
<![CDATA[
|
|
public class Test {
|
|
public void foo(Integer[] ints) {
|
|
// could just use Arrays.asList(ints)
|
|
List<Integer> l= new ArrayList<>(100);
|
|
for (int i=0; i< 100; i++) {
|
|
l.add(ints[i]);
|
|
}
|
|
for (int i=0; i< 100; i++) {
|
|
l.add(a[i].toString()); // won't trigger the rule
|
|
}
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UseIndexOfChar"
|
|
since="3.5"
|
|
message="String.indexOf(char) is faster than String.indexOf(String)."
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.UseIndexOfCharRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#useindexofchar">
|
|
<description>
|
|
Use String.indexOf(char) when checking for the index of a single character; it executes faster.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
String s = "hello world";
|
|
// avoid this
|
|
if (s.indexOf("d") {}
|
|
// instead do this
|
|
if (s.indexOf('d') {}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UselessStringValueOf"
|
|
since="3.8"
|
|
message="No need to call String.valueOf to append to a string."
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.UselessStringValueOfRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#uselessstringvalueof">
|
|
<description>
|
|
No need to call String.valueOf to append to a string; just use the valueOf() argument directly.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public String convert(int i) {
|
|
String s;
|
|
s = "a" + String.valueOf(i); // not required
|
|
s = "a" + i; // preferred approach
|
|
return s;
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UseStringBufferForStringAppends"
|
|
since="3.1"
|
|
message="Prefer StringBuilder (non-synchronized) or StringBuffer (synchronized) over += for concatenating strings"
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.UseStringBufferForStringAppendsRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#usestringbufferforstringappends">
|
|
<description>
|
|
The use of the '+=' operator for appending strings causes the JVM to create and use an internal StringBuffer.
|
|
If a non-trivial number of these concatenations are being used then the explicit use of a StringBuilder or
|
|
threadsafe StringBuffer is recommended to avoid this.
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
public class Foo {
|
|
void bar() {
|
|
String a;
|
|
a = "foo";
|
|
a += " bar";
|
|
// better would be:
|
|
// StringBuilder a = new StringBuilder("foo");
|
|
// a.append(" bar");
|
|
}
|
|
}
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
<rule name="UseStringBufferLength"
|
|
since="3.4"
|
|
message="This is an inefficient use of StringBuffer.toString; call StringBuffer.length instead."
|
|
class="net.sourceforge.pmd.lang.java.rule.performance.UseStringBufferLengthRule"
|
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#usestringbufferlength">
|
|
<description>
|
|
Use StringBuffer.length() to determine StringBuffer length rather than using StringBuffer.toString().equals("")
|
|
or StringBuffer.toString().length() == ...
|
|
</description>
|
|
<priority>3</priority>
|
|
<example>
|
|
<![CDATA[
|
|
StringBuffer sb = new StringBuffer();
|
|
|
|
if (sb.toString().equals("")) {} // inefficient
|
|
|
|
if (sb.length() == 0) {} // preferred
|
|
]]>
|
|
</example>
|
|
</rule>
|
|
|
|
|
|
<!--
|
|
other optimization/performance should be like avoiding
|
|
"" + int
|
|
or "" + (int) i
|
|
and String.valueOf(int)
|
|
|
|
and using Integer.toString(int)
|
|
|
|
IntegerToStringShouldBeUsed
|
|
LongToStringShouldBeUsed
|
|
BooleanToStringShouldBeUsed
|
|
-->
|
|
|
|
</ruleset>
|