Search code examples
javalambdajava-8java-streamfunctional-interface

Fibonacci using Stream And BinaryOperator in Java


I'm student and I learning functional Java 8. I got project to do and I don't understand how this function interface work. My teacher told me "you should know that" and I'm looking for help to understand this problem. It should count Fibonacci series

I got this code

StreamUtils.generateRest(Stream.of(1, 1), (a, b) -> a + b)
    .limit(7)
    .forEach(System.out::println);

StreamUtils.generateRest(Stream.of("AAA", "BB", "KKKK"), (a, b) -> a + b)
    .limit(7)
    .forEach(System.out::println);

StreamUtils.generateRest(Stream.of(i -> 0), 
    (BinaryOperator<UnaryOperator<Integer>>) (f, g) -> (x -> x == 0 ? 1 : x * g.apply(x - 1)))
    .limit(10)
    .map(f -> f.apply(7))
    .forEach(System.out::println);

I did something like this but it doesn't work

public class StreamUtils<T> {

    public static <T> Stream generateRest(Stream<T> stream, BinaryOperator<T> binaryOperator) {
        return Stream.of(stream.reduce((a, b) -> binaryOperator.apply(a, b)));
    }

}

Someone can help me with that and explain how to solve this problem?


Solution

  • I'm assuming that having more than 2 items means A, B, C, A+B, B+C, C+(A+B), (A+B)+(B+C), etc., and that having 1 item means A, A+A, A+(A+A), (A+A)+(A+(A+A)), etc., where + is the binary operator.

    Basically you turn the stream into an array, then you use Stream.generate and at each step you generate the element after the ones you have, shift the array left to fit the new element, and return the old first element (which is no longer in the array). Note that since this has side effects (modifying an external array) it cannot be used with .parallel().

    @SuppressWarnings("unchecked")
    public static <T> Stream<T> generateRest(Stream<T> stream, BinaryOperator<T> binaryOperator) {
        T[] t = (T[]) stream.toArray();
        if (t.length == 1) {
            t = (T[]) new Object[] { t[0], binaryOperator.apply(t[0], t[0]) };
        }
        final T[] items = t;
        return Stream.generate(() -> {
            T first = items[0];
            T next = binaryOperator.apply(items[0], items[1]);
            System.arraycopy(items, 1, items, 0, items.length - 1);
            items[items.length - 1] = next;
            return first;
        });
    }
    

    Output:

    1
    1
    2
    3
    5
    8
    13
    AAA
    BB
    KKKK
    AAABB
    BBKKKK
    KKKKAAABB
    AAABBBBKKKK
    0
    0
    0
    0
    0
    0
    0
    0
    5040
    5040