Let's say you want to display something like:
One Two Three Four
1 2 3 4
And since you hate the idea of predefining the widths of the columns you want to print it with something like this:
public static void main(String[] args) {
new Columns()
.addLine("One", "Two", "Three", "Four")
.addLine("1", "2", "3", "4")
.print()
;
}
Either listing below can do this. Which is easier to read? How would you improve either of them? Do either paint us into a corner? Any multithreaded concerns? How could it be made extensible? Would the getThis() trick help here or is it a bad idea?
Listing A
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Columns {
List<List<String>> lines = new ArrayList<>();
List<Integer> maxLengths = new ArrayList<>();
int numColumns = -1;
public Columns addLine(String... line) {
if (numColumns == -1){
numColumns = line.length;
for(int i = 0; i < numColumns; i++) {
maxLengths.add(0);
}
}
if (numColumns != line.length) {
throw new IllegalArgumentException();
}
for(int i = 0; i < numColumns; i++) {
maxLengths.set( i, Math.max( maxLengths.get(i), line[i].length() ) );
}
lines.add( Arrays.asList(line) );
return this;
}
public void print(){
System.out.println( toString() );
}
public String toString(){
String result = "";
for(List<String> line : lines) {
for(int i = 0; i < numColumns; i++) {
result += pad( line.get(i), maxLengths.get(i) + 1 );
}
result += System.lineSeparator();
}
return result;
}
private String pad(String word, int newLength){
while (word.length() < newLength) {
word += " ";
}
return word;
}
}
Listing B
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Columns {
List<List<String>> lines = new ArrayList<>();
List<Integer> maxLengths = new ArrayList<>();
int numColumns = -1;
String[] line;
public Columns addLine(String... line) {
this.line = line;
learnNumOfColumnsOnce();
ensureConsistantNumOfColumns();
widenColumnsThatNeedIt();
rememberLine();
return this;
}
private void learnNumOfColumnsOnce() {
if (numColumns == -1){
numColumns = line.length;
for(int i = 0; i < numColumns; i++) {
maxLengths.add(0);
}
}
}
private void ensureConsistantNumOfColumns() {
if (numColumns != line.length) {
throw new IllegalArgumentException();
}
}
private void widenColumnsThatNeedIt() {
for(int i = 0; i < numColumns; i++) {
maxLengths.set( i, Math.max( maxLengths.get(i), line[i].length() ) );
}
}
private void rememberLine() {
lines.add( Arrays.asList(line) );
}
public void print(){
System.out.println( toString() );
}
public String toString(){
String result = "";
for(List<String> line : lines) {
for(int i = 0; i < numColumns; i++) {
result += padWithSpaces( line.get(i), maxLengths.get(i) + 1 );
}
result += System.lineSeparator();
}
return result;
}
private String padWithSpaces(String word, int newLength){
while (word.length() < newLength) {
word += " ";
}
return word;
}
}