6

As an exercise I'm converting some old code to functional streams. I don't know much about streams. It seems like it should be simple to convert this code, but I haven't had much luck. The method starts at a given integer, passes it to isPrime, which returns true if it's prime. and then hands off the new(next) prime number to be printed. If isPrime is false i is incremented and we check the next integer.

private static int nextPrime(final int number) {
    int i = number + 1;

    while (!isPrime(i)) {
        i++;
    }

    return i;
}
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
scott parent
  • 77
  • 1
  • 1
  • 3
  • 6
    Why do you think you need to convert such a simple loop? And what problem did you encounter when you “haven't had much luck”? And what is your method supposed to do when there is no next prime in the `int` value range? The current behavior of overflowing doesn’t look much convincing. – Holger Mar 02 '18 at 19:56
  • 4
    @Holger "As an exercise..." – alex Mar 02 '18 at 20:39

2 Answers2

7

I see no reason to use a Stream for this other than to take advantage of parallelism (if the primes happen to be very far apart, but this won't be true within int bounds, so there's essentially no benefit).

You can iterate over an IntStream of ascending integers (starting from number + 1) and filter only the prime numbers. When one is inevitably found, you can return the first.

private static int nextPrime(final int number) {
    return IntStream.iterate(number + 1, i -> i + 1)
                    .filter(Test::isPrime)
                    .findFirst()
                    .getAsInt();
}

Note: The class that I used to test this is called Test, as seen by the method reference. You should change that to your class name.

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • An infinite stream can never return an empty optional. – shmosel Mar 02 '18 at 21:05
  • True, I'll convey that better. – Jacob G. Mar 02 '18 at 21:07
  • 1
    @Aominè Good catch, I forgot it's not `get` for `OptionalInt` ;) – Jacob G. Mar 02 '18 at 21:10
  • 4
    I realize there's no NEED for a stream. I'm just trying to learn functional programming be transforming code I know already works. The code you gave was a big help. I'm SLOWLY getting my head around it. – scott parent Mar 02 '18 at 21:27
  • 4
    I’d prefer `IntStream.rangeClosed(number+1, Integer.MAX_VALUE)`; it’s more efficient and the behavior of throwing a `NoSuchElementException` when there is no bigger prime, is more reasonable than overflowing… – Holger Mar 03 '18 at 08:39
-1

Based on this answer, for an object like an Enumeration<T> for example, where you can only call .hasMoreElements() & .nextElement(), you can use this kind of code :

public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) {
    return StreamSupport.stream(
        new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED) {
            public boolean tryAdvance(Consumer<? super T> action) {
                if(e.hasMoreElements()) {
                    action.accept(e.nextElement());
                    return true;
                }
                return false;
            }
            public void forEachRemaining(Consumer<? super T> action) {
                while(e.hasMoreElements()) action.accept(e.nextElement());
            }
    }, false);
}
Lucas Cimon
  • 1,859
  • 2
  • 24
  • 33