0

I have problem with method filter. I can't filter out values less than 4,000,000. Do you have any ideas?

public class Euler2 {

    public static void main(String[] args) {
        long sum = calculateSumOfTheEvenValuesOfTheFibonacciSequence();
        System.out.println(sum);
    }

    static long calculateSumOfTheEvenValuesOfTheFibonacciSequence() {
        return Stream.iterate(new Long[]{1L, 2L}, x -> new Long[]{x[1], x[0] + x[1]})
                .flatMap(Arrays::stream)
                .filter(new Predicate<Long>() {
                    @Override
                    public boolean test(Long x) {
                        if (x < 4_000_000) {
                            return true;
                        } else {
                            return false;
                        }
                    }
                })
                .filter(x -> x % 2 == 0)
                .reduce(0L, Long::sum);
    }
}
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • 2
    your stream is infinite... – Eugene Mar 10 '21 at 19:43
  • 1
    Please be more specific, tell us what you expect to see, and what actually happens. Also note that you really shouldnt use an anonymous inner class but a lambda, see http://www.java2s.com/Tutorials/Java/java.util.function/Predicate/index.htm here – GhostCat Mar 10 '21 at 19:44
  • I expect filter out values smaller than 4_000_000 – Hubert Kowalski Mar 10 '21 at 19:46
  • 1
    Why are you using a verbose anonymous inner class when the preceding lines indicate that you know about lambda expressions? And why are you using a construct like `if (x < 4_000_000) { return true; } else { return false; }`? Just use `.filter(x -> x < 4_000_000)`. Still, the Stream is infinite. After some iterations, the long values will overflow and there will be values smaller than `4_000_000` again. So the resulting stream has an infinite number of elements. But even with a predicate accepting only a finite number of elements, processing the source stream would take an infinite time. – Holger Mar 11 '21 at 09:18
  • 1
    And by the way, when you use `long[]` instead of `Long[]`, you can use `flatMapToLong` instead of `flatMap` and just use `sum()` instead of `reduce(0L, Long::sum)`. – Holger Mar 11 '21 at 09:21
  • 1
    …and your approach using `flatMap` is wrong anyway, as it leads to repeated numbers. For a Fibonacci sequence, you have to use `.map(a -> a[0])` (or `mapToLong`) instead of `flatMap(Arrays::stream)` and use `{ 1, 1 }` as starting point. Compare with [this answer](https://stackoverflow.com/a/30596139/2711488)… – Holger Mar 11 '21 at 09:30

1 Answers1

4

Instead of that filter, you really want a :

.takeWhile(x -> x < 4_000_000)

so that you make it finite. Otherwise, that Long::sum will overflow.

You can replace that reduce that you have with .reduce(0L, Math::addExact); and see that it fails.

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • 1
    Without using `takeWhile`, even the `x[0] + x[1]` at the source will overflow, regardless of the overflow at `Long::sum`. But even without overflows, the Stream would never complete, as the implementation is not capable of detecting whether it is impossible to encounter matching elements again in the infinite sequence. – Holger Mar 11 '21 at 09:35