Выровнять строки для вывода

Я написал класс, который может форматировать ввод так, чтобы он был правильно выровнен.

Меня интересуют все предложения (относительно структуры, удобства использования, стиля, имен, комментариев и т. д.).

Мне особенно интересно:

  • Есть ли лучший способ написать тесты? Я хочу сначала проверить класс Content, а затем проверить Align (так что, когда возникает ошибка, я сразу вижу, где она). Прямо сейчас, я в основном просто скопировал теги Content (add и set) и добавление align.output((String s) -> nothing());. Это не похоже на правильный способ сделать это.

Пример использования

   public static void main(String[] args) {
       Align align = new Align();
       // header
       align.addLine("Name", "Age", "Address", "Phone");

       // data
       align.addLine("Alice", "32", "United States", "555-123456");
       align.addLine("Bob", "12", "nowhere", "555-123456");
       align.addLine("Carol", "78", "1080 Maple Court Cape Girardeau, MO 63701", "555-123456");
       align.addLine("Ed", "159", "Fake Stree, Fakesville");

       // output
        align.output((String s) -> System.out.println(s));

       // add a forgotten column
       align.addColumn(3, "Hair Color", "Red", "Brown", "Blue", "Purple", "Orange");
       align.output((String s) -> System.out.println(s));
    }

Вывод:

 Name     Age     Address                                       Phone     
Alice    32      United States                                 555-123456
Bob      12      nowhere                                       555-123456
Carol    78      1080 Maple Court Cape Girardeau, MO 63701     555-123456
Ed       159     Fake Stree, Fakesville                        -         

Name     Age     Address                                       Hair Color     Phone     
Alice    32      United States                                 Red            555-123456
Bob      12      nowhere                                       Brown          555-123456
Carol    78      1080 Maple Court Cape Girardeau, MO 63701     Blue           555-123456
Ed       159     Fake Stree, Fakesville                        Purple         -         
-        -       -                                             Orange         -  

