Skip to content

Caching the length/size in a variable for collections in order to avo… #6453

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

LuisOsv
Copy link

@LuisOsv LuisOsv commented May 7, 2025

Description

Caching the length/size in a variable for collections in order to avoid repeated calls within loops, which can slightly improve performance and readability.

Motivation and Context

While reading High Performance with Java (link), I came across a useful performance tip: it's recommended to cache the size of a collection before entering a loop, instead of calling .size() in the loop condition.

Instead of:

for (int i = 0; i < list.size(); i++) {
    // logic
}

Prefer:

int size = list.size();
for (int i = 0; i < size; i++) {
    // logic
}

How Has This Been Tested?

  • gradlew build was executed and 99% passed (only testInterfaces() failed)
  • gradlew createDist was executed and play with compiled .jar file locally

Types of changes

  • Refactor foor loops

…id repeated calls within loops, which can slightly improve performance and readability.
@ra0077
Copy link
Contributor

ra0077 commented May 9, 2025

Hi,

Thanks to the PR
Do you have bench results (with JMH) to check the performance gain?

Thanks

@LuisOsv
Copy link
Author

LuisOsv commented May 11, 2025

Thanks for the feedback. Since the caching was applied in multiple places, benchmarking every change would be tricky. I can run a benchmark on a representative use case — could you suggest a core functionality or flow you'd like me to focus on?


if (log.isDebugEnabled()) {
log.debug("JmeterKeyStore type: {}", keys.getClass());
}

// Now wrap the default managers with our key manager
for (int i = 0; i < managers.length; i++) {
for (int i = 0; i < managersCount; i++) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could it better be changed to for-each loop instead of factoring managersCount variable?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @vlsi agreed, but the new version will still use index since there is insertion on the array given the index. Are you ok with this change?

Example:

int indexManager = 0;
        for (KeyManager manager : managers) {
            if (manager instanceof X509KeyManager) {
                newManagers[indexManager] = new WrappedX509KeyManager((X509KeyManager) manager, keys);
            } else {
                newManagers[indexManager] = manager;
            }
            indexManager++;
        }

Comment on lines +240 to +241
int trustManagersCount = trustmanagers.length;
for (int i = 0; i < trustManagersCount; i++) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYT of for-each loop?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, are you agree with new version with index?

int indexTrustManager = 0;
        for (TrustManager trustManager : trustmanagers) {
            if (trustManager instanceof X509TrustManager) {
                trustmanagers[indexTrustManager] = new CustomX509TrustManager(
                        (X509TrustManager) trustManager);
            }
            indexTrustManager++;
        }

@vlsi
Copy link
Collaborator

vlsi commented May 11, 2025

There are three types of changes here:

  1. There are valid improvements, and in theory they could make the code a tiny bit faster.

    int columnCount = tableModel.getColumnCount();
    for (int i = 0; i < columnCount; i++) {
  2. There are changes when the loop iteration goes backward. I believe the changes are not justified, and they do not affect performance.

    for (int i = rowsSelected.length - 1; i >= 0; i--) {
  3. There are cases when the loop could be refactored to for-each. I would prefer for-each loops rather than manual for loops.

I suggest we should cleanup 2&3 before merging the PR.
However, what bothers me the most is I can't understand how could one "test" the PR. In other words, is there any automation that could detect "suboptimal loops" and refactor them to the optimal case?
The thing is the new code is slightly harder to read, and I could easily imagine someone could file a PR that refactors the code to the old style. It would be great if there was an automated refactoring to implement the change.

…the loop was unnecessary, as `stack.size()` was already evaluated only once during loop initialization. The additional variable does not improve performance or readability.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants