Just because everything looks like a nail when you're wielding the hammer that is Java 8 streams...
public static void print(int x) {
IntStream.rangeClosed(1, x).mapToObj(i ->
IntStream.rangeClosed(1, x).mapToObj(j ->
Integer.toString(i * j))
.collect(Collectors.joining("\t")))
.forEach(System.out::println);
}
I find it easier to visualize it as two streams - one horizontal and one vertical. The formula to print the value at [i, j] is of course just i * j, and afterwards it's just a matter of coalescing into a String per row and 'sending' each to the console output.
For a more generic way of handling the output x by y table, you can easily adapt the above method to return a Collection<String>, such as the example below:
public class MultiplicationTable {
public static void main(String[] args) {
print(9).forEach(System.out::println);
print(8, 9).forEach(System.out::println);
}
public static Collection<String> print(int x) {
return print(x, x);
}
public static Collection<String> print(int x, int y) {
return IntStream.rangeClosed(1, y).mapToObj(i ->
IntStream.rangeClosed(1, x).mapToObj(j ->
Integer.toString(i * j))
.collect(Collectors.joining("\t")))
.collect(Collectors.toList());
}
}
edit
Attempting to answer your original questions...
What is processing inefficiency and how is that shown in my code?
As mentioned in the comments, your code turns the relatively straightforward question of:
Given x, show us a table from 1 to the square of x with each cell as the product of each row and column number
To a three-clause if statement that involves three different calculations (number, columnCounter and columnCounter * rowCounter) to derive the number to print.
If you think it more like a 2D-array, then my answer quite clearly illustrates just a single formula can do the same thing too.
What is object allocation inefficiency(I didn't use any static variables)
This is probably related specifically to the question (I don't consider concatenating Strings using + as a form of object allocation inefficiency unless that's the last place of bottleneck in a high-performance application), but you had to use four variables to derive the number to print:
int totalNumberOfPrints = x * x;
int rowCounter = 0;
int columnCounter = 1;
int number = 0;
Granted, int primitives are not Java Objects per se, but I'm willing to give the interviewer the benefit of doubt and interpret this particular feedback as 'many allocations going on'.
In my alternative approach, there is only the equivalent of your rowCounter and columnCounter, as i and j.
Is it better to use less lines (I thought it doesn't matter?)
We are not reading gripping novels that require detailed and illustrative characters' backgrounds, so yes, generally the less content to read, the better. Lesser content cuts through boilerplate code templates or complicated logic, and better reflects what a method is doing.
edit 2
200_success's excellent answer prompted me to give my solution a shot at printing a nicely formatted output too. Note that this part on is really just an academic exercise, and may/will seem overly verbose compared to 200_success's solution. This possibly showcases a borderline unhealthy obsession with new language features...
public static Collection<String> print(int x, int y) {
final Collector<Integer, ?, String> formatter = formatOutput(x);
return IntStream.rangeClosed(1, y).mapToObj(i ->
IntStream.rangeClosed(1, x).map(j ->
i * j).boxed().collect(formatter))
.collect(Collectors.toList());
}
public static Collector<Integer, ?, String> formatOutput(int x) {
return Collector.of(ArrayList::new,
(list, element) -> list.add(element),
(left, right) -> { left.addAll(right); return left; },
list -> { return String.format(String.join(" ",
Collections.nCopies(x, "%" +
(1 + (int) Math.floor(Math.log10(x * x))) + "d")),
list.toArray()); }
);
}
This updated solution creates a Collector, where the formatting logic is implemented within the finisher argument. We accumulate our Integer objects (thanks to boxed()) into a List, and then finally call String.format() with our format String and list.toArray().