Выровнять класс:

 import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class Align {

    private String paddingChar = "-";
    private int minSpacing = 5;

    protected Content content;

    public Align() {
        content = new Content();
    }

    /**
     * set the character that is used for values that don't exist.
     *
     * @param paddingChar padding char
     */
    public void setPaddingChar(String paddingChar) {
        this.paddingChar = paddingChar;
    }

    /**
     * the minimum amount of spaces between columns in the formated output.
     *
     * Must be at least 0, but a minimum of at least 1 is suggested.
     *
     * @param minSpacing minimum of spaces (must be at least 0)
     */
    public void setMinSpacing(int minSpacing) {
        if (minSpacing < 0) {
            throw new IllegalArgumentException("min spacing must be at least 0");
        }

        this.minSpacing = minSpacing;
    }

    public void addLine(int position, List<String> lineContent) {
        content.addLine(position, lineContent);
    }

    public void addLine(List<String> lineContent) {
        addLine(content.lineCount(), lineContent);
    }

    public void addLine(String... lineContent) {
        addLine(content.lineCount(), new ArrayList<>(Arrays.asList(lineContent)));
    }

    public void addLine(int position, String... lineContent) {
        addLine(position, new ArrayList<>(Arrays.asList(lineContent)));
    }

    public void addColumn(int position, List<String> columnContent) {
        content.addColumn(position, columnContent);
    }

    public void addColumn(List<String> columnContent) {
        addColumn(content.columnCount(), columnContent);
    }

    public void addColumn(String... columnContent) {
        addColumn(content.columnCount(), new ArrayList<>(Arrays.asList(columnContent)));
    }

    public void addColumn(int position, String... columnContent) {
        addColumn(position, new ArrayList<>(Arrays.asList(columnContent)));
    }

    /**
     * sets the value at the given column and row to the given content.
     *
     * If the value doesn't exist already, an IllegalArgumentException will be
     * thrown.
     *
     * @param column column
     * @param row row
     * @param value value
     */
    public void set(int column, int row, String value) {
        content.set(column, row, value);
    }

    /**
     * passes the formated string to consumer.
     *
     * To get the formated string, use toString.
     *
     * @param consumer consumer
     */
    public void output(Consumer<String> consumer) {
        consumer.accept(toString());
    }

    @Override
    public String toString() {
        List<Integer> maxContentLength = getMaxLengths();
        List<String> spaces = getSpaces(maxContentLength);

        StringBuilder out = new StringBuilder();
        for (Content.Line line : content.lines) {
            for (int columnIndex = 0; columnIndex < line.size(); columnIndex++) {
                String column = line.get(columnIndex);
                out.append(column);
                out.append(spaces.get(columnIndex)
                        .substring(0,
                                spaces.get(columnIndex).length()
                                - column.length())); // align
            }
            out.append("\n");
        }
        return out.toString();
    }

    /**
     * returns a list of spaces of the given lengths.
     *
     * @param lengths lengths
     * @return list of spaces
     */
    private List<String> getSpaces(List<Integer> lengths) {
        List<String> spaces = new ArrayList<>();
        for (Integer length : lengths) {
            spaces.add(getSpaces(length));
        }
        return spaces;
    }

    /**
     * returns n spaces.
     *
     * @param n number of spaces
     * @return n spaces
     */
    private static String getSpaces(int n) {
        StringBuilder spaces = new StringBuilder(n);
        for (int i = 0; i < n; i++) {
            spaces.append(" ");
        }
        return spaces.toString();
    }

    /**
     * returns a list containing the length of the longest string of each
     * column.
     *
     * @return lengths
     */
    private List<Integer> getMaxLengths() {
        List<Integer> maxContentLength = new ArrayList<>();
        for (int i = 0; i <= content.columnCount(); i++) {
            maxContentLength.add(0); // init max length with 0
        }

        for (Content.Line line : content.lines) {
            for (int columnIndex = 0; columnIndex < content.columnCount(); columnIndex++) {
                String column = line.get(columnIndex);
                if (column.length() > maxContentLength.get(columnIndex)) {
                    maxContentLength.set(columnIndex, column.length() + minSpacing);
                }
            }
        }
        return maxContentLength;
    }

    protected class Content {

        private List<Line> lines;

        public Content() {
            lines = new ArrayList<>();
        }

        /**
         * returns number of lines.
         *
         * @return number of lines
         */
        public int lineCount() {
            return lines.size();
        }

        /**
         * returns number of columns.
         *
         * @return number of columns
         */
        public int columnCount() {
            if (lines.isEmpty()) {
                return 0;
            }
            return lines.get(0).size(); // all lines are the same length
        }

        public void set(int column, int row, String value) {
            if (row < 0 || row > lineCount()) {
                throw new IllegalArgumentException("row doesn't exist");
            }
            Line line = lines.get(row);
            if (column < 0 || column > columnCount()) {
                throw new IllegalArgumentException("column doesn't exist");
            }
            line.set(column, value);
        }

        public void addColumn(int position, List<String> columnContent) {
            if (position < 0) {
                throw new IllegalArgumentException("Column position is negative");
            }

            // if the new position is outside the current content, extend short lines to position
            if (position > columnCount()) {
                for (Line line : lines) {
                    padTo(line, position);
                }
            }

            // add new lines for content of this column in case the column is too long
            while (lines.size() < columnContent.size()) {
                Line newLine = new Line(new ArrayList<>());
                padTo(newLine, position); // if the current line is new, and thus too short, pad it
                lines.add(newLine);
            }

            for (int i = 0; i < columnContent.size(); i++) {
                Line line = lines.get(i);
                line.add(position, columnContent.get(i)); // add actual content of column
            }

            if (columnContent.size() > columnCount()) {
                for (Line line : lines) {
                    padTo(line, content.columnCount());
                }
            }

            // if the column was shorter then previous once, shift the rest of the lines and insert padding char for the new column
            if (columnContent.size() < lines.size()) {
                shift(position, lines.subList(columnContent.size(), lines.size()));
            }
        }

        public void addLine(int position, List<String> lineContent) {
            if (position < 0) {
                throw new IllegalArgumentException("Line position is negative");
            }

            // add elements to this line if it is too short
            padTo(lineContent, columnCount());

            if (lineContent.size() > columnCount()) { // add elements to all other lines if this line is the new longest line
                for (Line line : lines) {
                    padTo(line, lineContent.size()); // padd to new longest line
                }
            }

            while (lines.size() < position) { // add new empty lines if this line is outside field
                List<String> emptyLineContent = new ArrayList<>();
                for (int i = 0; i < columnCount(); i++) {
                    emptyLineContent.add(paddingChar);
                }
                lines.add(new Line(emptyLineContent));
            }
            lines.add(position, new Line(lineContent)); // add actual line
        }

        /**
         * shifts all given lines at given position one entry to the right.
         *
         * The padding character will be inserted at the new position.
         *
         * @param position position
         * @param list list
         */
        private void shift(int position, List<Line> list) {
            for (Line line : list) {
                line.add(position, paddingChar);
            }
        }

        /**
         * add elements to given line until its length is the given max.
         *
         * @param line line
         * @param max max
         */
        private void padTo(List<String> line, int max) {
            while (line.size() < max) {
                line.add(paddingChar);
            }
        }

        private class Line extends ArrayList<String> {
            public Line(List<String> line) {
                super(line);
            }
        }
    }
}

Тесты:

 import org.junit.Test;

public class AlignTest {

    private static Align getAlign(int columns, int rows) {
        Align align = new Align();
        for (int i = 0; i < rows; i++) {
            String[] row = new String[columns];
            for (int j = 0; j < columns; j++) {
                row[j] = String.valueOf(i) + String.valueOf(j);
            }
            align.addLine(row);
        }
        return align;
    }

    /** TEST CONTENT **/

    @Test(expected=IllegalArgumentException.class)
    public void setNegativeColumn() {
        getAlign(2, 3).set(-1, 1, "new value");
    }

    @Test(expected=IllegalArgumentException.class)
    public void setNonExistingColumn() {
        getAlign(2, 3).set(20, 1, "new value");
    }

    @Test(expected=IllegalArgumentException.class)
    public void setNegativeLine() {
        getAlign(2, 3).set(1, -1, "new value");
    }

    @Test(expected=IllegalArgumentException.class)
    public void setNonExistingLine() {
        getAlign(2, 3).set(1, 20, "new value");
    }

    @Test()
    public void setExisting() {
        getAlign(2, 3).set(1, 1, "new value");
    }

    @Test()
    public void setExistingCornerCases() {
        getAlign(3, 3).set(0, 1, "new value");
        getAlign(3, 3).set(1, 0, "new value");
        getAlign(3, 3).set(1, 2, "new value");
        getAlign(3, 3).set(2, 1, "new value");
    }

    @Test(expected=IllegalArgumentException.class)
    public void addNegativeColumn() {
        getAlign(2, 3).addColumn(-1, "new");
    }

    @Test(expected=IllegalArgumentException.class)
    public void addNegativeLine() {
        getAlign(2, 3).addLine(-1, "new");
    }

    @Test()
    public void addShortColumn() {
        getAlign(2, 3).addColumn(1, "new");
    }

    @Test()
    public void addShortColumnOutsideField() {
        getAlign(2, 3).addColumn(5, "new");
    }

    @Test()
    public void addLongColumn() {
        getAlign(2, 3).addColumn(1, "new", "new", "new", "new", "new");
    }

    @Test()
    public void addLongColumnOutsideField() {
        getAlign(2, 3).addColumn(5, "new", "new", "new", "new", "new");
    }

    @Test()
    public void addShortLine() {
        getAlign(2, 3).addLine(1, "new");
    }

    @Test()
    public void addShortLineOutsideField() {
        getAlign(2, 3).addLine(5, "new");
    }

    @Test()
    public void addLongLine() {
        getAlign(2, 3).addLine(1, "new", "new", "new", "new", "new");
    }

    @Test()
    public void addLongLineOutsideField() {
        getAlign(2, 3).addLine(5, "new", "new", "new", "new", "new");
    }

    /** TEST ALIGN **/

    @Test()
    public void outputSetExisting() {
        Align align = getAlign(2, 3);
        align.set(1, 1, "new value");
        align.output((String s) -> nothing(s));
    }

    @Test()
    public void outputAddShortColumn() {
        Align align = getAlign(2, 3);
        align.addColumn(1, "new");
        align.output((String s) -> nothing(s));
    }

    @Test()
    public void outputAddShortColumnOutsideField() {
        Align align = getAlign(2, 3);
        align.addColumn(5, "new");
        align.output((String s) -> nothing(s));
    }

    @Test()
    public void outputAddLongColumn() {
        Align align = getAlign(2, 3);
        align.addColumn(1, "new", "new", "new", "new", "new");
        align.output((String s) -> nothing(s));
    }

    @Test()
    public void outputAddLongColumnOutsideField() {
        Align align = getAlign(2, 3);
        align.addColumn(5, "new", "new", "new", "new", "new");
        align.output((String s) -> nothing(s));
    }

    @Test()
    public void outputAddShortLine() {
        Align align = getAlign(2, 3);
        align.addLine(1, "new");
        align.output((String s) -> nothing(s));
    }

    @Test()
    public void outputAddShortLineOutsideField() {
        Align align = getAlign(2, 3);
        align.addLine(5, "new");
        align.output((String s) -> nothing(s));
    }

    @Test()
    public void outputAddLongLine() {
        Align align = getAlign(2, 3);
        align.addLine(1, "new", "new", "new", "new", "new");
        align.output((String s) -> nothing(s));
    }

    @Test()
    public void outputAddLongLineOutsideField() {
        Align align = getAlign(2, 3);
        align.addLine(5, "new", "new", "new", "new", "new");
        align.output((String s) -> nothing(s));
    }

    public void nothing(String s) {
        //System.out.println(s + "\n\n");
    }
}
11 голосов | спросил tim 1 +04002014-10-01T19:31:49+04:00312014bEurope/MoscowWed, 01 Oct 2014 19:31:49 +0400 2014, 19:31:49

4 ответа


10

Вы можете упростить это:

align.output((String s) -> nothing(s));

в более короткую форму:

align.output(this::nothing);

Но важно то, что, как вы уже догадались, печать из модульных тестов - это не то, что нужно делать. Вы должны преобразовать печать в утверждения, например:

@Test()
public void outputAddShortLineOutsideField() {
    Align align = getAlign(2, 3);
    align.addLine(5, "new");
    assertEquals(
            "00     01     \n" +
            "10     11     \n" +
            "20     21     \n" +
            "-      -      \n" +
            "-      -      \n" +
            "new    -      \n", align.toString());
}

@Test()
public void outputAddLongColumn() {
    Align align = getAlign(2, 3);
    align.addColumn(1, "new", "new", "new", "new", "new");
    assertEquals(
            "00     new     01     \n" +
            "10     new     11     \n" +
            "20     new     21     \n" +
            "-      new     -      \n" +
            "-      new     -      \n", align.toString());
}

Я рекомендую заменить все строки align.output(this::nothing); следующим образом:

assertEquals("", align.toString());

Запустите его (много сбоев), ваша среда IDE должна печатать (где-то) сообщение об ошибке с ожидаемыми и фактическими значениями. Если фактические значения выглядят так, как вы ожидали, скопируйте пасту в модульный тест. Повторите все тесты, и все готово. (... или пойти дальше и реорганизовать еще немного; -)

Кстати, я думаю, что неплохо использовать toString для форматирования. Было бы лучше переместить логику форматирования на другой метод (.format()?) И сделать .toString() больше "технических".

Кроме того, я думаю, что Align не является отличным именем. Что-то вроде TabularTextBuilder или просто TableBuilder будет лучше. И может иметь смысл заимствовать идеи из шаблона Builder, делая addLine return this вместо void, так что вы можете связать все .addLine(...) (и другие), заканчивающиеся на вызов .format(), который возвращает форматированный текст .

ответил janos 2 +04002014-10-02T10:51:26+04:00312014bEurope/MoscowThu, 02 Oct 2014 10:51:26 +0400 2014, 10:51:26
5

Концепция здесь велика, мне она нравится, и я могу видеть ее полезную для нее.

Класс Content не нужен, это просто логический контейнер, который не добавляет значения. Все методы в Align просто передают Content в любом случае, и есть ровно один контент для Align. Вместо Content, вы могли бы просто иметь List<Line> и сделать логику там более приватной .... Я не уверен, почему Content был защищен в любом случае.

Может быть небольшое преимущество в производительности для отслеживания максимальных размеров каждого столбца при добавлении данных и условного пересчета, если данные удалены или установлены (и удаленное значение имеет тот же размер, что и max для этой колонки).

Вероятно, вы можете сэкономить достаточный объем памяти, если вы предварительно рассчитали размер StringBuilder в toString():

int rowwidth = maxContentLength.stream().sum();
rowwidth += (maxContentLength.size() - 1) * 1 + 1; // spaces between columns and a newline
int charcount = rowwidth * lines.size();
StringBuilder out = new StringBuilder(charcount);
StringBuilder out = new StringBuilder();
ответил rolfl 1 +04002014-10-01T20:21:57+04:00312014bEurope/MoscowWed, 01 Oct 2014 20:21:57 +0400 2014, 20:21:57
3

Изменения:

  • более согласован с использованием Line вместо List<String> в Table (ранее называемый Content)
  • выделил некоторые функции для функций
  • изменил, как работает addColumn (я думаю, немного проще сменить все строки, чтобы выделить место для столбца, а затем установить значения) литий>

Из других ответов:

  • предварительный расчет StringBuilder size
  • переместить связанный с линией код на Line
  • protected -> private
  • не используйте toString для форматирования
  • обновленные тесты
  • новое имя для Align и Content
  • return this вместо void для методов add
  • объекты могут быть добавлены напрямую с помощью formater

FormatedTableBuilder

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class FormatedTableBuilder {

    private String paddingChar = "-";
    private int minSpacing = 5;

    private Table table;

    public FormatedTableBuilder() {
        table = new Table();
    }

    /**
     * set the character that is used for values that don't exist.
     *
     * @param paddingChar padding char
     */
    public void setPaddingChar(String paddingChar) {
        this.paddingChar = paddingChar;
    }

    /**
     * the minimum amount of spaces between columns in the formated output.
     *
     * Must be at least 0, but a minimum of at least 1 is suggested.
     *
     * @param minSpacing minimum of spaces (must be at least 0)
     */
    public void setMinSpacing(int minSpacing) {
        if (minSpacing < 0) {
            throw new IllegalArgumentException("min spacing must be at least 0");
        }
        this.minSpacing = minSpacing;
    }

    public interface Formater<T> {
        String[] format(T object);
    }

    public <T> FormatedTableBuilder add(List<T> objects, Formater<T> formater) {
        objects.forEach((T object) -> addLine(formater.format(object)));
        return this;
    }

    public FormatedTableBuilder addLine(int position, List<String> lineContent) {
        table.addLine(position, new Line(lineContent));
        return this;
    }

    public FormatedTableBuilder addLine(List<String> lineContent) {
        return addLine(table.lineCount(), lineContent);
    }

    public FormatedTableBuilder addLine(String... lineContent) {
        return addLine(table.lineCount(), new ArrayList<>(Arrays.asList(lineContent)));
    }

    public FormatedTableBuilder addLine(int position, String... lineContent) {
        return addLine(position, new ArrayList<>(Arrays.asList(lineContent)));
    }

    public FormatedTableBuilder addColumn(int position, List<String> columnContent) {
        table.addColumn(position, columnContent);
        return this;
    }

    public FormatedTableBuilder addColumn(List<String> columnContent) {
        return addColumn(table.columnCount(), columnContent);
    }

    public FormatedTableBuilder addColumn(String... columnContent) {
        return addColumn(table.columnCount(), new ArrayList<>(Arrays.asList(columnContent)));
    }

    public FormatedTableBuilder addColumn(int position, String... columnContent) {
        return addColumn(position, new ArrayList<>(Arrays.asList(columnContent)));
    }

    /**
     * sets the value at the given column and row to the given content.
     *
     * If the value doesn't exist already, an IllegalArgumentException will be
     * thrown.
     *
     * @param column column
     * @param row row
     * @param value value
     * @return this builder
     */
    public FormatedTableBuilder set(int column, int row, String value) {
        table.set(column, row, value);
        return this;
    }

    /**
     * passes the formated string to consumer.
     *
     * To get the formated string, use format.
     *
     * @param consumer consumer
     */
    public void output(Consumer<String> consumer) {
        consumer.accept(format());
    }

    /**
     * formats all given content so it presents as a well aligned table.
     *
     * @return formated content
     */
    public String format() {
        List<Integer> maxContentLength = getMaxLengths();
        List<String> spaces = getSpaces(maxContentLength);

        // calculate stringbuilder size
        int rowwidth = maxContentLength.stream().mapToInt(i -> i).sum();
        rowwidth += (table.columnCount() - 1) * minSpacing + 1; // spaces between columns and a newline
        int charCount = rowwidth * table.lineCount();

        StringBuilder out = new StringBuilder(charCount);
        for (Line line : table.lines) {
            for (int columnIndex = 0; columnIndex < line.size(); columnIndex++) {
                String spacesForCurrentColumn = spaces.get(columnIndex);
                String column = line.get(columnIndex);
                out.append(column);
                out.append(spacesForCurrentColumn
                        .substring(0,
                                spacesForCurrentColumn.length()
                                - column.length())); // align
            }
            out.append("\n");
        }
        return out.toString();
    }

    @Override
    public String toString() {
        StringBuilder out = new StringBuilder();
        table.lines.forEach(line -> {
            line.forEach(
                    field -> out.append(field).append("            "));
            out.append("\n");
        });
        return out.toString();
    }

    /**
     * returns a list of spaces of the given lengths.
     *
     * @param lengths lengths
     * @return list of spaces
     */
    private List<String> getSpaces(List<Integer> lengths) {
        List<String> spaces = new ArrayList<>();
        lengths.forEach(length -> spaces.add(getSpaces(length)));
        return spaces;
    }

    /**
     * returns n spaces.
     *
     * @param n number of spaces
     * @return n spaces
     */
    private static String getSpaces(int n) {
        StringBuilder spaces = new StringBuilder(n);
        for (int i = 0; i < n; i++) {
            spaces.append(" ");
        }
        return spaces.toString();
    }

    /**
     * returns a list containing the length of the longest string of each
     * column.
     *
     * @return lengths
     */
    private List<Integer> getMaxLengths() {
        List<Integer> maxContentLength = new ArrayList<>();
        for (int i = 0; i < table.columnCount(); i++) {
            maxContentLength.add(0); // init max length with 0
        }

        for (Line line : table.lines) {
            for (int columnIndex = 0; columnIndex < table.columnCount(); columnIndex++) {
                String column = line.get(columnIndex);
                if (column.length() > maxContentLength.get(columnIndex)) {
                    maxContentLength.set(columnIndex, column.length() + minSpacing);
                }
            }
        }
        return maxContentLength;
    }

    private class Table {

        private List<Line> lines;

        public Table() {
            lines = new ArrayList<>();
        }

        public int lineCount() {
            return lines.size();
        }

        public int columnCount() {
            if (lines.isEmpty()) {
                return 0;
            }
            return lines.get(0).size(); // all lines are always the same length because of padding
        }

        public void set(int column, int row, String value) {
            if (row < 0 || row > lineCount()) {
                throw new IllegalArgumentException("row doesn't exist");
            }
            Line line = lines.get(row);
            if (column < 0 || column > columnCount()) {
                throw new IllegalArgumentException("column doesn't exist");
            }
            line.set(column, value);
        }

        public void addColumn(int position, List<String> columnContent) {
            if (position < 0) {
                throw new IllegalArgumentException("Column position is negative");
            }

            // if the new position is outside the current content, extend short lines to position
            if (position > columnCount()) {
                padLinesTo(position);
            }

            // add new lines for content of this column in case the column is too long
            while (lines.size() < columnContent.size()) {
                addLinePaddedTo(position);
            }

            shiftAllAt(position, lines); // make space for new column
            for (int lineIndex = 0; lineIndex < columnContent.size(); lineIndex++) { // add new column
                set(position, lineIndex, columnContent.get(lineIndex));
            }

            if (columnContent.size() > columnCount()) {
                padLinesTo(table.columnCount());
            }
        }

        public void addLine(int position, List<String> columnContent) {
            Line newLine = new Line(columnContent);
            if (position < 0) {
                throw new IllegalArgumentException("Line position is negative");
            }

            // add elements to this line if it is too short
            newLine.padTo(columnCount());

            if (newLine.size() > columnCount()) { // add elements to all other lines if bew line is the new longest line
                padLinesTo(newLine.size()); // padd to new longest line
            }

            while (lines.size() < position) { // add new padded empty lines if new line is outside field
                addLinePaddedTo(columnCount());
            }
            lines.add(position, newLine); // add actual line
        }

        /**
         * adds a new line to the end of the content, padded to the given
         * position.
         *
         * @param padTo padTo
         */
        private void addLinePaddedTo(int padTo) {
            Line emptyLine = new Line();
            emptyLine.padTo(padTo);
            lines.add(emptyLine);
        }

        /**
         * adds padding char to all lines until they are the given length.
         *
         * @param padTo padTo
         */
        private void padLinesTo(int padTo) {
            lines.forEach(line -> line.padTo(padTo));
        }

        /**
         * shifts all given lines at given position one entry to the right.
         *
         * The padding character will be inserted at the new position.
         *
         * @param position position
         * @param list list
         */
        private void shiftAllAt(int position, List<Line> list) {
            list.forEach(line -> line.shiftAt(position));
        }
    }

    private class Line extends ArrayList<String> {

        public Line() {
            super();
        }

        public Line(List<String> line) {
            super(line);
        }

        /**
         * add padding char to this line until its length is the given max.
         *
         * @param max max
         */
        private void padTo(int max) {
            while (this.size() < max) {
                this.add(paddingChar);
            }
        }

        /**
         * inserts the padding char at the given position, thus shifting the
         * rest of the line one position to the right.
         *
         * @param position position
         */
        private void shiftAt(int position) {
            this.add(position, paddingChar);
        }
    }
}

Испытания

import static org.junit.Assert.assertEquals;
import org.junit.Test;

public class FormatedTableBuilderTest {

    private static FormatedTableBuilder getAlign(int columns, int rows) {
        FormatedTableBuilder align = new FormatedTableBuilder();
        for (int i = 0; i < rows; i++) {
            String[] row = new String[columns];
            for (int j = 0; j < columns; j++) {
                row[j] = String.valueOf(i) + String.valueOf(j);
            }
            align.addLine(row);
        }
        align.setMinSpacing(5);
        align.setPaddingChar("-");
        return align;
    }

    /**
     * TEST CONTENT *
     */
    @Test(expected = IllegalArgumentException.class)
    public void setNegativeColumn() {
        getAlign(2, 3).set(-1, 1, "new value");
    }

    @Test(expected = IllegalArgumentException.class)
    public void setNonExistingColumn() {
        getAlign(2, 3).set(20, 1, "new value");
    }

    @Test(expected = IllegalArgumentException.class)
    public void setNegativeLine() {
        getAlign(2, 3).set(1, -1, "new value");
    }

    @Test(expected = IllegalArgumentException.class)
    public void setNonExistingLine() {
        getAlign(2, 3).set(1, 20, "new value");
    }

    @Test()
    public void setExisting() {
        getAlign(2, 3).set(1, 1, "new value");
    }

    @Test()
    public void setExistingCornerCases() {
        getAlign(3, 3).set(0, 1, "new value");
        getAlign(3, 3).set(1, 0, "new value");
        getAlign(3, 3).set(1, 2, "new value");
        getAlign(3, 3).set(2, 1, "new value");
    }

    @Test(expected = IllegalArgumentException.class)
    public void addNegativeColumn() {
        getAlign(2, 3).addColumn(-1, "new");
    }

    @Test(expected = IllegalArgumentException.class)
    public void addNegativeLine() {
        getAlign(2, 3).addLine(-1, "new");
    }

    @Test()
    public void addShortColumn() {
        getAlign(2, 3).addColumn(1, "new");
    }

    @Test()
    public void addShortColumnOutsideField() {
        getAlign(2, 3).addColumn(5, "new");
    }

    @Test()
    public void addLongColumn() {
        getAlign(2, 3).addColumn(1, "new", "new", "new", "new", "new");
    }

    @Test()
    public void addLongColumnOutsideField() {
        getAlign(2, 3).addColumn(5, "new", "new", "new", "new", "new");
    }

    @Test()
    public void addShortLine() {
        getAlign(2, 3).addLine(1, "new");
    }

    @Test()
    public void addShortLineOutsideField() {
        getAlign(2, 3).addLine(5, "new");
    }

    @Test()
    public void addLongLine() {
        getAlign(2, 3).addLine(1, "new", "new", "new", "new", "new");
    }

    @Test()
    public void addLongLineOutsideField() {
        getAlign(2, 3).addLine(5, "new", "new", "new", "new", "new");
    }

    /**
     * TEST ALIGN *
     */
    @Test()
    public void outputSetExisting() {
        FormatedTableBuilder align = getAlign(2, 3);
        align.set(1, 1, "new value");
        assertEquals(
                "00     01            \n"
                + "10     new value     \n"
                + "20     21            \n", align.format());
    }

    @Test()
    public void outputAddShortColumn() {
        FormatedTableBuilder align = getAlign(2, 3);
        align.addColumn(1, "new");
        assertEquals(
                "00     new     01     \n"
                + "10     -       11     \n"
                + "20     -       21     \n", align.format());
    }

    @Test()
    public void outputAddShortColumnOutsideField() {
        FormatedTableBuilder align = getAlign(2, 3);
        align.addColumn(5, "new");
        assertEquals(
                "00     01     -     -     -     new     \n"
                + "10     11     -     -     -     -       \n"
                + "20     21     -     -     -     -       \n", align.format());
    }

