diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index eb1a123a63..c0719e98bb 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -252,6 +252,11 @@ The rule reference documentation has been updated to reflect these changes. * The Java rule `EmptyCatchBlock` (category `errorprone`, former ruleset `java-empty`) has been changed to ignore exceptions named `ignore` or `expected` by default. You can still override this behaviour by setting the `allowExceptionNameRegex` property. +* The Java rule `OptimizableToArrayCall` (category `performance`, former ruleset `design`) has been + modified to fit for the current JVM implementations: It basically detects now the opposite and suggests to + use `Collection.toArray(new E[0])` with a zero-sized array. + See [Arrays of Wisdom of the Ancients](https://shipilev.net/blog/2016/arrays-wisdom-ancients/). + #### Deprecated Rules * The Java rules `NcssConstructorCount`, `NcssMethodCount`, and `NcssTypeCount` (ruleset `java-codesize`) have been @@ -339,6 +344,7 @@ a warning will now be produced suggesting users to adopt it for better performan * cpp * [#448](https://github.com/pmd/pmd/issues/448): \[cpp] Write custom CharStream to handle continuation characters * java + * [#1454](https://sourceforge.net/p/pmd/bugs/1454/): \[java] OptimizableToArrayCall is outdated and invalid in current JVMs * [#1513](https://sourceforge.net/p/pmd/bugs/1513/): \[java] Remove deprecated rule UseSingleton * [#328](https://github.com/pmd/pmd/issues/328): \[java] java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/servlet/jsp/PageContext * [#487](https://github.com/pmd/pmd/pull/487): \[java] Fix typeresolution for anonymous extending object diff --git a/pmd-java/src/main/resources/category/java/performance.xml b/pmd-java/src/main/resources/category/java/performance.xml index 388f1d39ed..86adf370c9 100644 --- a/pmd-java/src/main/resources/category/java/performance.xml +++ b/pmd-java/src/main/resources/category/java/performance.xml @@ -428,9 +428,17 @@ public class Foo { class="net.sourceforge.pmd.lang.rule.XPathRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#optimizabletoarraycall"> -Calls to a collection's toArray() method should specify target arrays sized to match the size of the -collection. Initial arrays that are too small are discarded in favour of new ones that have to be created -that are the proper size. +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[]`. 3 @@ -442,7 +450,7 @@ that are the proper size. [ PrimarySuffix/Arguments/ArgumentList/Expression /PrimaryExpression/PrimaryPrefix/AllocationExpression - /ArrayDimsAndInits/Expression/PrimaryExpression/PrimaryPrefix/Literal[@Image='0'] + /ArrayDimsAndInits/Expression/PrimaryExpression/PrimaryPrefix[not(Literal[@Image='0'])] ] ]]> @@ -450,13 +458,13 @@ PrimarySuffix/Arguments/ArgumentList/Expression foos = getFoos(); - // inefficient, the array will be discarded +// 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]); - // much better; this one sizes the destination array, - // avoiding of a new one via reflection +// 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()]); ]]> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/OptimizableToArrayCall.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/OptimizableToArrayCall.xml index b58567951c..d4866c48b2 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/OptimizableToArrayCall.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/OptimizableToArrayCall.xml @@ -4,10 +4,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> - - 1 + Preferred usage (sf #1454) + 0 - - 0 + Array dimensioner uses method call, performance issue + 1 - - 0 + Array dimensioner uses variable, performance issue + 1 #937 OptimizableToArrayCall does not catch multilevel method chains - 1 + 0 + + + + Array with a literal dimension, zero still better + 1 + + + + + toArray call without an array should not be flagged + 0 +