Печать с паузой, не работающей в Java

Я пытаюсь получить программу, написанную в java, для вывода текстового письма по букве с паузой между каждой буквой. Кодовое слово обертывает строку и печатает ее. Мой метод задержки "slow()" работает хорошо, когда задержка составляет половину секунды или секунду, но при более низких задержках она делает некоторые странные вещи.

Когда печать и задержка являются слишком короткими, программа зависает на этой строке для времени задержки количества печатаемых букв до того, как линия вернется, а затем выплевывает все сразу.

Также, когда для задержки установлено значение 250 миллисекунд, текст также выводится неверно.

В примере строка:

"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla vitae molestie leo, sed molestie turpis."

Ожидаемый результат:

Lorem ipsum dolor sit amet, consectetur adipiscing
Элит. Nulla vitae molestie leo, sed molestie turpis.

Но выход 250 равен:

Lrem ipsum dolrst aet, adetiscing conseteur
Элит. ulla vitae olestie lo sed oleste turis.

Здесь код:

public static void main(String[] args) {
    String x = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla vitae molestie leo, sed molestie turpis.";
    say(500,x); // Works Nicely, does one letter at a time with a 0.5s wait in between.
    System.out.println();
    say(250,x); // Has proper delay, but prints strange stuff
    System.out.println();
    say(100,x); // Prints Line by line with a wait of (letters*0.1s) wait in between.
}

public static void say(int speed, String words) {
    int i = 0;
    int ii = 0;
    while (i < words.length()) {
        slow(speed);
        System.out.print("" + words.charAt(i));
        if (ii >= 50 && words.charAt(i) == ' ') {
            System.out.println(words.charAt(i));
            ii = 0;
        } else {
            ii++;
        }
        i++;
    }
    System.out.println(" ");
}

public static void slow(int time) {
    try {
        Thread.sleep(time);
    } catch(InterruptedException ex) {
        Thread.currentThread().interrupt();
    }
}

Альтернативный метод slow() с такими же ошибками:

public static void slow(int time) {
    long startTime = System.currentTimeMillis();
    while(System.currentTimeMillis() - startTime < time) {

    }
}

Я не уверен, что это важно, но все это делается в NetBeans 7.4 x64 с JDK 1.7.

Я новичок в Java, но не новичок в программировании. Любая помощь будет оценена! Основная проблема - это время, это то, что мне нужно для работы; Странная печать - это просто вопрос.

Ответ 1

Это запах рыбный. Ваш код выглядит хорошо и отлично работает для меня, запустив его из командной строки. Я думаю, как сказал Джим Гаррисон, это связано с вашей средой. Вы пытались запустить свою программу из командной строки, чтобы оставить Netbeans из нее?

Следующее, что я подозреваю, это строка Thread.currentThread().interrupt(); в вашем блоке catch(InterruptedException ex). Попробуйте прокомментировать это (и ничего не делайте, за исключением, возможно, печати трассировки стека InterruptedException (ex.printStackTrace()).

Ответ 2

Идиоматическое решение с использованием Timer/TimerTask:

Идиоматические примечания:

  • Использование BreakIterator для разделения текста.
  • Использование Timer/TimerTask для управления задержками.
  • Использование AtomicLong для потокобезопасного общего объекта.

Q23794090.java

import javax.annotation.Nonnull;
import java.text.BreakIterator;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicLong;

public class Q23794090
{
    private static final Timer TIMER = new Timer();
    private static AtomicLong DELAY = new AtomicLong(0L);

    private static void say(final long delay, @Nonnull final String value, @Nonnull final BreakIterator bi)
    {
        bi.setText(value);
        int start = bi.first();
        int end = bi.next();

        while (end != BreakIterator.DONE)
        {
            final String s = value.substring(start, end);
            TIMER.schedule(new TimerTask()
            {
                @Override
                public void run()
                {
                    System.out.print(s);
                }
            }, DELAY.addAndGet(delay));
            start = end;
            end = bi.next();
        }
        TIMER.schedule(new TimerTask()
        {
            @Override
            public void run()
            {
                System.out.println();
                System.out.println("========================");
            }
        }, DELAY.addAndGet(0));
    }

    public static void main(final String[] args)
    {
        final String x = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla vitae molestie leo, sed molestie turpis.";
        say(250, x, BreakIterator.getCharacterInstance());
        say(500, x, BreakIterator.getWordInstance());
        say(1000, x, BreakIterator.getSentenceInstance());
        TIMER.schedule(new TimerTask()
        {
            @Override
            public void run()
            {
                TIMER.cancel();
            }
        }, DELAY.addAndGet(1000));
        try { Thread.currentThread().join(); } 
        catch (InterruptedException e) { throw new RuntimeException(e); }
    }
}

Работает в Intellij Idea 13.x

В консоли, поэтому нет проблем с вызовом System.out.flush() любой такой глупости.

Что нужно улучшить:

  • BreakIterator factory принимают необязательный Locale, так как нет Latin, который я мог бы найти легко, я просто позволяю ему использовать значение по умолчанию. В моем случае это en_US. Ваше возражение может отличаться.