    @Test()
    public void outputAddLongColumn() {
        FormatedTableBuilder align = getAlign(2, 3);
        align.addColumn(1, "new", "new", "new", "new", "new");
        assertEquals(
                "00     new     01     \n"
                + "10     new     11     \n"
                + "20     new     21     \n"
                + "-      new     -      \n"
                + "-      new     -      \n", align.format());
    }

    @Test()
    public void outputAddLongColumnOutsideField() {
        FormatedTableBuilder align = getAlign(2, 3);
        align.addColumn(5, "new", "new", "new", "new", "new");
        assertEquals(
                "00     01     -     -     -     new     \n"
                + "10     11     -     -     -     new     \n"
                + "20     21     -     -     -     new     \n"
                + "-      -      -     -     -     new     \n"
                + "-      -      -     -     -     new     \n", align.format());
    }

    @Test()
    public void outputAddShortColumnEndOfField() {
        FormatedTableBuilder align = getAlign(2, 3);
        align.addColumn("new");
        assertEquals(
                "00     01     new     \n"
                + "10     11     -       \n"
                + "20     21     -       \n", align.format());
    }

    @Test()
    public void outputAddLongColumnEndOfField() {
        FormatedTableBuilder align = getAlign(2, 3);
        align.addColumn("new", "new", "new", "new", "new");
        assertEquals(
                "00     01     new     \n"
                + "10     11     new     \n"
                + "20     21     new     \n"
                + "-      -      new     \n"
                + "-      -      new     \n", align.format());
    }

    @Test()
    public void outputAddShortLine() {
        FormatedTableBuilder align = getAlign(2, 3);
        align.addLine(1, "new");
        assertEquals(
                "00     01     \n"
                + "new    -      \n"
                + "10     11     \n"
                + "20     21     \n", align.format());
    }

    @Test()
    public void outputAddShortLineOutsideField() {
        FormatedTableBuilder align = getAlign(2, 3);
        align.addLine(5, "new");
        assertEquals(
                "00     01     \n"
                + "10     11     \n"
                + "20     21     \n"
                + "-      -      \n"
                + "-      -      \n"
                + "new    -      \n", align.format());
    }

    @Test()
    public void outputAddLongLine() {
        FormatedTableBuilder align = getAlign(2, 3);
        align.addLine(1, "new", "new", "new", "new", "new");
        assertEquals(
                "00     01     -     -     -     \n"
                + "new    new    new   new   new   \n"
                + "10     11     -     -     -     \n"
                + "20     21     -     -     -     \n", align.format());
    }

    @Test()
    public void outputAddLongLineOutsideField() {
        FormatedTableBuilder align = getAlign(2, 3);
        align.addLine(5, "new", "new", "new", "new", "new");
        assertEquals(
                "00     01     -     -     -     \n"
                + "10     11     -     -     -     \n"
                + "20     21     -     -     -     \n"
                + "-      -      -     -     -     \n"
                + "-      -      -     -     -     \n"
                + "new    new    new   new   new   \n", align.format());
    }
}

Пример использования объектов:

    FormatedTableBuilder builder = new FormatedTableBuilder();
    List<User> users = getUsers();

    // format yourself
    for (User user : users) {
        builder.addLine(user.getName(), user.getLastName(), String.valueOf(user.getAge()));
    }
    builder.output((String s) -> System.out.println(s));

    // use formater
    builder.add(users,
            (User user) -> new String[]{user.getName(), user.getLastName(), String.valueOf(user.getAge())});
    builder.output((String s) -> System.out.println(s));
ответил tim 2 +04002014-10-02T19:41:15+04:00312014bEurope/MoscowThu, 02 Oct 2014 19:41:15 +0400 2014, 19:41:15
-3

Это совершенно неправильно, я имею в виду все.

  • Не один полезный javadoc или комментарий
  • Выровнять как имя класса? В самом деле?
  • Открытый класс класса Выровнять ужасен. Почему четыре метода addLine и четыре метода addColumn?
  • Контент как имя переменной действительно описательный.

Вот идея, куда идти:

Formatter<User> userFormatter = new Formatter(format);
for (User user : users)
{
    System.out.println(userFormatter.format(user));
}
ответил Epinuj 2 +04002014-10-02T18:58:15+04:00312014bEurope/MoscowThu, 02 Oct 2014 18:58:15 +0400 2014, 18:58:15

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132