I have some working code that turns this:
public static void main(String[] args) {
new Columns()
.addLine("One", "Two", "Three", "Four")
.addLine("1", "2", "3", "4")
.print()
;
}
into this:
One Two Three Four
1 2 3 4
but while trying to improve it with this also working code, and follow the advice given about it here, I tried to replace this working toString()
code:
public String toString(){
final StringBuilder result = new StringBuilder();
final int rows = columns.get(0).size();
IntStream
.range(0, rows)
.forEach(
row -> {
result
.append(
columns
.stream()
.map(col -> col.getCell(row))
.collect( Collectors.joining(columnSeparator) )
)
;
result.append( System.lineSeparator() );
}
)
;
return result.toString();
}
with this broken toString()
code: was following this
public String toString(){
final int rows = columns.get(0).size();
return IntStream
.range(0, rows)
.flatMap(row -> columns
.stream()
.map( col -> col.getCell(row) )
.collect( Collectors.joining(columnSeparator) )
)
.collect( Collectors.joining( System.lineSeparator() ) )
;
}
only to see this:
Columns.java:81: error: incompatible types: bad return type in lambda expression
.collect( Collectors.joining(columnSeparator) )
^
inference variable R has incompatible bounds
equality constraints: String
lower bounds: IntStream,Object
where R,A,T are type-variables:
R extends Object declared in method <R,A>collect(Collector<? super T,A,R>)
A extends Object declared in method <R,A>collect(Collector<? super T,A,R>)
T extends Object declared in interface Stream
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error
to which I can only say, rats.
If you're the kind that hates clicking links here's the highlights of what you're missing:
private final List<Column> columns = new ArrayList<>();
And down in the Column
class we find
public String getCell(int row){
return padCell( words.get(row), maxLength );
}
The advise I was given: "replace the StringBuilder
in toString with another joining Collector
."
The toString
is trying to traverse these columns row by row concatenating the padded cells of strings it finds in each. Completing a row of cells from all columns before going to the next row.
Yes I know a simple double for loop can do this but where's the fun in that?
Honestly it works but leaves unneeded column separators hanging on the side which bugs me
Your outer stream calls flatMap()
which is supposed to expand each element into a stream (in this case, IntStream
) and flatten the results back into one stream. It's failing because the provided fuction returns a single string instead of a stream. Since the result is one-for-one, you just need an ordinary map operation to transform each row into a string:
return IntStream
.range(0, rows)
.mapToObj(row -> columns
.stream()
.map( col -> col.getCell(row) )
.collect( Collectors.joining(columnSeparator) )
)
.collect( Collectors.joining( System.lineSeparator() ) )
;