R
R
reus2017-09-01 15:48:12
Java
reus, 2017-09-01 15:48:12

How does an application run faster in a loop in Java?

Hello, I've got this dilemma.
For example, I have a User object, and I need to iterate over the data from the array and initialize the User. Will there be profit from moving the user variable outside the block with a cycle or not?
That is, it will be faster like this:

User user = null;
for (int i=0;i<userListData.size();i++, user = new User(userListData.get(i))){
    user.sendToHome();
}

Or like this:
for (int i=0;i<userListData.size();i++){
    User user = new User(userListData.get(i));
    user.sendToHome();
}

??
It is especially interesting how this affects when you need to initialize millions of heavy objects.
I would be grateful for benchmarks :)

Answer the question

In order to leave comments, you need to log in

2 answer(s)
S
Sergey Gornostaev, 2017-09-01
@reus

In both cases, the user variable will be declared once, and an object of type User will be created and assigned to this variable as many times as there are loop iterations. So there will be no gain in terms of speed, but the second option is stylistically correct .
If you really want measurements, you can throw benchmarks on JMH :

package com.example;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;

class User {
    private final String name;

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

public class MyBenchmark {
    // Загрузка списка имён для инициализации объектов
    @State(Scope.Thread)
    public static class MyState {
        public List<String> nameList;

        @Setup(Level.Trial)
        public void setup() throws IOException {
            nameList = new ArrayList<>();

            ClassLoader classLoader = getClass().getClassLoader();
            
            try (BufferedReader br = new BufferedReader(
                                       new InputStreamReader(
                                         classLoader.getResourceAsStream("names.txt")))) {
                String line;
                while ((line = br.readLine()) != null) {
                    nameList.add(line.trim());
                }
            }
        }
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public void outerVarDef(MyState state, Blackhole blackhole) {
        long counter = 0;

        // Если здесь оставить null, как у вас написано,
        // то получим NullPointerException на первой итерации
        User user = new User(state.nameList.get(0));
        // Конструкцию i++, user = new User(userListData.get(i)) можно и нужно сократить
        // так и короче, и красивее, и OutOfBoundException не получим
        for (int i = 0; i < state.nameList.size(); user = new User(state.nameList.get(i++))) {
            counter += user.getName().length(); // Чтобы избежать Dead Code Elimination
        }

        blackhole.consume(counter);
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public void innerVarDef(MyState state, Blackhole blackhole) {
        long counter = 0;

        for (int i = 0; i < state.nameList.size(); i++) {
            User user = new User(state.nameList.get(i));
            counter += user.getName().length(); // Чтобы избежать Dead Code Elimination
        }

        blackhole.consume(counter);
    }
}

Maven project in full.
In addition, with a high degree of probability, the JIT compiler will turn both loops into the same code. Their bytecode is not much different.

D
Dmitry Alexandrov, 2017-09-01
@jamakasi666

To be sure, try it yourself and find the fastest option like this:

long start = System.currentTimeMillis();
//цикл
long result = System.currentTimeMillis() - start;

There are a lot of variations of writing a loop in Jav'e and they all differ in performance, and the type of the collection (array) itself plays an important role.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question