This is an assignment to the Software Architecture class at the Technische Hochschule Nürnberg.

Assignment 12: Functional - CLI variant

This assignment covers the basics of the Java 8 Stream API. Streams are a functional concept and are relatively new in Java but they are very useful in combination with all kinds of iterable data sources. Streams may look a little bit complicated but when you got the concept they improve the readability of your code because they are more data pipeline oriented as normal Java code is where you always have to iterate a collection with any kind of loop.

Setup

  1. Create a fork of this repository (button in the right upper corner)
  2. Clone the project (get the link by clicking the green Clone or download button)
  3. Import the project to your IntelliJ
  4. Read the whole assignment spec!

Remark: the given test suite is incomplete but will succeed after the checkout.

Objectives

  1. Implement the RandomJokeSupplier - this supplier returns a random joke every time it is used.
  2. Implement the AllJokesSupplier - this supplier iterates all jokes in an infinite loop i.e. if all jokes were retrieved it continues with the first joke.
  3. Implement the JokeGenerator - the generator returns infinite streams based on the implemented suppliers.
  4. Complete the test suite to ensure that your generators are working correctly!

Note 1: the class structure is already there (including the empty unit tests).

Note 2: the whole logic around the CNJDB is already implemented including the CNJDBService service (which manages an API singleton)! There is no way to implement asynchronous generators so you will have to use the CNJDBApi also in a synchronous way.

Generators

A generator is component that creates a Stream. There are two kinds of streams:

  • finite
  • infinite

A stream based on a list of objects is a finite stream as there are only a discrete number of elements that can be iterated.

A infinite stream is created by providing a Supplier<T> instance to the Stream.generate(...) method like this:

var prngStream = Stream.generate(new PseudoRandomNumberSupplier());

where PseudoRandomNumberSupplier is an implementation of the Supplier<T> interface builtin in the JDK. See also the following complete example of how to implement the Supplier<T> interface and how to create an infinite stream.

Infinite streams are seaming to be a little bit weird but they are also very useful. Think of a pseudo random number generator. An infinite stream may be used to produce as many random numbers as required. This generator may be implemented like this:

public abstract class PseudoRandomNumberGenerator {

    private PseudoRandomNumberGenerator() {
    }

    public static Stream<Integer> createStream() {
        return Stream.generate(new PseudoRandomNumberSupplier());
    }

    private static class PseudoRandomNumberSupplier implements Supplier<Integer> {

        private final Random random = new Random();

        @Override
        public Integer get() {
            return random.nextInt();
        }
    }
}

The stream may be used like this:

Stream<Integer> prngStream = createStream();
prngStream
        .limit(10)
        .forEach(System.out::println);

Note that the limit(...) operation is mandatory because the stream is infinite and otherwise the whole operation will not terminate!

In this part of the assignment you have to implement two generators as shown in the following UML:

Generator spec

Remark: the UML is incomplete and is meant as implementation hint!

Using the generators

The given class App already implements a basic CLI interface. To complete the assignment implement the required code marked with a TODO.

The following flow diagram explains how to use the jokesSource:

Stream flow

Every chart element corresponds to a single method call on the stream of jokes. For further reading about the Java 8 streams have a look at this article.

Remark: this part is technically an one-liner. To improve the readability add line breaks after every stream transformation. That should result in 5-6 lines of code.

If you want to improve your knowledge about streams you could extend the assignment by asking the user if he wants to filter the jokes for a specific category and if so which category (read the category as string). Then filter the stream after the unwrap transformation for the chosen category.