99 bottles of beer

The problem

Write a command line program that will print out the lyrics to 99 Bottles. Bottles of what? Make a variable for what is in the bottle (so it can be easily changed) and start it out as “beer” or another beverage of your choice, if you would like. Also, extract a variable to represent the initial number of bottles. Output should look as follows:

99 bottles of beer on the wall.
99 bottles of beer!
Take one down. Pass it around.
98 bottles of beer on the wall.

98 bottles of beer on the wall. 98 bottles of beer!
Take one down. Pass it around.
97 bottles of beer on the wall.

... and so on until ...

2 bottles of beer on the wall.
2 bottles of beer!
Take one down. Pass it around.
1 bottle of beer on the wall.

1 bottle of beer on the wall.
1 bottle of beer!
Take one down. Pass it around.
No more bottles of beer on the wall.

Breaking it down

Since there isn't a way to peek at the next value in a stream, we will need to seperate the 99 bottles of beer lyrics into to lists concatinating inital seed values and beverage variable. Next, we can iterate over a series of Integer using java8 range. The catch is we want to perform the operation in reverse order such as [99..1] and in order to do this we will need to reverse the stream. Converting the IntStream to an iterator we can loop over the elements checking if we have reached the end.

Diving into the while loop, we can use the map function to replace any of the numbers. To learn more about the map function visit java 8 map tutorial. Next we can println java 8 stream using the forEach and referencing the static method System.out::println.

static int seed = 3;
static String beverage = "beer";

public static void main(String[] args) {

    List<String> phrase = new ArrayList<>();
    phrase.add("%d bottles of " + beverage + " on the wall.");
    phrase.add("%d bottles of " + beverage + "!");
    phrase.add("Take one down. Pass it around.");
    phrase.add("%t bottles of " + beverage + " on the wall.");
    
    List<String> endingPhrase = new ArrayList<>();
    endingPhrase.add("1 bottle of " + beverage + " on the wall, 1 bottle of " + beverage + ".");
    endingPhrase.add("Take one down and pass it around, no more bottles of " + beverage + " on the wall.");
    endingPhrase.add("No more bottles of " + beverage + " on the wall, no more bottles of " + beverage + ".");
    endingPhrase.add("Go to the store and buy some more, " + seed + " bottles of " + beverage + " on the wall.");
    
    Iterator<Integer> numberOfBottles = IntStream.iterate(seed, i -> i - 1)
            .limit(seed).boxed().iterator();

    while (numberOfBottles.hasNext()) {
        Integer bottle = numberOfBottles.next();
        
        if (numberOfBottles.hasNext()) {
            phrase.stream()
            .map(s -> s.replaceAll("%d", String.valueOf(bottle)))
            .map(s -> s.replaceAll("%t", String.valueOf(bottle - 1)))
            .forEach(System.out::println);
        } else {
            endingPhrase.stream().forEach(System.out::println);;
        }
    }
}

Output

3 bottles of beer on the wall.
3 bottles of beer!
Take one down. Pass it around.
2 bottles of beer on the wall.
2 bottles of beer on the wall.
2 bottles of beer!
Take one down. Pass it around.
1 bottles of beer on the wall.
1 bottle of beer on the wall, 1 bottle of beer.
Take one down and pass it around, no more bottles of beer on the wall.
No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 3 bottles of beer on the wall.