@reus

Как быстрее работает приложение в цикле на Java?

Здравствуйте, вот задался такой делемой.
Вот к примеру у меня есть объект User, и мне нужно перебрать данные из массива и инициализировать User. Будет ли профит от выноса переменной user за блок с циклом или нет?

То есть будет быстрее так:
User user = null;
for (int i=0;i<userListData.size();i++, user = new User(userListData.get(i))){
    user.sendToHome();
}


Или так:
for (int i=0;i<userListData.size();i++){
    User user = new User(userListData.get(i));
    user.sendToHome();
}

??

Особенно интересно как это влияет когда нужно инициализировать миллионы тяжелых объектов.
Буду благодарен за бенчмарки :)
  • Вопрос задан
  • 259 просмотров
Решения вопроса 1
sergey-gornostaev
@sergey-gornostaev Куратор тега Java
Седой и строгий
В обоих случаях переменная user будет объявлена один раз, а объект типа User будет создан и присвоен этой переменной столько раз, сколько будет итераций цикла. Так что по скорости выигрыша никакого не будет, но второй вариант стилистически правильнее.

Если уж очень хочется замеров, можно накидать бенчмарков на 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-проект полностью.

Кроме того, с высокой долей вероятности JIT-компилятор оба цикла превратит в одинаковый код. У них байткод-то не сильно отличается.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
jamakasi666
@jamakasi666 Куратор тега Java
Просто IT'шник.
Чтобы наверняка попробуйте сами и найдите наиболее быстрый вариант примерно так:
long start = System.currentTimeMillis();
//цикл
long result = System.currentTimeMillis() - start;

Вариаций написания цикла в Jav'e очень много и все отличаются в производительности причем немаловажную роль играет то,какого типа сама коллекция(массив).
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы