[Решено] Multiple lines in tablist

  • Автор темы Автор темы CoolBoy
  • Дата начала Дата начала
Статус
Закрыто для дальнейших ответов.
В данном случае - это костыль.
Код цикла и код StringJoiner выполняет одно и тоже, а значит - не костыль.

Зачем костылять, если есть уже готовое в Java SE? Пиши тогда еще и свою коллекцию.
Я такого нигде не говорил.
Зачем костылять, если есть уже готовое в Java SE?
Сказали. И если программер не умеет делать реализации простых структур данных - такие никому не нужны.
 
Код цикла и код StringJoiner выполняет одно и тоже, а значит - не костыль.




Сказали. И если программер не умеет делать реализации простых структур данных - такие никому не нужны.
"Я лучше знаю, что ты сказал."
Костыль. И посмотри код StringJoiner'а, там принцип другой, да и производительность выше.
И если программер не знает Java SE API, такой тоже никому не нужен. От него можно ждать только костыльные реализации.
 
Последнее редактирование:
"Я лучше знаю, что ты сказал."
Костыль. И посмотри код StringJoiner'а, там принцип другой, да и производительность выше.
И если программер не знает Java SE API, такой тоже никому не нужен. От него можно ждать только костыльные реализации.
Костыль - это кривая, но работающая затычка в коде. В данном случае собственная реализация стрингджойнера - велосипед, но может человек не может в жабу 8, всякое говно бывает.
 
Костыль - это кривая, но работающая затычка в коде. В данном случае собственная реализация стрингджойнера - велосипед, но может человек не может в жабу 8, всякое говно бывает.
Было бы велосипедом, если бы использовал хотя бы StringBuilder, а так - костыль.
Если элементов много будет, то сколько там объектов StringBuilder наплодится?
 
Код цикла и код StringJoiner выполняет одно и тоже, а значит - не костыль.




Сказали. И если программер не умеет делать реализации простых структур данных - такие никому не нужны.
Ваш велосипед - говно, что по производительности, что по стилю кода.

А теперь к теме тса, просто \n - символ переноса, для тех кто не знает, потому и логично что он переносит строки, правда не везде в майнкрафте есть его поддержка. Можно ещё посмотреть сколько максимум символов вмещает строка и добивать пробелами, но вот это уже изврат.
 
С
Java:
 if (i == WORD_COUNT - 1)
заорал.
Но если что, твой примитив иногда действительно быстрее.
Примитив будет быстрее только в случае 1го элемента, потому что у стрингджойнера есть накладные расходы на инициализацию стрингбилдера. Случаи до 100 элементов надо бенчить с учётом прогрева jvm, но это уже тонкости. В общем случае лучше использовать StringBuilder при конкатенации большого либо неизвестного заранее количества символов (строк).
 
Примитив будет быстрее только в случае 1го элемента
Оказывается, что нет. Он так же быстрее, если элементов больше 850 тысяч.
Java:
/**
* Little edit for much perfomance.
* @author fall.us
*/
public class Main {

    final static int WORD_COUNT = 1000000;

    public static void main(String[] args) {
        Random rand = new Random(System.currentTimeMillis());
        String[] strings = new String[WORD_COUNT];

        for (int i = 0; i < WORD_COUNT; i++) {
            strings[i] = String.valueOf(rand.nextLong());
        }
    
        long clockStrings, clockSJoiner, clockStart = System.currentTimeMillis();
    
        StringBuilder words = new StringBuilder();
        for (int i = 0; i < WORD_COUNT; i++) {
            words.append(strings[i]).append("\n");
        }

        clockStrings = System.currentTimeMillis() - clockStart;
        clockStart = System.currentTimeMillis();

        StringJoiner sj = new StringJoiner("\n");
        for (int i = 0; i < WORD_COUNT; i++) {
            sj.add(strings[i]);
        }

        clockSJoiner = System.currentTimeMillis() - clockStart;
        words = new StringBuilder();
        words.append("Overall time: ").append((clockSJoiner + clockStrings)).append(" ms\n");
        words.append("Strings: ").append(clockStrings).append(" ms\n");
        words.append("StringJoiner: ").append(clockSJoiner).append(" ms");
        System.out.println(words.toString());
    }
}
 
Оказывается, что нет. Он так же быстрее, если элементов больше 850 тысяч.
Java:
/**
* Little edit for much perfomance.
* @author fall.us
*/
public class Main {

    final static int WORD_COUNT = 1000000;

    public static void main(String[] args) {
        Random rand = new Random(System.currentTimeMillis());
        String[] strings = new String[WORD_COUNT];

        for (int i = 0; i < WORD_COUNT; i++) {
            strings[i] = String.valueOf(rand.nextLong());
        }
   
        long clockStrings, clockSJoiner, clockStart = System.currentTimeMillis();
   
        StringBuilder words = new StringBuilder();
        for (int i = 0; i < WORD_COUNT; i++) {
            words.append(strings[i]).append("\n");
        }

        clockStrings = System.currentTimeMillis() - clockStart;
        clockStart = System.currentTimeMillis();

        StringJoiner sj = new StringJoiner("\n");
        for (int i = 0; i < WORD_COUNT; i++) {
            sj.add(strings[i]);
        }

        clockSJoiner = System.currentTimeMillis() - clockStart;
        words = new StringBuilder();
        words.append("Overall time: ").append((clockSJoiner + clockStrings)).append(" ms\n");
        words.append("Strings: ").append(clockStrings).append(" ms\n");
        words.append("StringJoiner: ").append(clockSJoiner).append(" ms");
        System.out.println(words.toString());
    }
}
В другое русло пошли, господа.
 
Оказывается, что нет. Он так же быстрее, если элементов больше 850 тысяч.
Java:
/**
* Little edit for much perfomance.
* @author fall.us
*/
public class Main {

    final static int WORD_COUNT = 1000000;

    public static void main(String[] args) {
        Random rand = new Random(System.currentTimeMillis());
        String[] strings = new String[WORD_COUNT];

        for (int i = 0; i < WORD_COUNT; i++) {
            strings[i] = String.valueOf(rand.nextLong());
        }
   
        long clockStrings, clockSJoiner, clockStart = System.currentTimeMillis();
   
        StringBuilder words = new StringBuilder();
        for (int i = 0; i < WORD_COUNT; i++) {
            words.append(strings[i]).append("\n");
        }

        clockStrings = System.currentTimeMillis() - clockStart;
        clockStart = System.currentTimeMillis();

        StringJoiner sj = new StringJoiner("\n");
        for (int i = 0; i < WORD_COUNT; i++) {
            sj.add(strings[i]);
        }

        clockSJoiner = System.currentTimeMillis() - clockStart;
        words = new StringBuilder();
        words.append("Overall time: ").append((clockSJoiner + clockStrings)).append(" ms\n");
        words.append("Strings: ").append(clockStrings).append(" ms\n");
        words.append("StringJoiner: ").append(clockSJoiner).append(" ms");
        System.out.println(words.toString());
    }
}
Скорее всего аллокация памяти для стрингбилдера вызвала аллокацию памяти из системы, запускай из консоли с достаточным количеством выделенной памяти, ибо у меня на любом количестве элементов которые ещё могут влезть в массив джойнер быстрее.
 
Скорее всего аллокация памяти для стрингбилдера вызвала аллокацию памяти из системы, запускай из консоли с достаточным количеством выделенной памяти, ибо у меня на любом количестве элементов которые ещё могут влезть в массив джойнер быстрее.
Вообще интересно выходит. 349 мб рамы отъедает.
2016 06 15_14-41-08.png

Интересная картина. Но всё равно StringJoiner для плагинов будет быстрее, ибо на сервере майнкрафта не найдётся столько объектов, чтобы замедлить его (кроме блоков - они замедляют всё что можно и нельзя).
В другое русло пошли, господа.
Да плевать.
 
Вообще интересно выходит. 349 мб рамы отъедает.

Интересная картина. Но всё равно StringJoiner для плагинов будет быстрее, ибо на сервере майнкрафта не найдётся столько объектов, чтобы замедлить его (кроме блоков - они замедляют всё что можно и нельзя).
Да плевать.
Xms забыл чтобы вся память сразу выделилась.
 
Последнее редактирование:
СтрингБилдер почти всегда будет быстрее, так как конкатенация объектов String вызывает новый объект StringBuilder'а.
Хотел уже написать чзх, но потом увидел у себя очепятку. Спасибки.
 
Вот нормальный тест:
Java:
package dk.xakeps.benchmarks.strings;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@State(Scope.Thread)
@SuppressWarnings({"all"})
public class Main {

    private StringBuilder stringBuilder1;
    private StringBuilder stringBuilder2;

    private StringBuffer stringBuffer1;
    private StringBuffer stringBuffer2;

    private String string1;
    private String string2;

    /*
     * re-initializing the value after every iteration
     */
    @Setup(Level.Iteration)
    public void init() {
        stringBuilder1 = new StringBuilder("foo");
        stringBuilder2 = new StringBuilder("bar");

        stringBuffer1 = new StringBuffer("foo");
        stringBuffer2 = new StringBuffer("bar");

        string1 = "foo";
        string2 = "bar";

    }

    @State(Scope.Benchmark)
    public static class BenchmarkState {
        volatile long builderConcatCount = 1;
        volatile long bufferConcatCount = 1;
        volatile long stringPlusCount = 1;
        volatile long stringConcatCount = 1;
    }

    /*
     * want to measure the progress from call to call so using the
     * SingleShotTime mode
     */
    @Benchmark
    @Warmup(iterations = 5, batchSize = 1)
    @Measurement(iterations = 100, batchSize = 1000)
    @BenchmarkMode(Mode.SingleShotTime)
    public StringBuilder stringBuilder(BenchmarkState state) {
        StringBuilder stringBuilder = null;
        for (long j = 0; j < state.builderConcatCount; j++) {
            stringBuilder = stringBuilder1.append(stringBuilder2);
        }
        state.builderConcatCount++;
        // to avoid dead code optimization returning the value
        return stringBuilder;
    }

    @Benchmark
    @Warmup(iterations = 5, batchSize = 1)
    @Measurement(iterations = 100, batchSize = 1000)
    @BenchmarkMode(Mode.SingleShotTime)
    public StringBuffer stringBuffer(BenchmarkState state) {
        StringBuffer stringBuffer = null;
        for (long j = 0; j < state.bufferConcatCount; j++) {
            stringBuffer = stringBuffer1.append(stringBuffer2);
        }
        state.bufferConcatCount++;
        // to avoid dead code optimization returning the value
        return stringBuffer;
    }

    /*
     * want to measure the progress from call to call so using the
     * SingleShotTime mode
     */
    @Benchmark
    @Warmup(iterations = 5, batchSize = 1)
    @Measurement(iterations = 100, batchSize = 1000)
    @BenchmarkMode(Mode.SingleShotTime)
    public String stringPlus(BenchmarkState state) {
        String string = null;
        for (long j = 0; j < state.stringPlusCount; j++) {
            string = string1 + string2;
        }
        state.stringPlusCount++;
        // to avoid dead code optimization returning the value
        return string;
    }

    @Benchmark
    @Warmup(iterations = 5, batchSize = 1)
    @Measurement(iterations = 100, batchSize = 1000)
    @BenchmarkMode(Mode.SingleShotTime)
    public String stringConcat(BenchmarkState state) {
        String string = null;
        for (long j = 0; j < state.stringConcatCount; j++) {
            string = string1.concat(string2);
        }
        state.stringConcatCount++;
        // to avoid dead code optimization returning the value
        return string;
    }


    public static void main(String[] args) throws RunnerException {
        Options options = new OptionsBuilder()
                .include(Main.class.getSimpleName())
                .threads(1)
                .forks(1)
                .shouldFailOnError(true)
                .shouldDoGC(true)
                .jvmArgs("-server", "-Xmx6G", "-Xms6G", "-XX:+UseG1GC")
                .build();
        new Runner(options).run();
    }
}
Результаты:
Код:
"-server", "-Xmx6G", "-Xms2G", "-XX:+UseConcMarkSweepGC"
# Run complete. Total time: 00:06:50

Benchmark           Mode  Cnt  Score   Error  Units
Main.stringBuffer     ss  100  0,733 ± 0,142   s/op
Main.stringBuilder    ss  100  0,508 ± 0,107   s/op
Main.stringConcat     ss  100  1,160 ± 0,226   s/op
Main.stringPlus       ss  100  0,602 ± 0,117   s/op

"-server", "-Xmx6G", "-Xms6G", "-XX:+UseConcMarkSweepGC"
# Run complete. Total time: 00:06:55

Benchmark           Mode  Cnt  Score   Error  Units
Main.stringBuffer     ss  100  0,679 ± 0,123   s/op
Main.stringBuilder    ss  100  0,482 ± 0,094   s/op
Main.stringConcat     ss  100  1,221 ± 0,243   s/op
Main.stringPlus       ss  100  0,661 ± 0,132   s/op

"-server", "-Xmx6G", "-Xms2G", "-XX:+UseG1GC"
# Run complete. Total time: 00:07:58

Benchmark           Mode  Cnt  Score   Error  Units
Main.stringBuffer     ss  100  0,717 ± 0,125   s/op
Main.stringBuilder    ss  100  0,489 ± 0,091   s/op
Main.stringConcat     ss  100  1,388 ± 0,278   s/op
Main.stringPlus       ss  100  0,750 ± 0,152   s/op

"-server", "-Xmx6G", "-Xms6G", "-XX:+UseG1GC"
# Run complete. Total time: 00:08:11

Benchmark           Mode  Cnt  Score   Error  Units
Main.stringBuffer     ss  100  0,752 ± 0,149   s/op
Main.stringBuilder    ss  100  0,516 ± 0,091   s/op
Main.stringConcat     ss  100  1,300 ± 0,261   s/op
Main.stringPlus       ss  100  0,625 ± 0,118   s/op
Вывод: скорость зависит от настроек GC, а не от Xms.
 
Вот нормальный тест:
Java:
package dk.xakeps.benchmarks.strings;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

@State(Scope.Thread)
@SuppressWarnings({"all"})
public class Main {

    private StringBuilder stringBuilder1;
    private StringBuilder stringBuilder2;

    private StringBuffer stringBuffer1;
    private StringBuffer stringBuffer2;

    private String string1;
    private String string2;

    /*
     * re-initializing the value after every iteration
     */
    @Setup(Level.Iteration)
    public void init() {
        stringBuilder1 = new StringBuilder("foo");
        stringBuilder2 = new StringBuilder("bar");

        stringBuffer1 = new StringBuffer("foo");
        stringBuffer2 = new StringBuffer("bar");

        string1 = "foo";
        string2 = "bar";

    }

    @State(Scope.Benchmark)
    public static class BenchmarkState {
        volatile long builderConcatCount = 1;
        volatile long bufferConcatCount = 1;
        volatile long stringPlusCount = 1;
        volatile long stringConcatCount = 1;
    }

    /*
     * want to measure the progress from call to call so using the
     * SingleShotTime mode
     */
    @Benchmark
    @Warmup(iterations = 5, batchSize = 1)
    @Measurement(iterations = 100, batchSize = 1000)
    @BenchmarkMode(Mode.SingleShotTime)
    public StringBuilder stringBuilder(BenchmarkState state) {
        StringBuilder stringBuilder = null;
        for (long j = 0; j < state.builderConcatCount; j++) {
            stringBuilder = stringBuilder1.append(stringBuilder2);
        }
        state.builderConcatCount++;
        // to avoid dead code optimization returning the value
        return stringBuilder;
    }

    @Benchmark
    @Warmup(iterations = 5, batchSize = 1)
    @Measurement(iterations = 100, batchSize = 1000)
    @BenchmarkMode(Mode.SingleShotTime)
    public StringBuffer stringBuffer(BenchmarkState state) {
        StringBuffer stringBuffer = null;
        for (long j = 0; j < state.bufferConcatCount; j++) {
            stringBuffer = stringBuffer1.append(stringBuffer2);
        }
        state.bufferConcatCount++;
        // to avoid dead code optimization returning the value
        return stringBuffer;
    }

    /*
     * want to measure the progress from call to call so using the
     * SingleShotTime mode
     */
    @Benchmark
    @Warmup(iterations = 5, batchSize = 1)
    @Measurement(iterations = 100, batchSize = 1000)
    @BenchmarkMode(Mode.SingleShotTime)
    public String stringPlus(BenchmarkState state) {
        String string = null;
        for (long j = 0; j < state.stringPlusCount; j++) {
            string = string1 + string2;
        }
        state.stringPlusCount++;
        // to avoid dead code optimization returning the value
        return string;
    }

    @Benchmark
    @Warmup(iterations = 5, batchSize = 1)
    @Measurement(iterations = 100, batchSize = 1000)
    @BenchmarkMode(Mode.SingleShotTime)
    public String stringConcat(BenchmarkState state) {
        String string = null;
        for (long j = 0; j < state.stringConcatCount; j++) {
            string = string1.concat(string2);
        }
        state.stringConcatCount++;
        // to avoid dead code optimization returning the value
        return string;
    }


    public static void main(String[] args) throws RunnerException {
        Options options = new OptionsBuilder()
                .include(Main.class.getSimpleName())
                .threads(1)
                .forks(1)
                .shouldFailOnError(true)
                .shouldDoGC(true)
                .jvmArgs("-server", "-Xmx6G", "-Xms6G", "-XX:+UseG1GC")
                .build();
        new Runner(options).run();
    }
}
Результаты:
Код:
"-server", "-Xmx6G", "-Xms2G", "-XX:+UseConcMarkSweepGC"
# Run complete. Total time: 00:06:50

Benchmark           Mode  Cnt  Score   Error  Units
Main.stringBuffer     ss  100  0,733 ± 0,142   s/op
Main.stringBuilder    ss  100  0,508 ± 0,107   s/op
Main.stringConcat     ss  100  1,160 ± 0,226   s/op
Main.stringPlus       ss  100  0,602 ± 0,117   s/op

"-server", "-Xmx6G", "-Xms6G", "-XX:+UseConcMarkSweepGC"
# Run complete. Total time: 00:06:55

Benchmark           Mode  Cnt  Score   Error  Units
Main.stringBuffer     ss  100  0,679 ± 0,123   s/op
Main.stringBuilder    ss  100  0,482 ± 0,094   s/op
Main.stringConcat     ss  100  1,221 ± 0,243   s/op
Main.stringPlus       ss  100  0,661 ± 0,132   s/op

"-server", "-Xmx6G", "-Xms2G", "-XX:+UseG1GC"
# Run complete. Total time: 00:07:58

Benchmark           Mode  Cnt  Score   Error  Units
Main.stringBuffer     ss  100  0,717 ± 0,125   s/op
Main.stringBuilder    ss  100  0,489 ± 0,091   s/op
Main.stringConcat     ss  100  1,388 ± 0,278   s/op
Main.stringPlus       ss  100  0,750 ± 0,152   s/op

"-server", "-Xmx6G", "-Xms6G", "-XX:+UseG1GC"
# Run complete. Total time: 00:08:11

Benchmark           Mode  Cnt  Score   Error  Units
Main.stringBuffer     ss  100  0,752 ± 0,149   s/op
Main.stringBuilder    ss  100  0,516 ± 0,091   s/op
Main.stringConcat     ss  100  1,300 ± 0,261   s/op
Main.stringPlus       ss  100  0,625 ± 0,118   s/op
Вывод: скорость зависит от настроек GC, а не от Xms.
2гб - максимальный размер строки, аллокации лишней системной памяти так и так не произойдёт, xms надо вообще уносить, тогда совсем небольшая разница будет на малых количествах итераций. И прогрев надо тогда отрубать.
Кстати судя по результатам теста jvm в итоге плюс таки превратила в стрингбилдер, дампани выхлоп jit, да и байткод не помешал бы.
 
2гб - максимальный размер строки, аллокации лишней системной памяти так и так не произойдёт, xms надо вообще уносить, тогда совсем небольшая разница будет на малых количествах итераций. И прогрев надо тогда отрубать.
Кстати судя по результатам теста jvm в итоге плюс таки превратила в стрингбилдер, дампани выхлоп jit, да и байткод не помешал бы.
Ага, что-то не подумал об этом. Потом сделаю тесты заново.
 
А не, сам тестовый код косячный, ты скадываешь две строки каждый раз, в итоге тест тестит только скорость операций, нам же надо складывать всё в одну большую строку чтобы увидеть влияние сайд эффектов.
 
Статус
Закрыто для дальнейших ответов.
Назад
Верх