Recursion is usually not a favoured strategy in Java due to concerns about stack overflow and function call efficiency. However, we can still review FizzBuzz as an exercise in recursive programming.
The first observation I have is that recursive solutions usually start by checking for the base case first. I recommend that you stick to that pattern. As a bonus, checking for count > max
will prevent infinite recursion if the function is accidentally called with the count
and max
parameters reversed.
Another typical feature of recursive solutions is that they avoid mutation and reassignment. When you recurse, previous values of your variables will already be kept on the stack for you, and that is generally sufficient to solve most problems. In your case, you've used +=
, whereas you should be able to use just +
.
You've used three ternary conditionals. If you reorder them, you can avoid concatenating += "fizz"
followed by += "buzz"
.
Since this is a pure function, it should probably be declared static
, so that you don't have to instantiate an object just to call the code.
Finally, note that the resulting string is already terminated by \n
, so perhaps you should call System.out.print()
rather than .println()
.
public void fizzbuzz(int count, int max, String accumulator) {
// Check for the base case
if (count > max) {
System.out.print(accumulator);
return;
}
// ... then proceed to the recursive cases.
//
// The first case below would be better written as (count % 15 == 0),
// but I've kept it as (count % 3 == 0 && count % 5 == 0) for easier
// comparison with your original code.
String fizzer = (count % 3 == 0 && count % 5 == 0) ? "fizzbuzz\n" :
(count % 3 == 0) ? "fizz\n" :
(count % 5 == 0) ? "buzz\n" : count + "\n";
fizzbuzz(count + 1, max, accumulator + fizzer);
}
You asked about reducing the number of parameters. The first parameter I would eliminate is not count
or max
, but the accumulator. You could change it into a return value instead, and it would be more natural. The caller would have to be responsible for printing the result — and I would also consider that an improvement, since it keeps the calculation and the output routines separate.
public static String fizzbuzz(int count, int max) {
if (count > max) {
return "";
}
String fizzer = (count % 15 == 0) ? "fizzbuzz\n" :
(count % 3 == 0) ? "fizz\n" :
(count % 5 == 0) ? "buzz\n" :
count + "\n";
return fizzer + fizzbuzz(count + 1, max);
}
public static void main(String[] args) {
System.out.print(fizzbuzz(1, 30));
}
Once you've done that, you can eliminate one more parameter by making it left-recursive instead of right-recursive.
public static String fizzbuzz(int n) {
if (n <= 0) {
return "";
}
String fizzer = (n % 15 == 0) ? "fizzbuzz\n" :
(n % 3 == 0) ? "fizz\n" :
(n % 5 == 0) ? "buzz\n" :
n + "\n";
return fizzbuzz(n - 1) + fizzer;
}
public static void main(String[] args) {
System.out.print(fizzbuzz(30));
}
StringBuilder
rather than aString
. Concatenation is evil. Also combining logic and printing is a big no-no - return theStringBuilder
and print elsewhere. \$\endgroup\$