Неправильная работа joiner`a

Доброе время суток. Делаю простейшую программу по шифрованию теста. Нужно каждых два символа поменять местами и переместится на два символа вперёд (по отношению к первому). Код, который это делает, работает, но в JTextArea выводиться только конечных два символа (предполагаю, что это из-за цикла while, но не понимаю, почему joiner не может объединить все пузырьки в один текст последовательно и вывести preResult).

P.S System.out.print выводит всё корректно.

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.StringJoiner;

public class Main {

    public static void main(String[] args) {

        JFrame frame = new JFrame();
        frame.setSize(500,417);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);

        JPanel panel = new JPanel();
        panel.setLayout(null);
        frame.add(panel);

        JTextArea input_text = new JTextArea();
        input_text.setBounds(5,5,475, 150);
        input_text.setWrapStyleWord(true);
        input_text.setLineWrap(true);
        panel.add(input_text);

        JTextArea output_text = new JTextArea();
        output_text.setBounds(5,220,475, 150);
        output_text.setWrapStyleWord(true);
        output_text.setEditable(false);
        output_text.setLineWrap(true);
        panel.add(output_text);

        JButton crypt_button = new JButton("Crypt");
        crypt_button.setBounds(10,163,100,50);
        panel.add(crypt_button);

        JButton uncrypt_button = new JButton("Uncrypt");
        uncrypt_button.setBounds(375,163,100,50);
        panel.add(uncrypt_button);

        crypt_button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                String text = input_text.getText();
                int lenght = text.length();

                int x = 0;
                int y = 1;

                String inter_x_1 = null;
                String inter_y_2 = null;

                int counter = 0;
                while (counter < lenght) {

                    char x_1 = text.charAt(x);
                    inter_x_1 =String.valueOf(x_1);
                    char y_2 = text.charAt(y);
                    inter_y_2 =String.valueOf(y_2);

                    x+=2;
                    y+=2;
                    counter += 2;

                    StringJoiner joiner = new StringJoiner("");
                    joiner.add(inter_y_2 + inter_x_1);
                    String bubble = joiner.toString();

                    StringJoiner joiner_1 = new StringJoiner("");
                    joiner_1.add(joiner_1 + bubble);
                    String preResult = joiner_1.toString();

                    output_text.setText(preResult);
                    System.out.print(preResult);

                }
            }
        });
        frame.setVisible(true);
    }
}

Ответы (1 шт):

Автор решения: Alex Rudenko

System.out.print выводит последовательно все пары в поток вывода.

Когда выполняется output_text.setText(preResult);, то в текстовый компонент записывается только последняя пара переставленных букв.

Для аналогии с System.out.print можно было бы добавлять текст:

output_text.setText(output_text.getText() + preResult);

Или накапливать результат в экземпляре StringBuilder и затем записать его после цикла while:

StringBuilder sb = new StringBuilder();

while (counter < lenght) {
// ...
    // output_text.setText(preResult); // убрать эту строку
    sb.append(preResult);
}
output_text.setText(sb.toString());

В целом, сама реализация данной задачи может быть значительно упрощена, так как нет никакой необходимости использовать два джойнера и постоянные преобразования в строку, если можно просто в цикле просто добавлять в StringBuilder переставленные пары символов.
Кроме того, в показанном коде может возникнуть исключение StringIndexOutOfBoundsException, когда длина входной строки -- нечётное число.

Примерная реализация:

private static String encryptGood(String text) {
    
    StringBuilder sb = new StringBuilder();
    
    int n = text.length() - 1;
    for (int i = 0; i < n; i += 2) {
        sb.append(text.charAt(i + 1)).append(text.charAt(i));
    }
    if (n % 2 == 0) { // добавить последний оставшийся символ при нечётной длине
        sb.append(text.charAt(n));
    }
    
    return sb.toString();
}

Тесты:

for (String txt : Arrays.asList("AB", "x", "TestEncrypt")) {
  System.out.println("encrypt(" + txt+ ") = " + encryptGood(txt));
}

Результаты:

encrypt(AB) = BA
encrypt(x) = x
encrypt(TestEncrypt) = eTtsnErcpyt

Тогда обработчик actionPerformed может быть переписан как:

public void actionPerformed(ActionEvent ae) {
    output_text.setText(encryptGood(input_text.getText()));
}
→ Ссылка