In a typical recursive algorithm, you want to have 2 things very clear in the code, as recursiveness often leads to more difficulty to read:
- The base condition. This is the condition that determines when to stop the recursion. Typically, this is placed at the beginning of the method, so that it is easy to spot and so that it leads to an early return.
- The recursive call, with the updated parameters.
In the current implementation of sayHello
, the base condition isn't obvious at all:
int sayHello(int num) {
System.out.println("Hello World!");
return (1 > num) ? 1 : sayHello(num -1); //self call
}
The method returns an integer, but is unused, and this can be confusing with regard to the base condition: why is it returning 1? Also, the base condition is a bit hidden inside the ternary operator, and I'd argue that the use of Yoda-like conditions 1 > num
are not typical in this instance, and harder to read than num < 1
.
Let's first state the signature of the method: it needs to know how many calls remaining there are (so 1 parameter), and it has no output (so void
). Then, when the number is zero (or less than 0), there is nothing to say, and the method exits (base condition). Otherwise, it prints the String, and calls itself with the remaining number of times decreased by one:
With this in mind, you would have:
void sayHello(int num) {
if (num <= 0) {
return;
}
System.out.println("Hello World!");
sayHello(num - 1);
}
Then, in this specific case, that can be re-organized a bit: instead of having an early return on num <= 0
, we can check for num > 0
:
void sayHello(int num) {
if (num > 0) {
System.out.println("Hello World!");
sayHello(num - 1);
}
}
Of course, this problem doesn't bend itself very well to recursion, and there are more straight-forward ways to implement it: with a stream, or even with a simple call to Collections.nCopies
void sayHello(int num) {
Collections.nCopies(num, "Hello World!").forEach(System.out::println);
}