1
\$\begingroup\$

Java allows methods to make recursive calls. This can be dangerous because an infinite recursive call will fill up the stack. It can be useful, however, for calculations that need iteration when the number of "self calls" is limited (it save a few keystrokes as well). The code below, although not very useful, does demonstrate the technique. What are some more practical uses of this technique and how could this code be modified for those uses?

class NoForLoop {
        int sayHello(int num) {
            System.out.println("Hello World!");
            return (1 > num) ? 1 : sayHello(num -1); //self call
        }
    public static void main (String [] args) {
        NoForLoop n = new NoForLoop();
        n.sayHello(5);
    }
}
\$\endgroup\$
  • \$\begingroup\$ This seems off-topic for Code Review. Here we focus on critiquing real, functional code. Abstract and general questions about coding technique and style do not belong here. You could consider some of the other SE sites, but I think it's probably off-topic for Software Engineering, too. The best-fitting site would probably be StackOverflow, but I suspect it would get a poor reception there. \$\endgroup\$ – PellMel Oct 31 '16 at 19:45
  • 1
    \$\begingroup\$ @PellMel I'd argue that this is example project and not example code, which would be on-topic. I can agree though that this is not the kind of question we prefer around here. \$\endgroup\$ – Simon Forsberg Oct 31 '16 at 20:04
  • 2
    \$\begingroup\$ "What are some more practical uses of this technique?" is asking for a very broad discussion. Your comment on @Tunaki's review ("I wan't asking for a better way to use recursion print "Hello World!") makes it off-topic as well, as it makes it clear that you are not asking for a code review. \$\endgroup\$ – 200_success Oct 31 '16 at 23:17
  • \$\begingroup\$ Recursion isn't really useful in Java where most code deals with mutability. It becomes much more important in languages, like Lisp and Scala, where immutability is much more important (or even required). Just as immutable classes require all information be available as parameters to the constructor or derivable from those parameters, a similar idea holds in a language where immutability is paramount. This question is better phrased, "Where and why is a recursive loop preferable and/or required?". \$\endgroup\$ – chaotic3quilibrium Nov 1 '16 at 3:02
6
\$\begingroup\$

In Java 8 you can use streams, they tend to make the code quite more compact:

IntStream.range(0, 5).forEach(i -> System.out.println("Hello World!"));

I would recommend reading the documentation of IntStream and Streams in general

\$\endgroup\$
6
\$\begingroup\$

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);
}
\$\endgroup\$
  • \$\begingroup\$ Although your comment is useful and informative it doesn't answer the question. I wan't asking for a better way to use recursion print "Hello World!". I was asking for a practical use of the technique. \$\endgroup\$ – Jim Ferguson Oct 31 '16 at 18:56

Not the answer you're looking for? Browse other questions tagged or ask your own question.